1
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:
2025-03-03 15:56:57 -05:00
parent 36faa6c234
commit ba10742c9b
71 changed files with 685 additions and 1100 deletions

View File

@ -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>
</>

View File

@ -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>

View File

@ -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?",

View File

@ -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>

View File

@ -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:{" "}

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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: [

View File

@ -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;
}

View File

@ -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 && (

View File

@ -251,7 +251,7 @@ export default function Page() {
title="My Public Key"
lightColor="#757575"
darkColor="#959595"
underline={false}
plain
openInNewTab
>
<GoLock

View File

@ -33,7 +33,3 @@
.screenshot:last-of-type {
margin-bottom: 0;
}
.divider {
margin: 1em auto;
}

View File

@ -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&trade;</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>

View File

@ -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} />

View File

@ -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`,
};
};

View File

@ -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;
};

View File

@ -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"] {

View File

@ -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>

View File

@ -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>&nbsp;&nbsp;&nbsp;&nbsp;
<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 />