1
mirror of https://github.com/jakejarvis/jarv.is.git synced 2025-04-26 17:28:27 -04:00

extract metadata merging logic from each page into a helper function

This commit is contained in:
Jake Jarvis 2025-03-14 20:16:27 -04:00
parent 6e572a8f48
commit 5ca7e6cb22
Signed by: jake
SSH Key Fingerprint: SHA256:nCkvAjYA6XaSPUqc4TfbBQTpzr8Xj7ritg/sGInCdkc
19 changed files with 211 additions and 245 deletions

11
.prettierignore Normal file
View File

@ -0,0 +1,11 @@
# pnpm
node_modules/
pnpm-lock.yaml
.pnpm-store/
# next.js
.next/
.vercel/
# other
.devcontainer/devcontainer.json

View File

@ -1,23 +1,16 @@
import PageTitle from "../../components/PageTitle"; import PageTitle from "../../components/PageTitle";
import Video from "../../components/Video"; import Video from "../../components/Video";
import { metadata as defaultMetadata } from "../layout"; import { addMetadata } from "../../lib/helpers/metadata";
import type { Metadata } from "next";
import thumbnail from "./thumbnail.png"; import thumbnail from "./thumbnail.png";
export const metadata: Metadata = { export const metadata = addMetadata({
title: "🎉 Cranky Birthday Boy on VHS Tape 📼", title: "🎉 Cranky Birthday Boy on VHS Tape 📼",
description: "The origin of my hatred for the Happy Birthday song.", description: "The origin of my hatred for the Happy Birthday song.",
openGraph: {
...defaultMetadata.openGraph,
title: "🎉 Cranky Birthday Boy on VHS Tape 📼",
url: "/birthday",
},
alternates: { alternates: {
...defaultMetadata.alternates,
canonical: "/birthday", canonical: "/birthday",
}, },
}; });
const Page = () => { const Page = () => {
return ( return (

View File

@ -1,19 +1,13 @@
import PageTitle from "../../components/PageTitle"; import PageTitle from "../../components/PageTitle";
import { metadata as defaultMetadata } from "../layout"; import { addMetadata } from "../../lib/helpers/metadata";
export const metadata = { export const metadata = addMetadata({
title: "CLI", title: "CLI",
description: "AKA, the most useless Node module ever published, in history, by anyone, ever.", description: "AKA, the most useless Node module ever published, in history, by anyone, ever.",
openGraph: {
...defaultMetadata.openGraph,
title: "CLI",
url: "/cli",
},
alternates: { alternates: {
...defaultMetadata.alternates,
canonical: "/cli", canonical: "/cli",
}, },
}; });
<PageTitle canonical="/cli">CLI</PageTitle> <PageTitle canonical="/cli">CLI</PageTitle>

View File

@ -1,22 +1,16 @@
import PageTitle from "../../components/PageTitle"; import PageTitle from "../../components/PageTitle";
import Link from "../../components/Link"; import Link from "../../components/Link";
import ContactForm from "./form"; import ContactForm from "./form";
import { metadata as defaultMetadata } from "../layout"; import { addMetadata } from "../../lib/helpers/metadata";
import type { Metadata, Route } from "next"; import type { Route } from "next";
export const metadata: Metadata = { export const metadata = addMetadata({
title: "Contact Me", title: "Contact Me",
description: "Fill out this quick form and I'll get back to you as soon as I can.", description: "Fill out this quick form and I'll get back to you as soon as I can.",
openGraph: {
...defaultMetadata.openGraph,
title: "Contact Me",
url: "/contact",
},
alternates: { alternates: {
...defaultMetadata.alternates,
canonical: "/contact", canonical: "/contact",
}, },
}; });
const Page = () => { const Page = () => {
return ( return (

View File

@ -1,24 +1,17 @@
import PageTitle from "../../components/PageTitle"; import PageTitle from "../../components/PageTitle";
import Link from "../../components/Link"; import Link from "../../components/Link";
import Video from "../../components/Video"; import Video from "../../components/Video";
import { metadata as defaultMetadata } from "../layout"; import { addMetadata } from "../../lib/helpers/metadata";
import type { Metadata } from "next";
import thumbnail from "./thumbnail.png"; import thumbnail from "./thumbnail.png";
export const metadata: Metadata = { export const metadata = addMetadata({
title: "My Brief Apperance in Hillary Clinton's DNC Video", title: "My Brief Apperance in Hillary Clinton's DNC Video",
description: "My brief apperance in one of Hillary Clinton's 2016 DNC convention videos on substance abuse.", description: "My brief apperance in one of Hillary Clinton's 2016 DNC convention videos on substance abuse.",
openGraph: {
...defaultMetadata.openGraph,
title: "My Brief Apperance in Hillary Clinton's DNC Video",
url: "/hillary",
},
alternates: { alternates: {
...defaultMetadata.alternates,
canonical: "/hillary", canonical: "/hillary",
}, },
}; });
const Page = () => { const Page = () => {
return ( return (

View File

@ -6,6 +6,7 @@ import Footer from "../components/Footer";
import { SkipToContentLink, SkipToContentTarget } from "../components/SkipToContent"; import { SkipToContentLink, SkipToContentTarget } from "../components/SkipToContent";
import * as config from "../lib/config"; import * as config from "../lib/config";
import { BASE_URL, MAX_WIDTH } from "../lib/config/constants"; import { BASE_URL, MAX_WIDTH } from "../lib/config/constants";
import defaultMetadata from "../lib/config/metadata";
import type { Metadata } from "next"; import type { Metadata } from "next";
import type { Person, WithContext } from "schema-dts"; import type { Person, WithContext } from "schema-dts";
@ -18,47 +19,7 @@ import styles from "./layout.module.css";
import ogImage from "./opengraph-image.jpg"; import ogImage from "./opengraph-image.jpg";
export const metadata: Metadata = { export const metadata: Metadata = defaultMetadata;
metadataBase: new URL(BASE_URL),
title: {
template: `%s ${config.siteName}`,
default: `${config.siteName} ${config.shortDescription}`,
},
description: config.longDescription,
openGraph: {
siteName: config.siteName,
title: {
template: "%s",
default: `${config.siteName} ${config.shortDescription}`,
},
url: "/",
locale: config.siteLocale?.replace("-", "_"),
type: "website",
},
twitter: {
creator: `@${config.authorSocial?.twitter}`,
},
alternates: {
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",
},
};
// https://nextjs.org/docs/app/building-your-application/optimizing/metadata#json-ld // https://nextjs.org/docs/app/building-your-application/optimizing/metadata#json-ld
const jsonLd: WithContext<Person> = { const jsonLd: WithContext<Person> = {

View File

@ -1,24 +1,17 @@
import PageTitle from "../../components/PageTitle"; import PageTitle from "../../components/PageTitle";
import Link from "../../components/Link"; import Link from "../../components/Link";
import Video from "../../components/Video"; import Video from "../../components/Video";
import { metadata as defaultMetadata } from "../layout"; import { addMetadata } from "../../lib/helpers/metadata";
import type { Metadata } from "next";
import thumbnail from "./thumbnail.png"; import thumbnail from "./thumbnail.png";
export const metadata: Metadata = { export const metadata = addMetadata({
title: 'Facebook App on "The Lab with Leo Laporte"', title: 'Facebook App on "The Lab with Leo Laporte"',
description: "Powncer app featured in Leo Laporte's TechTV show.", description: "Powncer app featured in Leo Laporte's TechTV show.",
openGraph: {
...defaultMetadata.openGraph,
title: 'Facebook App on "The Lab with Leo Laporte"',
url: "/leo",
},
alternates: { alternates: {
...defaultMetadata.alternates,
canonical: "/leo", canonical: "/leo",
}, },
}; });
const Page = () => { const Page = () => {
return ( return (

View File

@ -1,18 +1,12 @@
import PageTitle from "../../components/PageTitle"; import PageTitle from "../../components/PageTitle";
import { metadata as defaultMetadata } from "../layout"; import { addMetadata } from "../../lib/helpers/metadata";
export const metadata = { export const metadata = addMetadata({
title: "License", title: "License",
openGraph: {
...defaultMetadata.openGraph,
title: "License",
url: "/license",
},
alternates: { alternates: {
...defaultMetadata.alternates,
canonical: "/license", canonical: "/license",
}, },
}; });
<PageTitle canonical="/license">License</PageTitle> <PageTitle canonical="/license">License</PageTitle>

View File

@ -7,7 +7,7 @@ import Comments from "../../../components/Comments";
import Loading from "../../../components/Loading"; import Loading from "../../../components/Loading";
import HitCounter from "./counter"; import HitCounter from "./counter";
import { getPostSlugs, getFrontMatter } from "../../../lib/helpers/posts"; import { getPostSlugs, getFrontMatter } from "../../../lib/helpers/posts";
import { metadata as defaultMetadata } from "../../layout"; import { addMetadata } from "../../../lib/helpers/metadata";
import * as config from "../../../lib/config"; import * as config from "../../../lib/config";
import { BASE_URL } from "../../../lib/config/constants"; import { BASE_URL } from "../../../lib/config/constants";
import type { Metadata, Route } from "next"; import type { Metadata, Route } from "next";
@ -34,13 +34,10 @@ export const generateMetadata = async ({ params }: { params: Promise<{ slug: str
const { slug } = await params; const { slug } = await params;
const frontmatter = await getFrontMatter(slug); const frontmatter = await getFrontMatter(slug);
return { return addMetadata({
title: frontmatter.title, title: frontmatter.title,
description: frontmatter.description, description: frontmatter.description,
openGraph: { openGraph: {
...defaultMetadata.openGraph,
title: frontmatter.title,
url: `/notes/${slug}`,
type: "article", type: "article",
authors: [config.authorName], authors: [config.authorName],
tags: frontmatter.tags, tags: frontmatter.tags,
@ -48,14 +45,12 @@ export const generateMetadata = async ({ params }: { params: Promise<{ slug: str
modifiedTime: frontmatter.date, modifiedTime: frontmatter.date,
}, },
twitter: { twitter: {
...defaultMetadata.twitter,
card: "summary_large_image", card: "summary_large_image",
}, },
alternates: { alternates: {
...defaultMetadata.alternates,
canonical: `/notes/${slug}`, canonical: `/notes/${slug}`,
}, },
}; });
}; };
const Page = async ({ params }: { params: Promise<{ slug: string }> }) => { const Page = async ({ params }: { params: Promise<{ slug: string }> }) => {

View File

@ -1,27 +1,21 @@
import Link from "../../components/Link"; import Link from "../../components/Link";
import Time from "../../components/Time"; import Time from "../../components/Time";
import { getAllPosts } from "../../lib/helpers/posts"; import { getAllPosts } from "../../lib/helpers/posts";
import { addMetadata } from "../../lib/helpers/metadata";
import * as config from "../../lib/config"; import * as config from "../../lib/config";
import { metadata as defaultMetadata } from "../layout";
import type { ReactElement } from "react"; import type { ReactElement } from "react";
import type { Metadata, Route } from "next"; import type { Route } from "next";
import type { FrontMatter } from "../../lib/helpers/posts"; import type { FrontMatter } from "../../lib/helpers/posts";
import styles from "./page.module.css"; import styles from "./page.module.css";
export const metadata: Metadata = { export const metadata = addMetadata({
title: "Notes", title: "Notes",
description: `Recent posts by ${config.authorName}.`, description: `Recent posts by ${config.authorName}.`,
openGraph: {
...defaultMetadata.openGraph,
title: "Notes",
url: "/notes",
},
alternates: { alternates: {
...defaultMetadata.alternates,
canonical: "/notes", canonical: "/notes",
}, },
}; });
const Page = async () => { const Page = async () => {
// parse the year of each note and group them together // parse the year of each note and group them together

View File

@ -3,8 +3,7 @@ import Link from "../../components/Link";
import Figure from "../../components/Figure"; import Figure from "../../components/Figure";
import CodeInline from "../../components/CodeInline"; import CodeInline from "../../components/CodeInline";
import HorizontalRule from "../../components/HorizontalRule"; import HorizontalRule from "../../components/HorizontalRule";
import { metadata as defaultMetadata } from "../layout"; import { addMetadata } from "../../lib/helpers/metadata";
import type { Metadata } from "next";
import { ComicNeue } from "../../lib/styles/fonts"; import { ComicNeue } from "../../lib/styles/fonts";
import styles from "./page.module.css"; import styles from "./page.module.css";
@ -24,19 +23,13 @@ import img_2012_09 from "./images/2012_09.png";
import img_2018_04 from "./images/2018_04.png"; import img_2018_04 from "./images/2018_04.png";
import img_2020_03 from "./images/2020_03.png"; import img_2020_03 from "./images/2020_03.png";
export const metadata: Metadata = { export const metadata = addMetadata({
title: "Previously on...", title: "Previously on...",
description: "An incredibly embarrassing and somewhat painful trip down this site's memory lane...", description: "An incredibly embarrassing and somewhat painful trip down this site's memory lane...",
openGraph: {
...defaultMetadata.openGraph,
title: "Previously on...",
url: "/previously",
},
alternates: { alternates: {
...defaultMetadata.alternates,
canonical: "/previously", canonical: "/previously",
}, },
}; });
const Page = () => { const Page = () => {
return ( return (

View File

@ -1,18 +1,12 @@
import PageTitle from "../../components/PageTitle"; import PageTitle from "../../components/PageTitle";
import { metadata as defaultMetadata } from "../layout"; import { addMetadata } from "../../lib/helpers/metadata";
export const metadata = { export const metadata = addMetadata({
title: "Privacy", title: "Privacy",
openGraph: {
...defaultMetadata.openGraph,
title: "Privacy",
url: "/privacy",
},
alternates: { alternates: {
...defaultMetadata.alternates,
canonical: "/privacy", canonical: "/privacy",
}, },
}; });
<PageTitle canonical="/privacy">Privacy</PageTitle> <PageTitle canonical="/privacy">Privacy</PageTitle>

View File

@ -4,27 +4,21 @@ import { GitForkIcon, StarIcon } from "lucide-react";
import PageTitle from "../../components/PageTitle"; import PageTitle from "../../components/PageTitle";
import Link from "../../components/Link"; import Link from "../../components/Link";
import RelativeTime from "../../components/RelativeTime"; import RelativeTime from "../../components/RelativeTime";
import { metadata as defaultMetadata } from "../layout"; import { addMetadata } from "../../lib/helpers/metadata";
import * as config from "../../lib/config"; import * as config from "../../lib/config";
import type { Metadata } from "next";
import type { User, Repository } from "@octokit/graphql-schema"; import type { User, Repository } from "@octokit/graphql-schema";
import styles from "./page.module.css"; import styles from "./page.module.css";
export const revalidate = 600; // 10 minutes export const revalidate = 600; // 10 minutes
export const metadata: Metadata = { export const metadata = addMetadata({
title: "Projects", title: "Projects",
openGraph: { description: `Most-starred repositories by @${config.authorSocial?.github} on GitHub`,
...defaultMetadata.openGraph,
title: "Projects",
url: "/projects",
},
alternates: { alternates: {
...defaultMetadata.alternates,
canonical: "/projects", canonical: "/projects",
}, },
}; });
type Project = { type Project = {
name: string; name: string;

View File

@ -1,19 +1,13 @@
import PageTitle from "../../components/PageTitle"; import PageTitle from "../../components/PageTitle";
import { metadata as defaultMetadata } from "../layout"; import { addMetadata } from "../../lib/helpers/metadata";
export const metadata = { export const metadata = addMetadata({
title: "/uses", title: "/uses",
description: "Things I use daily.", description: "Things I use daily.",
openGraph: {
...defaultMetadata.openGraph,
title: "/uses",
url: "/uses",
},
alternates: { alternates: {
...defaultMetadata.alternates,
canonical: "/uses", canonical: "/uses",
}, },
}; });
<PageTitle canonical="/uses">Uses</PageTitle> <PageTitle canonical="/uses">Uses</PageTitle>

View File

@ -1,23 +1,16 @@
import Link from "../../components/Link"; import Link from "../../components/Link";
import CodeBlock from "../../components/CodeBlock/CodeBlock"; import CodeBlock from "../../components/CodeBlock/CodeBlock";
import { metadata as defaultMetadata } from "../layout"; import { addMetadata } from "../../lib/helpers/metadata";
import type { Metadata } from "next";
import backgroundImg from "./sundar.jpg"; import backgroundImg from "./sundar.jpg";
export const metadata: Metadata = { export const metadata = addMetadata({
title: "fuckyougoogle.zip", title: "fuckyougoogle.zip",
description: "This is a horrible idea.", description: "This is a horrible idea.",
openGraph: {
...defaultMetadata.openGraph,
title: "fuckyougoogle.zip",
url: "/zip",
},
alternates: { alternates: {
...defaultMetadata.alternates,
canonical: "/zip", canonical: "/zip",
}, },
}; });
const Page = () => { const Page = () => {
return ( return (

47
lib/config/metadata.ts Normal file
View File

@ -0,0 +1,47 @@
import * as config from ".";
import { BASE_URL } from "./constants";
import type { Metadata } from "next";
const metadata: Metadata = {
metadataBase: new URL(BASE_URL),
title: {
template: `%s ${config.siteName}`,
default: `${config.siteName} ${config.shortDescription}`,
},
description: config.longDescription,
openGraph: {
siteName: config.siteName,
title: {
template: "%s",
default: `${config.siteName} ${config.shortDescription}`,
},
url: "/",
locale: config.siteLocale?.replace("-", "_"),
type: "website",
},
twitter: {
creator: `@${config.authorSocial?.twitter}`,
},
alternates: {
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",
},
};
export default metadata;

29
lib/helpers/metadata.ts Normal file
View File

@ -0,0 +1,29 @@
import defaultMetadata from "../config/metadata";
import type { Metadata } from "next";
// helper function to deep merge a page's metadata into the default site metadata
export const addMetadata = (metadata: Metadata): Metadata => {
return {
...defaultMetadata,
...metadata,
openGraph: {
...defaultMetadata.openGraph,
title: metadata.title as string,
description: metadata.description as string,
url: metadata.alternates?.canonical as string,
...metadata.openGraph,
},
twitter: {
...defaultMetadata.twitter,
...metadata.twitter,
},
alternates: {
...defaultMetadata.alternates,
...metadata.alternates,
},
other: {
...defaultMetadata.other,
...metadata.other,
},
};
};

View File

@ -22,9 +22,9 @@
"@giscus/react": "^3.1.0", "@giscus/react": "^3.1.0",
"@mdx-js/loader": "^3.1.0", "@mdx-js/loader": "^3.1.0",
"@mdx-js/react": "^3.1.0", "@mdx-js/react": "^3.1.0",
"@next/bundle-analyzer": "15.3.0-canary.8", "@next/bundle-analyzer": "15.3.0-canary.9",
"@next/mdx": "15.3.0-canary.8", "@next/mdx": "15.3.0-canary.9",
"@next/third-parties": "15.3.0-canary.8", "@next/third-parties": "15.3.0-canary.9",
"@octokit/graphql": "^8.2.1", "@octokit/graphql": "^8.2.1",
"@octokit/graphql-schema": "^15.26.0", "@octokit/graphql-schema": "^15.26.0",
"@prisma/client": "^6.5.0", "@prisma/client": "^6.5.0",
@ -36,9 +36,9 @@
"feed": "^4.2.2", "feed": "^4.2.2",
"geist": "^1.3.1", "geist": "^1.3.1",
"html-entities": "^2.5.2", "html-entities": "^2.5.2",
"lucide-react": "0.481.0", "lucide-react": "0.482.0",
"modern-normalize": "^3.0.1", "modern-normalize": "^3.0.1",
"next": "15.3.0-canary.8", "next": "15.3.0-canary.9",
"obj-str": "^1.1.0", "obj-str": "^1.1.0",
"p-map": "^7.0.3", "p-map": "^7.0.3",
"p-memoize": "^7.1.1", "p-memoize": "^7.1.1",
@ -79,7 +79,7 @@
"@types/react-is": "^19.0.0", "@types/react-is": "^19.0.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^9.22.0", "eslint": "^9.22.0",
"eslint-config-next": "15.3.0-canary.8", "eslint-config-next": "15.3.0-canary.9",
"eslint-config-prettier": "^10.1.1", "eslint-config-prettier": "^10.1.1",
"eslint-plugin-css-modules": "^2.12.0", "eslint-plugin-css-modules": "^2.12.0",
"eslint-plugin-import": "^2.31.0", "eslint-plugin-import": "^2.31.0",

148
pnpm-lock.yaml generated
View File

@ -21,14 +21,14 @@ importers:
specifier: ^3.1.0 specifier: ^3.1.0
version: 3.1.0(@types/react@19.0.10)(react@19.0.0) version: 3.1.0(@types/react@19.0.10)(react@19.0.0)
'@next/bundle-analyzer': '@next/bundle-analyzer':
specifier: 15.3.0-canary.8 specifier: 15.3.0-canary.9
version: 15.3.0-canary.8 version: 15.3.0-canary.9
'@next/mdx': '@next/mdx':
specifier: 15.3.0-canary.8 specifier: 15.3.0-canary.9
version: 15.3.0-canary.8(@mdx-js/loader@3.1.0(acorn@8.14.1))(@mdx-js/react@3.1.0(@types/react@19.0.10)(react@19.0.0)) version: 15.3.0-canary.9(@mdx-js/loader@3.1.0(acorn@8.14.1))(@mdx-js/react@3.1.0(@types/react@19.0.10)(react@19.0.0))
'@next/third-parties': '@next/third-parties':
specifier: 15.3.0-canary.8 specifier: 15.3.0-canary.9
version: 15.3.0-canary.8(next@15.3.0-canary.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) version: 15.3.0-canary.9(next@15.3.0-canary.9(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)
'@octokit/graphql': '@octokit/graphql':
specifier: ^8.2.1 specifier: ^8.2.1
version: 8.2.1 version: 8.2.1
@ -58,19 +58,19 @@ importers:
version: 4.2.2 version: 4.2.2
geist: geist:
specifier: ^1.3.1 specifier: ^1.3.1
version: 1.3.1(next@15.3.0-canary.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)) version: 1.3.1(next@15.3.0-canary.9(react-dom@19.0.0(react@19.0.0))(react@19.0.0))
html-entities: html-entities:
specifier: ^2.5.2 specifier: ^2.5.2
version: 2.5.2 version: 2.5.2
lucide-react: lucide-react:
specifier: 0.481.0 specifier: 0.482.0
version: 0.481.0(react@19.0.0) version: 0.482.0(react@19.0.0)
modern-normalize: modern-normalize:
specifier: ^3.0.1 specifier: ^3.0.1
version: 3.0.1 version: 3.0.1
next: next:
specifier: 15.3.0-canary.8 specifier: 15.3.0-canary.9
version: 15.3.0-canary.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) version: 15.3.0-canary.9(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
obj-str: obj-str:
specifier: ^1.1.0 specifier: ^1.1.0
version: 1.1.0 version: 1.1.0
@ -187,8 +187,8 @@ importers:
specifier: ^9.22.0 specifier: ^9.22.0
version: 9.22.0 version: 9.22.0
eslint-config-next: eslint-config-next:
specifier: 15.3.0-canary.8 specifier: 15.3.0-canary.9
version: 15.3.0-canary.8(eslint@9.22.0)(typescript@5.8.2) version: 15.3.0-canary.9(eslint@9.22.0)(typescript@5.8.2)
eslint-config-prettier: eslint-config-prettier:
specifier: ^10.1.1 specifier: ^10.1.1
version: 10.1.1(eslint@9.22.0) version: 10.1.1(eslint@9.22.0)
@ -652,17 +652,17 @@ packages:
'@types/react': '>=16' '@types/react': '>=16'
react: '>=16' react: '>=16'
'@next/bundle-analyzer@15.3.0-canary.8': '@next/bundle-analyzer@15.3.0-canary.9':
resolution: {integrity: sha512-K3PLM+bxciuah4Q/coJQvxEVWhkptKAWous0fjjbajSgNY8h+DqK77ZZZc00u+0EOiLYsTUntoXb8VDNGyChNw==} resolution: {integrity: sha512-smWqfd9XCLQ3QCS14DMhPHS1KEOQrkUwoDzV6rh0t4tPfXn10OdJhKzZbGso0nDdDfOMmqUKNTMNnGc6782SEQ==}
'@next/env@15.3.0-canary.8': '@next/env@15.3.0-canary.9':
resolution: {integrity: sha512-/cGLuOWycBJnskYxETUtVH8XdwfYNiWJ7Db17qnZd76nLDLfulnIKSZ4QiHTm3cm5uWj9HhkXhm1Pkbj2LObuA==} resolution: {integrity: sha512-kvABHn6GmJbyf02wozUzrC4evHdVSmc6FYV8I7Q4g3qZW1x64v6ppi3Hw1KEUzKieC1Car/maGT+r3oRalCg4Q==}
'@next/eslint-plugin-next@15.3.0-canary.8': '@next/eslint-plugin-next@15.3.0-canary.9':
resolution: {integrity: sha512-WIa24zXGlI/8xpAOvWrdiHA9ypj8eTh2KHowNMHoU2u4GC9igV+GOOjghhBx/PhAkYyiXpG2iJ3EFnvf7sBMQA==} resolution: {integrity: sha512-jl7QuMIESjFFOzlKnFt3ssqOQqTVN+ZMjBUPBop09BC7kXcx0DYZRVmDXly8Esl02Pofj6GhmYOpK8z1lQanXQ==}
'@next/mdx@15.3.0-canary.8': '@next/mdx@15.3.0-canary.9':
resolution: {integrity: sha512-VaKbWHy32z72JyCNT5kqDALy253aPlJsavNvRC+Wm8d3diXUdOc+ztou4KGy0iRC8+o6flE9sncy/6bzzBV0VA==} resolution: {integrity: sha512-sfT6OYKkTJF21TmKDdSJQEwYid+6xM2ICiVOOq1fOtVCKyTCb1xAeYfCGILEgmWwZ0C0IWiEyRIMBzRQFlb2og==}
peerDependencies: peerDependencies:
'@mdx-js/loader': '>=0.15.0' '@mdx-js/loader': '>=0.15.0'
'@mdx-js/react': '>=0.15.0' '@mdx-js/react': '>=0.15.0'
@ -672,56 +672,56 @@ packages:
'@mdx-js/react': '@mdx-js/react':
optional: true optional: true
'@next/swc-darwin-arm64@15.3.0-canary.8': '@next/swc-darwin-arm64@15.3.0-canary.9':
resolution: {integrity: sha512-ItDJSApzYkYLKxjXvI2WRYeb8FkCww6/Wou0Tsdunixh5XeUp/UE7cNP88YGgmp3bI3FgDpVYnP+rUsPToJBUg==} resolution: {integrity: sha512-llJnHJGXQGux7sHJ4t0q5HbMnID+M3+s5ghvYBw79uP4QDkH5XVXRC2oQUwTvEPzHXUhWpB/kf6KUpWmOEI8xQ==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@next/swc-darwin-x64@15.3.0-canary.8': '@next/swc-darwin-x64@15.3.0-canary.9':
resolution: {integrity: sha512-kh55C9939RM0unsZ7700LlHeqUNwnv2Vmd8iz40HQ+G8aaS/Dkd5M7kdzMXkGcY3D79TFL1dxGSL6s1te5R4dg==} resolution: {integrity: sha512-igGqAeBB/3tJ4XLqbdcuzbgwgdNh9kRp2AFSME/Ok4jyetSPmcQFX43+C6piuMj2gQ06Q6gDWj3qib0MNf5IWw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@next/swc-linux-arm64-gnu@15.3.0-canary.8': '@next/swc-linux-arm64-gnu@15.3.0-canary.9':
resolution: {integrity: sha512-YVyuFoF0GAssBsCTnv1w4rJCxPApVe3UQyNRBjrTL/szRm5kZc6lPz+bBTc/QfgsOZz7iGV/6z4CuR8L+NSm0w==} resolution: {integrity: sha512-Ym9FxqbBmQyUjoe2bW7MsDkrYV3sSR8WXCEqJQthETjAqSsG6zwUfL86dMAKe2RUetqlNzWlXDH/+FM9fdPVOw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@next/swc-linux-arm64-musl@15.3.0-canary.8': '@next/swc-linux-arm64-musl@15.3.0-canary.9':
resolution: {integrity: sha512-YMZxUsvNz7LtVd8q9pXlp+AJoN73lvycUMLB+Or2Zc207KvnPxIspkmeOj4AiiNC6q5AIxc0W3YxWH7NmFvJJg==} resolution: {integrity: sha512-aB9umTo1HHcQWRTXffWSrt6wTMvhg+fYbtZ8PR7h28gBrQaYL6Lu8Kg7BQynYEx8Ze42GqVcS0MlwVsTQrpwMw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@next/swc-linux-x64-gnu@15.3.0-canary.8': '@next/swc-linux-x64-gnu@15.3.0-canary.9':
resolution: {integrity: sha512-Cbij+lmUlqj0FSv64jAU5j8iTAGSb2BAfXpE0Crz8pymddlny1h+mYJtiYo3fOACQPqQnExBXyzXRY5RveiH7Q==} resolution: {integrity: sha512-d+tU/H5SaPAuHcxGJ9fiqt0qzXpkOmksu1lF9JQNHd6WKtBnnJMzpYL8onLLYXThrIPaETVSLpBiv1wvwIgwFg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@next/swc-linux-x64-musl@15.3.0-canary.8': '@next/swc-linux-x64-musl@15.3.0-canary.9':
resolution: {integrity: sha512-zJyaG6tiYFHhLsge8MULXwOhaWqAj2OLWSL7yjWGLMSm+c5n06S4tfppQiY4E/4fJiqtpo7Ty9s7AjG3TbTWSw==} resolution: {integrity: sha512-b+V+36WIopplWQI2/xOIqzuRGCRGTDLVe2luhhtjcwewRqUujktGnphHW5zRcEVD9nNwwPCisxC01XLL3geggg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@next/swc-win32-arm64-msvc@15.3.0-canary.8': '@next/swc-win32-arm64-msvc@15.3.0-canary.9':
resolution: {integrity: sha512-qhV+9EkjyRlxvS54aC1e+wDqe2JgP2vXCo00VkyVPJqiVXIvpSIR/7DXg7bDuSvxr7t1sufm7P7v4jhUWTmg1w==} resolution: {integrity: sha512-6YbKTAP1Z+dnFtEoPQc4NuQ9J3VIN0vc8gHmZHBl5qfBQgF9f4DfBwcTrXMXEKIFVkQN4YMZU83v+2DSzT+7FQ==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@next/swc-win32-x64-msvc@15.3.0-canary.8': '@next/swc-win32-x64-msvc@15.3.0-canary.9':
resolution: {integrity: sha512-3lE7Qz7XmAswjJ+WczXsiLjdQ9TpXNX9yJ33cEAsaCBP6+5dsmYeyviguvKDza1VbmQXlxRHqSeZvMFr9jXrBQ==} resolution: {integrity: sha512-Ujf4+i1memQV3Qk0EjY00C4bzumV6jOZze9kCdi4PnpPjzEefTj88CFGR7ACmYgu1qDHOKaZQxR08MALy/yvIw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@next/third-parties@15.3.0-canary.8': '@next/third-parties@15.3.0-canary.9':
resolution: {integrity: sha512-ELJ6bR4AFgsDboH0pC856jauB16U+574uGM6r2JsQz2IM/iI+d3TJvUa6C942sbGNsbnPd4eo5ycORZZV0PS7Q==} resolution: {integrity: sha512-6Sy5adFXNpsYfOwVzS7p79bcETqvsh6Hewv3GhmwF/4MZtcWygt6mi04IUYGoVZbTlF1TkEPGSfBy9EqqDX8mw==}
peerDependencies: peerDependencies:
next: ^13.0.0 || ^14.0.0 || ^15.0.0 next: ^13.0.0 || ^14.0.0 || ^15.0.0
react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
@ -1479,8 +1479,8 @@ packages:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'} engines: {node: '>=12'}
eslint-config-next@15.3.0-canary.8: eslint-config-next@15.3.0-canary.9:
resolution: {integrity: sha512-3kcG6U4jii1+Vur5XQbUUYZrDHa4pvHa0Me2GdWAa2JhevJuNOzIVmWLHrKlPtULBbVmxWjX09wUesQIkoYb4Q==} resolution: {integrity: sha512-haW90iIvkZ70hVf8joY98NoQYl2bpixl0IXeSlWjniPR9cgvlq2U4BpNxb1nDO2n/iuy+kwig0dsEcqH1/7XLw==}
peerDependencies: peerDependencies:
eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 eslint: ^7.23.0 || ^8.0.0 || ^9.0.0
typescript: '>=3.3.1' typescript: '>=3.3.1'
@ -2308,8 +2308,8 @@ packages:
lru-cache@10.4.3: lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
lucide-react@0.481.0: lucide-react@0.482.0:
resolution: {integrity: sha512-NrvUDNFwgLIvHiwTEq9boa5Kiz1KdUT8RJ+wmNijwxdn9U737Fw42c43sRxJTMqhL+ySHpGRVCWpwiF+abrEjw==} resolution: {integrity: sha512-XM8PzHzSrg8ATmmO+fzf+JyYlVVdQnJjuyLDj2p4V2zEtcKeBNAqAoJIGFv1x2HSBa7kT8gpYUxwdQ0g7nypfw==}
peerDependencies: peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
@ -2550,8 +2550,8 @@ packages:
natural-compare@1.4.0: natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
next@15.3.0-canary.8: next@15.3.0-canary.9:
resolution: {integrity: sha512-RuXoaWX13+VhfK0lD/r8XqcyZFpyER4/KaomW/wZYaEyoiHVEFH6ndpD6m4b9+a60w1bua3CoRn2Ih1419FZ8Q==} resolution: {integrity: sha512-R9+FanTpLPN4cez/lJurj/kedcOERPCQebl/F5kevPSzCQzp8Dj/LCv6L10wTqBH3zBgqepp0eytzsVrjW8VjA==}
engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -3916,53 +3916,53 @@ snapshots:
'@types/react': 19.0.10 '@types/react': 19.0.10
react: 19.0.0 react: 19.0.0
'@next/bundle-analyzer@15.3.0-canary.8': '@next/bundle-analyzer@15.3.0-canary.9':
dependencies: dependencies:
webpack-bundle-analyzer: 4.10.1 webpack-bundle-analyzer: 4.10.1
transitivePeerDependencies: transitivePeerDependencies:
- bufferutil - bufferutil
- utf-8-validate - utf-8-validate
'@next/env@15.3.0-canary.8': {} '@next/env@15.3.0-canary.9': {}
'@next/eslint-plugin-next@15.3.0-canary.8': '@next/eslint-plugin-next@15.3.0-canary.9':
dependencies: dependencies:
fast-glob: 3.3.1 fast-glob: 3.3.1
'@next/mdx@15.3.0-canary.8(@mdx-js/loader@3.1.0(acorn@8.14.1))(@mdx-js/react@3.1.0(@types/react@19.0.10)(react@19.0.0))': '@next/mdx@15.3.0-canary.9(@mdx-js/loader@3.1.0(acorn@8.14.1))(@mdx-js/react@3.1.0(@types/react@19.0.10)(react@19.0.0))':
dependencies: dependencies:
source-map: 0.7.4 source-map: 0.7.4
optionalDependencies: optionalDependencies:
'@mdx-js/loader': 3.1.0(acorn@8.14.1) '@mdx-js/loader': 3.1.0(acorn@8.14.1)
'@mdx-js/react': 3.1.0(@types/react@19.0.10)(react@19.0.0) '@mdx-js/react': 3.1.0(@types/react@19.0.10)(react@19.0.0)
'@next/swc-darwin-arm64@15.3.0-canary.8': '@next/swc-darwin-arm64@15.3.0-canary.9':
optional: true optional: true
'@next/swc-darwin-x64@15.3.0-canary.8': '@next/swc-darwin-x64@15.3.0-canary.9':
optional: true optional: true
'@next/swc-linux-arm64-gnu@15.3.0-canary.8': '@next/swc-linux-arm64-gnu@15.3.0-canary.9':
optional: true optional: true
'@next/swc-linux-arm64-musl@15.3.0-canary.8': '@next/swc-linux-arm64-musl@15.3.0-canary.9':
optional: true optional: true
'@next/swc-linux-x64-gnu@15.3.0-canary.8': '@next/swc-linux-x64-gnu@15.3.0-canary.9':
optional: true optional: true
'@next/swc-linux-x64-musl@15.3.0-canary.8': '@next/swc-linux-x64-musl@15.3.0-canary.9':
optional: true optional: true
'@next/swc-win32-arm64-msvc@15.3.0-canary.8': '@next/swc-win32-arm64-msvc@15.3.0-canary.9':
optional: true optional: true
'@next/swc-win32-x64-msvc@15.3.0-canary.8': '@next/swc-win32-x64-msvc@15.3.0-canary.9':
optional: true optional: true
'@next/third-parties@15.3.0-canary.8(next@15.3.0-canary.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)': '@next/third-parties@15.3.0-canary.9(next@15.3.0-canary.9(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)':
dependencies: dependencies:
next: 15.3.0-canary.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) next: 15.3.0-canary.9(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react: 19.0.0 react: 19.0.0
third-party-capital: 1.0.20 third-party-capital: 1.0.20
@ -4864,9 +4864,9 @@ snapshots:
escape-string-regexp@5.0.0: {} escape-string-regexp@5.0.0: {}
eslint-config-next@15.3.0-canary.8(eslint@9.22.0)(typescript@5.8.2): eslint-config-next@15.3.0-canary.9(eslint@9.22.0)(typescript@5.8.2):
dependencies: dependencies:
'@next/eslint-plugin-next': 15.3.0-canary.8 '@next/eslint-plugin-next': 15.3.0-canary.9
'@rushstack/eslint-patch': 1.11.0 '@rushstack/eslint-patch': 1.11.0
'@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(typescript@5.8.2) '@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(typescript@5.8.2)
'@typescript-eslint/parser': 8.26.1(eslint@9.22.0)(typescript@5.8.2) '@typescript-eslint/parser': 8.26.1(eslint@9.22.0)(typescript@5.8.2)
@ -5273,9 +5273,9 @@ snapshots:
functions-have-names@1.2.3: {} functions-have-names@1.2.3: {}
geist@1.3.1(next@15.3.0-canary.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)): geist@1.3.1(next@15.3.0-canary.9(react-dom@19.0.0(react@19.0.0))(react@19.0.0)):
dependencies: dependencies:
next: 15.3.0-canary.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) next: 15.3.0-canary.9(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
get-east-asian-width@1.3.0: {} get-east-asian-width@1.3.0: {}
@ -5911,7 +5911,7 @@ snapshots:
lru-cache@10.4.3: {} lru-cache@10.4.3: {}
lucide-react@0.481.0(react@19.0.0): lucide-react@0.482.0(react@19.0.0):
dependencies: dependencies:
react: 19.0.0 react: 19.0.0
@ -6400,9 +6400,9 @@ snapshots:
natural-compare@1.4.0: {} natural-compare@1.4.0: {}
next@15.3.0-canary.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0): next@15.3.0-canary.9(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies: dependencies:
'@next/env': 15.3.0-canary.8 '@next/env': 15.3.0-canary.9
'@swc/counter': 0.1.3 '@swc/counter': 0.1.3
'@swc/helpers': 0.5.15 '@swc/helpers': 0.5.15
busboy: 1.6.0 busboy: 1.6.0
@ -6412,14 +6412,14 @@ snapshots:
react-dom: 19.0.0(react@19.0.0) react-dom: 19.0.0(react@19.0.0)
styled-jsx: 5.1.6(react@19.0.0) styled-jsx: 5.1.6(react@19.0.0)
optionalDependencies: optionalDependencies:
'@next/swc-darwin-arm64': 15.3.0-canary.8 '@next/swc-darwin-arm64': 15.3.0-canary.9
'@next/swc-darwin-x64': 15.3.0-canary.8 '@next/swc-darwin-x64': 15.3.0-canary.9
'@next/swc-linux-arm64-gnu': 15.3.0-canary.8 '@next/swc-linux-arm64-gnu': 15.3.0-canary.9
'@next/swc-linux-arm64-musl': 15.3.0-canary.8 '@next/swc-linux-arm64-musl': 15.3.0-canary.9
'@next/swc-linux-x64-gnu': 15.3.0-canary.8 '@next/swc-linux-x64-gnu': 15.3.0-canary.9
'@next/swc-linux-x64-musl': 15.3.0-canary.8 '@next/swc-linux-x64-musl': 15.3.0-canary.9
'@next/swc-win32-arm64-msvc': 15.3.0-canary.8 '@next/swc-win32-arm64-msvc': 15.3.0-canary.9
'@next/swc-win32-x64-msvc': 15.3.0-canary.8 '@next/swc-win32-x64-msvc': 15.3.0-canary.9
sharp: 0.33.5 sharp: 0.33.5
transitivePeerDependencies: transitivePeerDependencies:
- '@babel/core' - '@babel/core'