mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2026-06-05 19:35:27 -04:00
refactor: update font imports and variables
- Replaced GeistSans and GeistMono with Inter and JetBrainsMono in globals.css and layout.tsx. - Updated font variable names to reflect the new font choices in fonts.ts.
This commit is contained in:
+2
-2
@@ -6,9 +6,9 @@
|
|||||||
@custom-variant dark (&:where(.dark *));
|
@custom-variant dark (&:where(.dark *));
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
--font-sans: var(--font-geist-sans);
|
--font-sans: var(--font-inter);
|
||||||
--font-sans--font-feature-settings: "rlig" 1, "calt" 0;
|
--font-sans--font-feature-settings: "rlig" 1, "calt" 0;
|
||||||
--font-mono: var(--font-geist-mono);
|
--font-mono: var(--font-jetbrains-mono);
|
||||||
--font-mono--font-feature-settings: "liga" 0;
|
--font-mono--font-feature-settings: "liga" 0;
|
||||||
--radius-sm: calc(var(--radius) - 4px);
|
--radius-sm: calc(var(--radius) - 4px);
|
||||||
--radius-md: calc(var(--radius) - 2px);
|
--radius-md: calc(var(--radius) - 2px);
|
||||||
|
|||||||
+2
-2
@@ -7,7 +7,7 @@ import { Footer } from "@/components/layout/footer";
|
|||||||
import { Toaster } from "@/components/ui/sonner";
|
import { Toaster } from "@/components/ui/sonner";
|
||||||
import { Analytics } from "@/app/analytics";
|
import { Analytics } from "@/app/analytics";
|
||||||
import { defaultMetadata } from "@/lib/metadata";
|
import { defaultMetadata } from "@/lib/metadata";
|
||||||
import { GeistSans, GeistMono } from "@/lib/fonts";
|
import { Inter, JetBrainsMono } from "@/lib/fonts";
|
||||||
import siteConfig from "@/lib/config/site";
|
import siteConfig from "@/lib/config/site";
|
||||||
import authorConfig from "@/lib/config/author";
|
import authorConfig from "@/lib/config/author";
|
||||||
import type { Person, WebSite } from "schema-dts";
|
import type { Person, WebSite } from "schema-dts";
|
||||||
@@ -20,7 +20,7 @@ const RootLayout = ({ children }: Readonly<{ children: React.ReactNode }>) => {
|
|||||||
return (
|
return (
|
||||||
<html
|
<html
|
||||||
lang={env.NEXT_PUBLIC_SITE_LOCALE}
|
lang={env.NEXT_PUBLIC_SITE_LOCALE}
|
||||||
className={`${GeistSans.variable} ${GeistMono.variable}`}
|
className={`${Inter.variable} ${JetBrainsMono.variable}`}
|
||||||
suppressHydrationWarning
|
suppressHydrationWarning
|
||||||
>
|
>
|
||||||
<head>
|
<head>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { ImageResponse } from "next/og";
|
|||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { getSlugs, getFrontMatter, POSTS_DIR } from "@/lib/posts";
|
import { getSlugs, getFrontMatter, POSTS_DIR } from "@/lib/posts";
|
||||||
import siteConfig from "@/lib/config/site";
|
import siteConfig from "@/lib/config/site";
|
||||||
|
import { loadGoogleFont } from "@/lib/og-utils";
|
||||||
|
|
||||||
export const contentType = "image/png";
|
export const contentType = "image/png";
|
||||||
export const size = {
|
export const size = {
|
||||||
@@ -53,16 +54,14 @@ const OpenGraphImage = async ({ params }: { params: Promise<{ slug: string }> })
|
|||||||
// get the post's title and image filename from its frontmatter
|
// get the post's title and image filename from its frontmatter
|
||||||
const frontmatter = await getFrontMatter(slug);
|
const frontmatter = await getFrontMatter(slug);
|
||||||
|
|
||||||
const [postImg, avatarImg, fontRegular, fontSemiBold] = await Promise.all([
|
// IMPORTANT: include these exact paths in next.config.ts under "outputFileTracingIncludes"
|
||||||
|
const [postImg, avatarImg] = await Promise.all([
|
||||||
frontmatter!.image ? getLocalImage(`${POSTS_DIR}/${slug}/${frontmatter!.image}`) : null,
|
frontmatter!.image ? getLocalImage(`${POSTS_DIR}/${slug}/${frontmatter!.image}`) : null,
|
||||||
|
|
||||||
// IMPORTANT: include these exact paths in next.config.ts under "outputFileTracingIncludes"
|
|
||||||
getLocalImage("app/avatar.jpg"),
|
getLocalImage("app/avatar.jpg"),
|
||||||
// load the Geist font directly from its npm package
|
|
||||||
fs.promises.readFile(path.join(process.cwd(), "node_modules/geist/dist/fonts/geist-sans/Geist-Regular.ttf")),
|
|
||||||
fs.promises.readFile(path.join(process.cwd(), "node_modules/geist/dist/fonts/geist-sans/Geist-SemiBold.ttf")),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const [fontRegular, fontSemibold] = await Promise.all([loadGoogleFont("Inter", 400), loadGoogleFont("Inter", 600)]);
|
||||||
|
|
||||||
// template is HEAVILY inspired by https://og-new.clerkstage.dev/
|
// template is HEAVILY inspired by https://og-new.clerkstage.dev/
|
||||||
return new ImageResponse(
|
return new ImageResponse(
|
||||||
<div
|
<div
|
||||||
@@ -138,8 +137,7 @@ const OpenGraphImage = async ({ params }: { params: Promise<{ slug: string }> })
|
|||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: "1.825rem",
|
fontSize: "1.825rem",
|
||||||
fontFamily: "Geist-SemiBold",
|
fontWeight: 600,
|
||||||
fontWeight: 700,
|
|
||||||
lineHeight: "3rem",
|
lineHeight: "3rem",
|
||||||
letterSpacing: "-0.015em",
|
letterSpacing: "-0.015em",
|
||||||
marginLeft: "0.75rem",
|
marginLeft: "0.75rem",
|
||||||
@@ -153,8 +151,7 @@ const OpenGraphImage = async ({ params }: { params: Promise<{ slug: string }> })
|
|||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexGrow: 0,
|
flexGrow: 0,
|
||||||
fontFamily: "Geist-SemiBold",
|
fontWeight: 600,
|
||||||
fontWeight: 700,
|
|
||||||
fontSize: "48px",
|
fontSize: "48px",
|
||||||
color: "#030712",
|
color: "#030712",
|
||||||
letterSpacing: "-0.025em",
|
letterSpacing: "-0.025em",
|
||||||
@@ -172,7 +169,6 @@ const OpenGraphImage = async ({ params }: { params: Promise<{ slug: string }> })
|
|||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontFamily: "Geist-Regular",
|
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
fontSize: "20px",
|
fontSize: "20px",
|
||||||
color: "#030712",
|
color: "#030712",
|
||||||
@@ -193,7 +189,6 @@ const OpenGraphImage = async ({ params }: { params: Promise<{ slug: string }> })
|
|||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexGrow: 0,
|
flexGrow: 0,
|
||||||
fontFamily: "Geist-Regular",
|
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
fontSize: "24px",
|
fontSize: "24px",
|
||||||
color: "#030712",
|
color: "#030712",
|
||||||
@@ -235,16 +230,16 @@ const OpenGraphImage = async ({ params }: { params: Promise<{ slug: string }> })
|
|||||||
...size,
|
...size,
|
||||||
fonts: [
|
fonts: [
|
||||||
{
|
{
|
||||||
name: "Geist-Regular",
|
name: "Inter",
|
||||||
data: fontRegular,
|
data: fontRegular,
|
||||||
style: "normal",
|
style: "normal",
|
||||||
weight: 400,
|
weight: 400,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Geist-SemiBold",
|
name: "Inter",
|
||||||
data: fontSemiBold,
|
data: fontSemibold,
|
||||||
style: "normal",
|
style: "normal",
|
||||||
weight: 700,
|
weight: 600,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,15 +9,14 @@ const Footer = () => {
|
|||||||
<Link href="/license" className="underline underline-offset-4">
|
<Link href="/license" className="underline underline-offset-4">
|
||||||
{siteConfig.license}
|
{siteConfig.license}
|
||||||
</Link>
|
</Link>
|
||||||
. Code is{" "}
|
. View source on{" "}
|
||||||
<a
|
<a
|
||||||
href={`https://github.com/${env.NEXT_PUBLIC_GITHUB_REPO}`}
|
href={`https://github.com/${env.NEXT_PUBLIC_GITHUB_REPO}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
title="View Source on GitHub"
|
|
||||||
className="underline underline-offset-4"
|
className="underline underline-offset-4"
|
||||||
>
|
>
|
||||||
open source
|
GitHub
|
||||||
</a>
|
</a>
|
||||||
.
|
.
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
+6
-6
@@ -2,22 +2,22 @@
|
|||||||
// https://nextjs.org/docs/pages/building-your-application/optimizing/fonts#reusing-fonts
|
// https://nextjs.org/docs/pages/building-your-application/optimizing/fonts#reusing-fonts
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Geist as GeistSansLoader,
|
Inter as InterLoader,
|
||||||
Geist_Mono as GeistMonoLoader,
|
JetBrains_Mono as JetBrainsMonoLoader,
|
||||||
Comic_Neue as ComicNeueLoader,
|
Comic_Neue as ComicNeueLoader,
|
||||||
} from "next/font/google";
|
} from "next/font/google";
|
||||||
|
|
||||||
export const GeistSans = GeistSansLoader({
|
export const Inter = InterLoader({
|
||||||
subsets: ["latin"],
|
subsets: ["latin"],
|
||||||
display: "swap",
|
display: "swap",
|
||||||
variable: "--font-geist-sans",
|
variable: "--font-inter",
|
||||||
preload: true,
|
preload: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const GeistMono = GeistMonoLoader({
|
export const JetBrainsMono = JetBrainsMonoLoader({
|
||||||
subsets: ["latin"],
|
subsets: ["latin"],
|
||||||
display: "swap",
|
display: "swap",
|
||||||
variable: "--font-geist-mono",
|
variable: "--font-jetbrains-mono",
|
||||||
preload: true,
|
preload: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { cacheLife } from "next/cache";
|
||||||
|
|
||||||
|
// Load a Google Font from the Google Fonts API
|
||||||
|
// Adapted from https://github.com/brianlovin/briOS/blob/f72dc33a11194de45c80337b22be4560da62ad7e/src/lib/og-utils.tsx#L32
|
||||||
|
export async function loadGoogleFont(font: string, weight: number): Promise<ArrayBuffer> {
|
||||||
|
"use cache";
|
||||||
|
|
||||||
|
const url = `https://fonts.googleapis.com/css2?family=${font}:wght@${weight}`;
|
||||||
|
|
||||||
|
const cssResponse = await fetch(url, {
|
||||||
|
next: {
|
||||||
|
revalidate: 31_536_000, // 1 year
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const css = await cssResponse.text();
|
||||||
|
const resource = css.match(/src: url\((.+)\) format\('(opentype|truetype)'\)/);
|
||||||
|
|
||||||
|
if (resource) {
|
||||||
|
const fontResponse = await fetch(resource[1], {
|
||||||
|
next: {
|
||||||
|
revalidate: 31_536_000, // 1 year
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (fontResponse.status === 200) {
|
||||||
|
cacheLife("max"); // cache indefinitely if successful
|
||||||
|
return fontResponse.arrayBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Failed to load font: ${font} ${weight}`);
|
||||||
|
}
|
||||||
+1
-6
@@ -22,12 +22,7 @@ const nextConfig = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
outputFileTracingIncludes: {
|
outputFileTracingIncludes: {
|
||||||
"/notes/[slug]/opengraph-image": [
|
"/notes/[slug]/opengraph-image": ["./notes/**/*", "./app/opengraph-image.jpg"],
|
||||||
"./notes/**/*",
|
|
||||||
"./app/opengraph-image.jpg",
|
|
||||||
"./node_modules/geist/dist/fonts/geist-sans/Geist-Regular.ttf",
|
|
||||||
"./node_modules/geist/dist/fonts/geist-sans/Geist-SemiBold.ttf",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
productionBrowserSourceMaps: true,
|
productionBrowserSourceMaps: true,
|
||||||
experimental: {
|
experimental: {
|
||||||
|
|||||||
+16
-17
@@ -47,11 +47,11 @@
|
|||||||
"@radix-ui/react-toggle-group": "^1.1.11",
|
"@radix-ui/react-toggle-group": "^1.1.11",
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
"@t3-oss/env-nextjs": "^0.13.10",
|
"@t3-oss/env-nextjs": "^0.13.10",
|
||||||
"@tanstack/react-form": "^1.28.0",
|
"@tanstack/react-form": "^1.28.3",
|
||||||
"@vercel/analytics": "^1.6.1",
|
"@vercel/analytics": "^1.6.1",
|
||||||
"@vercel/functions": "^3.4.0",
|
"@vercel/functions": "^3.4.2",
|
||||||
"@vercel/speed-insights": "^1.3.1",
|
"@vercel/speed-insights": "^1.3.1",
|
||||||
"better-auth": "^1.4.17",
|
"better-auth": "^1.4.18",
|
||||||
"botid": "^1.5.10",
|
"botid": "^1.5.10",
|
||||||
"cheerio": "^1.2.0",
|
"cheerio": "^1.2.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
@@ -60,18 +60,17 @@
|
|||||||
"drizzle-orm": "^0.45.1",
|
"drizzle-orm": "^0.45.1",
|
||||||
"fast-glob": "^3.3.3",
|
"fast-glob": "^3.3.3",
|
||||||
"feed": "^5.2.0",
|
"feed": "^5.2.0",
|
||||||
"geist": "^1.5.1",
|
|
||||||
"html-entities": "^2.6.0",
|
"html-entities": "^2.6.0",
|
||||||
"lucide-react": "0.563.0",
|
"lucide-react": "0.575.0",
|
||||||
"next": "16.1.6",
|
"next": "16.1.6",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"pg": "^8.17.2",
|
"pg": "^8.18.0",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
"react-activity-calendar": "^3.1.1",
|
"react-activity-calendar": "^3.1.1",
|
||||||
"react-compare-slider": "^3.1.0",
|
"react-compare-slider": "^3.1.0",
|
||||||
"react-countup": "^6.5.3",
|
"react-countup": "^6.5.3",
|
||||||
"react-dom": "19.2.4",
|
"react-dom": "19.2.4",
|
||||||
"react-lite-youtube-embed": "^3.3.3",
|
"react-lite-youtube-embed": "~3.3.3",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"react-schemaorg": "^2.0.0",
|
"react-schemaorg": "^2.0.0",
|
||||||
"react-timeago": "^8.3.0",
|
"react-timeago": "^8.3.0",
|
||||||
@@ -92,12 +91,12 @@
|
|||||||
"remark-rehype": "^11.1.2",
|
"remark-rehype": "^11.1.2",
|
||||||
"remark-smartypants": "^3.0.2",
|
"remark-smartypants": "^3.0.2",
|
||||||
"remark-strip-mdx-imports-exports": "^1.0.1",
|
"remark-strip-mdx-imports-exports": "^1.0.1",
|
||||||
"resend": "^6.9.1",
|
"resend": "^6.9.2",
|
||||||
"server-only": "0.0.1",
|
"server-only": "0.0.1",
|
||||||
"shiki": "^3.21.0",
|
"shiki": "^3.22.0",
|
||||||
"sonner": "^2.0.7",
|
"sonner": "^2.0.7",
|
||||||
"tailwind-merge": "^3.4.0",
|
"tailwind-merge": "^3.5.0",
|
||||||
"tailwindcss": "^4.1.18",
|
"tailwindcss": "^4.2.0",
|
||||||
"unified": "^11.0.5",
|
"unified": "^11.0.5",
|
||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
@@ -105,18 +104,18 @@
|
|||||||
"@eslint/eslintrc": "^3.3.3",
|
"@eslint/eslintrc": "^3.3.3",
|
||||||
"@eslint/js": "^9.39.2",
|
"@eslint/js": "^9.39.2",
|
||||||
"@jakejarvis/eslint-config": "^4.0.7",
|
"@jakejarvis/eslint-config": "^4.0.7",
|
||||||
"@tailwindcss/postcss": "^4.1.18",
|
"@tailwindcss/postcss": "^4.2.0",
|
||||||
"@tailwindcss/typography": "^0.5.19",
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
"@types/hast": "^3.0.4",
|
"@types/hast": "^3.0.4",
|
||||||
"@types/mdx": "^2.0.13",
|
"@types/mdx": "^2.0.13",
|
||||||
"@types/node": "^25.1.0",
|
"@types/node": "^25.3.0",
|
||||||
"@types/pg": "^8.16.0",
|
"@types/pg": "^8.16.0",
|
||||||
"@types/react": "19.2.10",
|
"@types/react": "19.2.14",
|
||||||
"@types/react-dom": "19.2.3",
|
"@types/react-dom": "19.2.3",
|
||||||
"babel-plugin-react-compiler": "19.1.0-rc.3",
|
"babel-plugin-react-compiler": "19.1.0-rc.3",
|
||||||
"cross-env": "^10.1.0",
|
"cross-env": "^10.1.0",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.3.1",
|
||||||
"drizzle-kit": "^0.31.8",
|
"drizzle-kit": "^0.31.9",
|
||||||
"eslint": "^9.39.2",
|
"eslint": "^9.39.2",
|
||||||
"eslint-config-next": "16.1.6",
|
"eslint-config-next": "16.1.6",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
@@ -141,7 +140,7 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=24.x"
|
"node": ">=24.x"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.28.2+sha512.41872f037ad22f7348e3b1debbaf7e867cfd448f2726d9cf74c08f19507c31d2c8e7a11525b983febc2df640b5438dee6023ebb1f84ed43cc2d654d2bc326264",
|
"packageManager": "pnpm@10.30.0+sha512.2b5753de015d480eeb88f5b5b61e0051f05b4301808a82ec8b840c9d2adf7748eb352c83f5c1593ca703ff1017295bc3fdd3119abb9686efc96b9fcb18200937",
|
||||||
"cacheDirectories": [
|
"cacheDirectories": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
".next/cache"
|
".next/cache"
|
||||||
|
|||||||
Generated
+657
-825
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user