mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2025-07-03 12:46:38 -04:00
properly import and optimize/cache images in markdown files
This commit is contained in:
@ -31,8 +31,8 @@ export default function Page() {
|
||||
src={{
|
||||
webm: "/static/images/birthday/birthday.webm",
|
||||
mp4: "/static/images/birthday/birthday.mp4",
|
||||
image: thumbnail.src,
|
||||
}}
|
||||
poster={thumbnail.src}
|
||||
/>
|
||||
</Content>
|
||||
</>
|
||||
|
@ -37,7 +37,9 @@ export default function Page() {
|
||||
anyone, ever).
|
||||
</Blockquote>
|
||||
|
||||
<Image src={cliImg} href="https://www.npmjs.com/package/@jakejarvis/cli" alt="Terminal Screenshot" priority />
|
||||
<Link href="https://www.npmjs.com/package/@jakejarvis/cli">
|
||||
<Image src={cliImg} alt="Terminal Screenshot" priority />
|
||||
</Link>
|
||||
|
||||
<H2 id="usage">Usage</H2>
|
||||
<CodeBlock withCopyButton>npx @jakejarvis/cli</CodeBlock>
|
||||
|
@ -15,7 +15,7 @@ export async function sendMessage(
|
||||
try {
|
||||
// these are both backups to client-side validations just in case someone squeezes through without them. the codes
|
||||
// are identical so they're caught in the same fashion.
|
||||
if (!formData.get("name") || !formData.get("email") || !formData.get("message")) {
|
||||
if (!formData || !formData.get("name") || !formData.get("email") || !formData.get("message")) {
|
||||
return { success: false, message: "Please make sure that all fields are properly filled in.", payload: formData };
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ export async function sendMessage(
|
||||
});
|
||||
const turnstileData = await turnstileResponse.json();
|
||||
|
||||
if (!turnstileData.success) {
|
||||
if (!turnstileData || !turnstileData.success) {
|
||||
return {
|
||||
success: false,
|
||||
message: "Did you complete the CAPTCHA? (If you're human, that is...)",
|
||||
@ -44,13 +44,14 @@ export async function sendMessage(
|
||||
from: `${formData.get("name")} <${process.env.RESEND_DOMAIN ? `noreply@${process.env.RESEND_DOMAIN}` : "onboarding@resend.dev"}>`,
|
||||
replyTo: `${formData.get("name")} <${formData.get("email")}>`,
|
||||
to: [config.authorEmail],
|
||||
subject: `[${config.siteDomain}] Contact Form Submission`,
|
||||
subject: `[${config.siteName}] Contact Form Submission`,
|
||||
text: formData.get("message") as string,
|
||||
});
|
||||
|
||||
return { success: true, message: "Thanks! You should hear from me soon.", payload: formData };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
return {
|
||||
success: false,
|
||||
message: "Internal server error... Try again later or shoot me an old-fashioned email?",
|
||||
|
@ -27,8 +27,8 @@ const ContactForm = () => {
|
||||
placeholder="Name"
|
||||
required
|
||||
className={styles.input}
|
||||
defaultValue={(formState.payload?.get("name") || "") as string}
|
||||
disabled={formState.success}
|
||||
defaultValue={(formState?.payload?.get("name") || "") as string}
|
||||
disabled={formState?.success}
|
||||
/>
|
||||
|
||||
<input
|
||||
@ -38,8 +38,8 @@ const ContactForm = () => {
|
||||
required
|
||||
inputMode="email"
|
||||
className={styles.input}
|
||||
defaultValue={(formState.payload?.get("email") || "") as string}
|
||||
disabled={formState.success}
|
||||
defaultValue={(formState?.payload?.get("email") || "") as string}
|
||||
disabled={formState?.success}
|
||||
/>
|
||||
|
||||
<TextareaAutosize
|
||||
@ -48,8 +48,8 @@ const ContactForm = () => {
|
||||
minRows={5}
|
||||
required
|
||||
className={styles.input}
|
||||
defaultValue={(formState.payload?.get("message") || "") as string}
|
||||
disabled={formState.success}
|
||||
defaultValue={(formState?.payload?.get("message") || "") as string}
|
||||
disabled={formState?.success}
|
||||
/>
|
||||
|
||||
<div
|
||||
@ -72,7 +72,7 @@ const ContactForm = () => {
|
||||
Markdown syntax
|
||||
</Link>{" "}
|
||||
is allowed here, e.g.: <strong>**bold**</strong>, <em>_italics_</em>, [
|
||||
<Link href="https://jarv.is" underline={false} openInNewTab>
|
||||
<Link href="https://jarv.is" plain>
|
||||
links
|
||||
</Link>
|
||||
](https://jarv.is), and <code>`code`</code>.
|
||||
@ -86,7 +86,7 @@ const ContactForm = () => {
|
||||
/>
|
||||
|
||||
<div className={styles.actionRow}>
|
||||
{!formState.success && (
|
||||
{!formState?.success && (
|
||||
<button type="submit" disabled={pending} className={styles.submitButton}>
|
||||
{pending ? (
|
||||
<span>Sending...</span>
|
||||
@ -98,10 +98,10 @@ const ContactForm = () => {
|
||||
</button>
|
||||
)}
|
||||
|
||||
{formState.message && (
|
||||
<div className={clsx(styles.result, formState.success ? styles.success : styles.error)}>
|
||||
{formState.success ? <GoCheck className={styles.resultIcon} /> : <GoX className={styles.resultIcon} />}{" "}
|
||||
{formState.message}
|
||||
{formState?.message && (
|
||||
<div className={clsx(styles.result, formState?.success ? styles.success : styles.error)}>
|
||||
{formState?.success ? <GoCheck className={styles.resultIcon} /> : <GoX className={styles.resultIcon} />}{" "}
|
||||
{formState?.message}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -31,9 +31,8 @@ export default function Page() {
|
||||
>
|
||||
<p>
|
||||
Fill out this quick form and I'll get back to you as soon as I can! You can also{" "}
|
||||
<Link href="mailto:jake@jarv.is">email me directly</Link>, send me a{" "}
|
||||
<Link href="https://fediverse.jarv.is/@jake">direct message on Mastodon</Link>, or{" "}
|
||||
<Link href="sms:+1-617-917-3737">text me</Link>.
|
||||
<Link href="mailto:jake@jarv.is">email me directly</Link> or send me a{" "}
|
||||
<Link href="https://fediverse.jarv.is/@jake">direct message on Mastodon</Link>.
|
||||
</p>
|
||||
<p>
|
||||
🔐 You can grab my public key here:{" "}
|
||||
|
@ -33,8 +33,8 @@ export default function Page() {
|
||||
webm: "/static/images/hillary/convention-720p.webm",
|
||||
mp4: "/static/images/hillary/convention-720p.mp4",
|
||||
vtt: "/static/images/hillary/subs.en.vtt",
|
||||
image: thumbnail.src,
|
||||
}}
|
||||
poster={thumbnail.src}
|
||||
/>
|
||||
|
||||
<p
|
||||
|
@ -1,5 +1,5 @@
|
||||
import clsx from "clsx";
|
||||
import { Analytics } from "@vercel/analytics/react";
|
||||
import { Analytics } from "@vercel/analytics/next";
|
||||
import { ThemeProvider } from "../contexts/ThemeContext";
|
||||
import Layout from "../components/Layout";
|
||||
import config from "../lib/config";
|
||||
@ -11,10 +11,10 @@ import "modern-normalize/modern-normalize.css"; // https://github.com/sindresorh
|
||||
import "./themes.css";
|
||||
import "./global.css";
|
||||
|
||||
import { meJpg } from "../lib/config/favicons";
|
||||
import meJpg from "../public/static/images/me.jpg";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(process.env.NEXT_PUBLIC_BASE_URL || `https://${config.siteDomain}`),
|
||||
metadataBase: new URL(config.baseUrl),
|
||||
title: {
|
||||
template: `%s – ${config.siteName}`,
|
||||
default: `${config.siteName} – ${config.shortDescription}`,
|
||||
@ -23,7 +23,7 @@ export const metadata: Metadata = {
|
||||
openGraph: {
|
||||
siteName: config.siteName,
|
||||
title: {
|
||||
template: `%s – ${config.siteName}`,
|
||||
template: "%s",
|
||||
default: `${config.siteName} – ${config.shortDescription}`,
|
||||
},
|
||||
url: "/",
|
||||
@ -37,11 +37,21 @@ export const metadata: Metadata = {
|
||||
],
|
||||
},
|
||||
alternates: {
|
||||
types: {
|
||||
"application/rss+xml": "/feed.xml",
|
||||
"application/atom+xml": "/feed.atom",
|
||||
},
|
||||
canonical: "/",
|
||||
types: {
|
||||
"application/rss+xml": [
|
||||
{
|
||||
title: `${config.siteName} (RSS)`,
|
||||
url: "/feed.xml",
|
||||
},
|
||||
],
|
||||
"application/atom+xml": [
|
||||
{
|
||||
title: `${config.siteName} (Atom)`,
|
||||
url: "/feed.atom",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
other: {
|
||||
humans: "/humans.txt",
|
||||
@ -53,10 +63,10 @@ const jsonLd: WithContext<Person> = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Person",
|
||||
name: config.authorName,
|
||||
url: metadata.metadataBase?.href || `https://${config.siteDomain}/`,
|
||||
image: new URL(meJpg.src, metadata.metadataBase || `https://${config.siteDomain}`).href,
|
||||
url: config.baseUrl,
|
||||
image: `${config.baseUrl}${meJpg.src}`,
|
||||
sameAs: [
|
||||
metadata.metadataBase?.href || `https://${config.siteDomain}/`,
|
||||
config.baseUrl,
|
||||
`https://github.com/${config.authorSocial?.github}`,
|
||||
`https://keybase.io/${config.authorSocial?.keybase}`,
|
||||
`https://twitter.com/${config.authorSocial?.twitter}`,
|
||||
@ -73,13 +83,6 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
return (
|
||||
<html lang={config.siteLocale} suppressHydrationWarning>
|
||||
<head>
|
||||
<script
|
||||
// unminified: https://gist.github.com/jakejarvis/79b0ec8506bc843023546d0d29861bf0
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `(()=>{try{const e=document.documentElement,t="undefined"!=typeof Storage?window.localStorage.getItem("theme"):null,a=(t&&"dark"===t)??window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";e.dataset.theme=a,e.style.colorScheme=a}catch(e){}})()`,
|
||||
}}
|
||||
/>
|
||||
|
||||
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
|
||||
</head>
|
||||
|
||||
|
@ -33,8 +33,8 @@ export default function Page() {
|
||||
webm: "/static/images/leo/leo.webm",
|
||||
mp4: "/static/images/leo/leo.mp4",
|
||||
vtt: "/static/images/leo/subs.en.vtt",
|
||||
image: thumbnail.src,
|
||||
}}
|
||||
poster={thumbnail.src}
|
||||
/>
|
||||
|
||||
<p
|
||||
|
@ -45,11 +45,7 @@ export default function Page() {
|
||||
<H2 id="full-text">Creative Commons Attribution 4.0 International Public License</H2>
|
||||
|
||||
<p style={{ textAlign: "center", lineHeight: 0 }}>
|
||||
<Link
|
||||
href="https://creativecommons.org/licenses/by/4.0/"
|
||||
title="Creative Commons Attribution 4.0"
|
||||
underline={false}
|
||||
>
|
||||
<Link href="https://creativecommons.org/licenses/by/4.0/" title="Creative Commons Attribution 4.0" plain>
|
||||
<svg width="120" height="42">
|
||||
<path d="M3.1.5l113.4.2c1.6 0 3-.2 3 3.2l-.1 37.3H.3V3.7C.3 2.1.4.5 3 .5z" fill="#aab2ab"></path>
|
||||
<path d="M117.8 0H2.2C1 0 0 1 0 2.2v39.3c0 .3.2.5.5.5h119c.3 0 .5-.2.5-.5V2.2c0-1.2-1-2.2-2.2-2.2zM2.2 1h115.6c.6 0 1.2.6 1.2 1.2v27.3H36.2a17.8 17.8 0 01-31.1 0H1V2.2C1 1.6 1.5 1 2.1 1z"></path>
|
||||
|
@ -1,11 +1,15 @@
|
||||
import config from "../lib/config";
|
||||
import { chrome512Png, chrome192Png, maskable512Png, maskable192Png } from "../lib/config/favicons";
|
||||
import type { MetadataRoute } from "next";
|
||||
|
||||
import chrome512Png from "../public/static/favicons/android-chrome-512x512.png";
|
||||
import chrome192Png from "../public/static/favicons/android-chrome-192x192.png";
|
||||
import maskable512Png from "../public/static/favicons/maskable-512x512.png";
|
||||
import maskable192Png from "../public/static/favicons/maskable-192x192.png";
|
||||
|
||||
const manifest = (): MetadataRoute.Manifest => {
|
||||
return {
|
||||
name: config.siteName,
|
||||
short_name: config.siteDomain,
|
||||
short_name: config.siteName,
|
||||
description: config.longDescription,
|
||||
lang: config.siteLocale,
|
||||
icons: [
|
||||
|
@ -7,16 +7,16 @@
|
||||
color: var(--colors-medium);
|
||||
}
|
||||
|
||||
.meta .item {
|
||||
.meta .metaItem {
|
||||
margin-right: 1.6em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.meta .link {
|
||||
.meta .metaLink {
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
.meta .icon {
|
||||
.meta .metaIcon {
|
||||
display: inline;
|
||||
width: 1.2em;
|
||||
height: 1.2em;
|
||||
@ -24,23 +24,23 @@
|
||||
margin-right: 0.6em;
|
||||
}
|
||||
|
||||
.meta .tags {
|
||||
.meta .metaTags {
|
||||
white-space: normal;
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.meta .tag {
|
||||
.meta .metaTag {
|
||||
text-transform: lowercase;
|
||||
white-space: nowrap;
|
||||
margin-right: 0.75em;
|
||||
}
|
||||
.meta .tag:before {
|
||||
.meta .metaTag:before {
|
||||
content: "\0023"; /* cosmetically hashtagify tags */
|
||||
padding-right: 0.125em;
|
||||
color: var(--colors-light);
|
||||
}
|
||||
.meta .tag:last-of-type {
|
||||
.meta .metaTag:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
import { Suspense } from "react";
|
||||
import * as runtime from "react/jsx-runtime";
|
||||
import { ErrorBoundary } from "react-error-boundary";
|
||||
import { evaluate } from "@mdx-js/mdx";
|
||||
import Content from "../../../components/Content";
|
||||
import Link from "../../../components/Link";
|
||||
import Time from "../../../components/Time";
|
||||
@ -9,7 +7,6 @@ import Comments from "../../../components/Comments";
|
||||
import Loading from "../../../components/Loading";
|
||||
import HitCounter from "./counter";
|
||||
import { getPostSlugs, getPostData } from "../../../lib/helpers/posts";
|
||||
import * as mdxComponents from "../../../lib/helpers/mdx-components";
|
||||
import { metadata as defaultMetadata } from "../../layout";
|
||||
import config from "../../../lib/config";
|
||||
import { FiCalendar, FiTag, FiEdit, FiEye } from "react-icons/fi";
|
||||
@ -62,7 +59,7 @@ export async function generateMetadata({ params }: { params: Promise<{ slug: str
|
||||
|
||||
export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
|
||||
const { slug } = await params;
|
||||
const { frontMatter, markdown } = await getPostData(slug);
|
||||
const { frontMatter } = await getPostData(slug);
|
||||
|
||||
const jsonLd: WithContext<Article> = {
|
||||
"@context": "https://schema.org",
|
||||
@ -76,49 +73,30 @@ export default async function Page({ params }: { params: Promise<{ slug: string
|
||||
author: {
|
||||
"@type": "Person",
|
||||
name: config.authorName,
|
||||
url: defaultMetadata.metadataBase?.href || `https://${config.siteDomain}`,
|
||||
url: config.baseUrl,
|
||||
},
|
||||
};
|
||||
|
||||
const { remarkGfm, remarkSmartypants, rehypeSlug, rehypeUnwrapImages, rehypePrism } = await import(
|
||||
"../../../lib/helpers/remark-rehype-plugins"
|
||||
);
|
||||
|
||||
const { default: MDXContent } = await evaluate(markdown, {
|
||||
...runtime,
|
||||
remarkPlugins: [
|
||||
[remarkGfm, { singleTilde: false }],
|
||||
[
|
||||
remarkSmartypants,
|
||||
{
|
||||
quotes: true,
|
||||
dashes: "oldschool",
|
||||
backticks: false,
|
||||
ellipses: false,
|
||||
},
|
||||
],
|
||||
],
|
||||
rehypePlugins: [rehypeSlug, rehypeUnwrapImages, [rehypePrism, { ignoreMissing: true }]],
|
||||
});
|
||||
const { default: MDXContent } = await import(`../../../notes/${slug}.mdx`);
|
||||
|
||||
return (
|
||||
<>
|
||||
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
|
||||
|
||||
<div className={styles.meta}>
|
||||
<div className={styles.item}>
|
||||
<Link href={`/notes/${frontMatter.slug}` as Route} underline={false} className={styles.link}>
|
||||
<FiCalendar className={styles.icon} />
|
||||
<div className={styles.metaItem}>
|
||||
<Link href={`/notes/${frontMatter.slug}` as Route} plain className={styles.metaLink}>
|
||||
<FiCalendar className={styles.metaIcon} />
|
||||
<Time date={frontMatter.date} format="MMMM D, YYYY" />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{frontMatter.tags && (
|
||||
<div className={styles.item}>
|
||||
<FiTag className={styles.icon} />
|
||||
<span className={styles.tags}>
|
||||
<div className={styles.metaItem}>
|
||||
<FiTag className={styles.metaIcon} />
|
||||
<span className={styles.metaTags}>
|
||||
{frontMatter.tags.map((tag) => (
|
||||
<span key={tag} title={tag} className={styles.tag} aria-label={`Tagged with ${tag}`}>
|
||||
<span key={tag} title={tag} className={styles.metaTag} aria-label={`Tagged with ${tag}`}>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
@ -126,14 +104,14 @@ export default async function Page({ params }: { params: Promise<{ slug: string
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={styles.item}>
|
||||
<div className={styles.metaItem}>
|
||||
<Link
|
||||
href={`https://github.com/${config.githubRepo}/blob/main/notes/${frontMatter.slug}.mdx`}
|
||||
title={`Edit "${frontMatter.title}" on GitHub`}
|
||||
underline={false}
|
||||
className={styles.link}
|
||||
plain
|
||||
className={styles.metaLink}
|
||||
>
|
||||
<FiEdit className={styles.icon} />
|
||||
<FiEdit className={styles.metaIcon} />
|
||||
<span>Improve This Post</span>
|
||||
</Link>
|
||||
</div>
|
||||
@ -142,14 +120,14 @@ export default async function Page({ params }: { params: Promise<{ slug: string
|
||||
{process.env.NEXT_PUBLIC_VERCEL_ENV === "production" && (
|
||||
<ErrorBoundary fallback={null}>
|
||||
<div
|
||||
className={styles.item}
|
||||
className={styles.metaItem}
|
||||
style={{
|
||||
// fix potential layout shift when number of hits loads
|
||||
minWidth: "7em",
|
||||
marginRight: 0,
|
||||
}}
|
||||
>
|
||||
<FiEye className={styles.icon} />
|
||||
<FiEye className={styles.metaIcon} />
|
||||
<Suspense fallback={<Loading boxes={3} width={20} />}>
|
||||
<HitCounter slug={`notes/${frontMatter.slug}`} />
|
||||
</Suspense>
|
||||
@ -162,16 +140,13 @@ export default async function Page({ params }: { params: Promise<{ slug: string
|
||||
<Link
|
||||
href={`/notes/${frontMatter.slug}` as Route}
|
||||
dangerouslySetInnerHTML={{ __html: frontMatter.htmlTitle || frontMatter.title }}
|
||||
underline={false}
|
||||
plain
|
||||
className={styles.link}
|
||||
/>
|
||||
</h1>
|
||||
|
||||
<Content>
|
||||
<MDXContent
|
||||
// @ts-ignore
|
||||
components={{ ...mdxComponents }}
|
||||
/>
|
||||
<MDXContent />
|
||||
</Content>
|
||||
|
||||
{!frontMatter.noComments && (
|
||||
|
@ -251,7 +251,7 @@ export default function Page() {
|
||||
title="My Public Key"
|
||||
lightColor="#757575"
|
||||
darkColor="#959595"
|
||||
underline={false}
|
||||
plain
|
||||
openInNewTab
|
||||
>
|
||||
<GoLock
|
||||
|
@ -33,7 +33,3 @@
|
||||
.screenshot:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 1em auto;
|
||||
}
|
||||
|
@ -52,13 +52,7 @@ export default async function Page() {
|
||||
fontFamily: `${ComicNeue.style.fontFamily}, var(--fonts-sans)`,
|
||||
}}
|
||||
>
|
||||
<Figure
|
||||
src={img_wayback}
|
||||
href="https://web.archive.org/web/20010501000000*/jakejarvis.com"
|
||||
alt="Timeline of this website's past."
|
||||
priority
|
||||
className={styles.screenshot}
|
||||
>
|
||||
<Figure src={img_wayback} alt="Timeline of this website's past." priority className={styles.screenshot}>
|
||||
...the{" "}
|
||||
<Link href="https://web.archive.org/web/20010501000000*/jakejarvis.com">Cringey Chronicles™</Link> of
|
||||
this website's past.
|
||||
@ -181,36 +175,21 @@ export default async function Page() {
|
||||
|
||||
<HorizontalRule className={styles.divider} />
|
||||
|
||||
<Figure
|
||||
src={img_2012_09}
|
||||
href="https://focused-knuth-7bc10d.netlify.app/"
|
||||
alt="September 2012"
|
||||
className={styles.screenshot}
|
||||
>
|
||||
<Figure src={img_2012_09} alt="September 2012" className={styles.screenshot}>
|
||||
<Link href="https://focused-knuth-7bc10d.netlify.app/">September 2012</Link> (
|
||||
<Link href="https://github.com/jakejarvis/jarv.is/tree/v1">view source</Link>)
|
||||
</Figure>
|
||||
|
||||
<HorizontalRule className={styles.divider} />
|
||||
|
||||
<Figure
|
||||
src={img_2018_04}
|
||||
href="https://hungry-mayer-40e790.netlify.app/"
|
||||
alt="April 2018"
|
||||
className={styles.screenshot}
|
||||
>
|
||||
<Figure src={img_2018_04} alt="April 2018" className={styles.screenshot}>
|
||||
<Link href="https://hungry-mayer-40e790.netlify.app/">April 2018</Link> (
|
||||
<Link href="https://github.com/jakejarvis/jarv.is/tree/v2">view source</Link>)
|
||||
</Figure>
|
||||
|
||||
<HorizontalRule className={styles.divider} />
|
||||
|
||||
<Figure
|
||||
src={img_2020_03}
|
||||
href="https://quiet-truffle-92842d.netlify.app/"
|
||||
alt="March 2020"
|
||||
className={styles.screenshot}
|
||||
>
|
||||
<Figure src={img_2020_03} alt="March 2020" className={styles.screenshot}>
|
||||
<Link href="https://quiet-truffle-92842d.netlify.app/">March 2020</Link> (
|
||||
<Link href="https://github.com/jakejarvis/jarv.is-hugo">view source</Link>)
|
||||
</Figure>
|
||||
|
@ -143,7 +143,7 @@ export default async function Page() {
|
||||
// @ts-ignore
|
||||
href={`${repo.url}/stargazers`}
|
||||
title={`${commaNumber(repo.stars)} ${repo.stars === 1 ? "star" : "stars"}`}
|
||||
underline={false}
|
||||
plain
|
||||
className={styles.metaLink}
|
||||
>
|
||||
<GoStar className={styles.metaIcon} />
|
||||
@ -158,7 +158,7 @@ export default async function Page() {
|
||||
// @ts-ignore
|
||||
href={`${repo.url}/network/members`}
|
||||
title={`${commaNumber(repo.forks)} ${repo.forks === 1 ? "fork" : "forks"}`}
|
||||
underline={false}
|
||||
plain
|
||||
className={styles.metaLink}
|
||||
>
|
||||
<GoRepoForked className={styles.metaIcon} />
|
||||
|
@ -1,5 +1,4 @@
|
||||
import config from "../lib/config";
|
||||
import { metadata } from "./layout";
|
||||
import type { MetadataRoute } from "next";
|
||||
|
||||
export const dynamic = "force-static";
|
||||
@ -73,7 +72,7 @@ const robots = (): MetadataRoute.Robots => {
|
||||
disallow: "/",
|
||||
},
|
||||
],
|
||||
sitemap: new URL("sitemap.xml", metadata.metadataBase?.href || `https://${config.siteDomain}`).href,
|
||||
sitemap: `${config.baseUrl}/sitemap.xml`,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import path from "path";
|
||||
import glob from "fast-glob";
|
||||
import { getAllPosts } from "../lib/helpers/posts";
|
||||
import { metadata } from "./layout";
|
||||
import config from "../lib/config";
|
||||
import type { MetadataRoute } from "next";
|
||||
|
||||
export const dynamic = "force-static";
|
||||
@ -11,21 +11,19 @@ const sitemap = async (): Promise<MetadataRoute.Sitemap> => {
|
||||
const routes: MetadataRoute.Sitemap = [
|
||||
{
|
||||
// homepage
|
||||
url: "/",
|
||||
url: config.baseUrl,
|
||||
priority: 1.0,
|
||||
changeFrequency: "weekly",
|
||||
lastModified: new Date(process.env.RELEASE_DATE || Date.now()), // timestamp frozen when a new build is deployed
|
||||
},
|
||||
{
|
||||
url: "/tweets/",
|
||||
changeFrequency: "yearly",
|
||||
},
|
||||
{ url: `${config.baseUrl}/tweets/` },
|
||||
];
|
||||
|
||||
// add each directory in the app folder as a route (excluding special routes)
|
||||
const appDir = path.resolve(process.cwd(), "app");
|
||||
(
|
||||
await glob("*", {
|
||||
cwd: path.join(process.cwd(), "app"),
|
||||
cwd: appDir,
|
||||
deep: 0,
|
||||
onlyDirectories: true,
|
||||
markDirectories: true,
|
||||
@ -39,7 +37,7 @@ const sitemap = async (): Promise<MetadataRoute.Sitemap> => {
|
||||
).forEach((route) => {
|
||||
routes.push({
|
||||
// make all URLs absolute
|
||||
url: route,
|
||||
url: `${config.baseUrl}/${route}`,
|
||||
});
|
||||
});
|
||||
|
||||
@ -51,9 +49,6 @@ const sitemap = async (): Promise<MetadataRoute.Sitemap> => {
|
||||
});
|
||||
});
|
||||
|
||||
// make all URLs absolute
|
||||
routes.forEach((page) => (page.url = new URL(page.url, metadata.metadataBase || "").href));
|
||||
|
||||
return routes;
|
||||
};
|
||||
|
||||
|
@ -29,7 +29,6 @@
|
||||
--sizes-maxLayoutWidth: 865px;
|
||||
--radii-corner: 0.6rem;
|
||||
--transitions-fade: 0.25s ease;
|
||||
--transitions-linkHover: 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
|
@ -40,7 +40,9 @@ export default function Page() {
|
||||
❤️
|
||||
</p>
|
||||
|
||||
<Image src={desktopImg} href={desktopImg.src as Route} alt="My mess of a desktop." priority />
|
||||
<Link href={desktopImg.src as Route} openInNewTab>
|
||||
<Image src={desktopImg} alt="My mess of a desktop." priority />
|
||||
</Link>
|
||||
|
||||
<H2 id="hardware">
|
||||
<span style={{ marginRight: "0.45em" }}>🚘</span>
|
||||
|
@ -40,7 +40,7 @@ export default async function Page() {
|
||||
<span style={{ color: "var(--colors-codeKeyword)" }}>google</span>:
|
||||
<span style={{ color: "var(--colors-codeAttribute)" }}>~</span>${" "}
|
||||
<span style={{ color: "var(--colors-codeLiteral)" }}>mv</span> /root
|
||||
<Link href="https://killedbygoogle.com/" style={{ color: "inherit" }} underline={false}>
|
||||
<Link href="https://killedbygoogle.com/" style={{ color: "inherit" }} plain>
|
||||
/stable_products_that_people_rely_on/
|
||||
</Link>
|
||||
googledomains.zip /tmp/
|
||||
@ -62,7 +62,7 @@ export default async function Page() {
|
||||
<span style={{ color: "var(--colors-codeAttribute)" }}>@monthly</span>
|
||||
<span style={{ color: "var(--colors-codeLiteral)" }}>rm</span>{" "}
|
||||
<span style={{ color: "var(--colors-codeVariable )" }}>-f</span> /tmp/
|
||||
<Link href="https://fuckyougoogle.zip/" style={{ color: "inherit" }} underline={false}>
|
||||
<Link href="https://fuckyougoogle.zip/" style={{ color: "inherit" }} plain>
|
||||
*.zip
|
||||
</Link>
|
||||
<br />
|
||||
|
Reference in New Issue
Block a user