diff --git a/apps/web/app/.gitignore b/apps/web/app/.gitignore index 4e4766d..5dccd89 100644 --- a/apps/web/app/.gitignore +++ b/apps/web/app/.gitignore @@ -1,3 +1,4 @@ # clerk configuration (can include secrets) /.clerk/ +.vercel diff --git a/apps/web/app/app/(auth)/sign-in/[[...sign-in]]/page.tsx b/apps/web/app/app/(auth)/sign-in/[[...sign-in]]/page.tsx index 9009fb5..b56e4e7 100644 --- a/apps/web/app/app/(auth)/sign-in/[[...sign-in]]/page.tsx +++ b/apps/web/app/app/(auth)/sign-in/[[...sign-in]]/page.tsx @@ -1,8 +1,10 @@ import { SignIn } from "@clerk/nextjs"; +import { createMetadata } from "@workspace/seo/metadata"; -export const metadata = { - title: "Sign In | Qurious", -}; +export const metadata = createMetadata({ + title: "Sign In", + description: "Sign in to your Qurious account", +}); export default function SignInPage() { return ; diff --git a/apps/web/app/app/(auth)/sign-up/[[...sign-up]]/page.tsx b/apps/web/app/app/(auth)/sign-up/[[...sign-up]]/page.tsx index f807462..25bdb1e 100644 --- a/apps/web/app/app/(auth)/sign-up/[[...sign-up]]/page.tsx +++ b/apps/web/app/app/(auth)/sign-up/[[...sign-up]]/page.tsx @@ -1,8 +1,10 @@ import { SignUp } from "@clerk/nextjs"; +import { createMetadata } from "@workspace/seo/metadata"; -export const metadata = { - title: "Sign Up | Qurious", -}; +export const metadata = createMetadata({ + title: "Sign Up", + description: "Create a new Qurious account", +}); export default function SignUpPage() { return ; diff --git a/apps/web/app/app/(user)/folders/[id]/layout.tsx b/apps/web/app/app/(user)/folders/[id]/layout.tsx index 829fa02..72659df 100644 --- a/apps/web/app/app/(user)/folders/[id]/layout.tsx +++ b/apps/web/app/app/(user)/folders/[id]/layout.tsx @@ -1,6 +1,7 @@ import { fetchQuery } from "convex/nextjs"; import { api } from "@workspace/backend/_generated/api"; import { Id } from "@workspace/backend/_generated/dataModel"; +import { createMetadata } from "@workspace/seo/metadata"; import { FolderLayoutClient } from "./client"; type Props = { @@ -19,11 +20,15 @@ export async function generateMetadata({ folderId: id as Id<"folders">, }); - return { - title: `${folder.name} | Folder | Qurious`, - }; + return createMetadata({ + title: `${folder.name} | Folder`, + description: `View and manage papers and searches in the ${folder.name} folder`, + }); } catch { - return { title: "Folder | Qurious" }; + return createMetadata({ + title: "Folder", + description: "View and manage papers and searches in this folder", + }); } } diff --git a/apps/web/app/app/(user)/folders/page.tsx b/apps/web/app/app/(user)/folders/page.tsx index ca8a4e4..fb6d68d 100644 --- a/apps/web/app/app/(user)/folders/page.tsx +++ b/apps/web/app/app/(user)/folders/page.tsx @@ -1,9 +1,10 @@ import { FolderClient } from "./client"; +import { createMetadata } from "@workspace/seo/metadata"; -export const metadata = { - title: "Folders | Qurious", +export const metadata = createMetadata({ + title: "Folders", description: "Manage your folders and organize your papers", -}; +}); export default function FoldersPage() { return ; diff --git a/apps/web/app/app/(user)/papers/[id]/layout.tsx b/apps/web/app/app/(user)/papers/[id]/layout.tsx index 2b5fcfb..5585fde 100644 --- a/apps/web/app/app/(user)/papers/[id]/layout.tsx +++ b/apps/web/app/app/(user)/papers/[id]/layout.tsx @@ -1,5 +1,6 @@ import { api } from "@workspace/backend/_generated/api"; import { fetchAction } from "convex/nextjs"; +import { createMetadata } from "@workspace/seo/metadata"; import { PaperLayoutClient } from "./client"; type Props = { @@ -36,11 +37,16 @@ export async function generateMetadata({ }, ); - return { - title: `${paper.title} | Paper | Qurious`, - }; + return createMetadata({ + title: `${paper.title} | Paper`, + description: + paper.tldr?.text || paper.abstract || "View paper details on Qurious", + }); } catch { - return { title: "Paper | Qurious" }; + return createMetadata({ + title: "Paper", + description: "View paper details on Qurious", + }); } } diff --git a/apps/web/app/app/(user)/search/page.tsx b/apps/web/app/app/(user)/search/page.tsx index ebb6baa..9af07e4 100644 --- a/apps/web/app/app/(user)/search/page.tsx +++ b/apps/web/app/app/(user)/search/page.tsx @@ -5,6 +5,7 @@ import { fieldsOfStudy, publicationTypes, } from "@workspace/semantic-scholar/src/index"; +import { createMetadata } from "@workspace/seo/metadata"; import { SearchResults } from "./client"; @@ -33,9 +34,12 @@ export async function generateMetadata(props: Props) { const searchParams = await props.searchParams; const { q } = searchParamsSchema.parse(searchParams); - return { - title: q ? `${q} | Search | Qurious` : "Search | Qurious", - }; + return createMetadata({ + title: q ? `${q} | Search` : "Search", + description: q + ? `Search results for "${q}" on Qurious` + : "Search for research papers and academic content", + }); } export default async function SearchPage(props: Props) { diff --git a/apps/web/app/app/(user)/settings/account/[[...account]]/page.tsx b/apps/web/app/app/(user)/settings/account/[[...account]]/page.tsx index 72b58f9..90674fe 100644 --- a/apps/web/app/app/(user)/settings/account/[[...account]]/page.tsx +++ b/apps/web/app/app/(user)/settings/account/[[...account]]/page.tsx @@ -9,10 +9,12 @@ import { CardHeader, CardTitle, } from "@workspace/design-system/components/card"; +import { createMetadata } from "@workspace/seo/metadata"; -export const metadata = { - title: "Account Settings | Qurious", -}; +export const metadata = createMetadata({ + title: "Account Settings", + description: "Manage your account profile and authentication settings", +}); export default function AccountSettingsPage() { return ( diff --git a/apps/web/app/app/(user)/settings/credits/page.tsx b/apps/web/app/app/(user)/settings/credits/page.tsx index 2a88a88..18c230f 100644 --- a/apps/web/app/app/(user)/settings/credits/page.tsx +++ b/apps/web/app/app/(user)/settings/credits/page.tsx @@ -1,10 +1,12 @@ import { Heading } from "@/components/global-heading"; import { CreditsClient } from "./client"; import { CreditCard } from "@workspace/design-system/icons"; +import { createMetadata } from "@workspace/seo/metadata"; -export const metadata = { - title: "Credits | Qurious", -}; +export const metadata = createMetadata({ + title: "Credits", + description: "Manage your credits and billing preferences", +}); export default function CreditsSettingsPage() { return ( diff --git a/apps/web/app/app/(user)/settings/customization/page.tsx b/apps/web/app/app/(user)/settings/customization/page.tsx index 6b0ddd2..e725787 100644 --- a/apps/web/app/app/(user)/settings/customization/page.tsx +++ b/apps/web/app/app/(user)/settings/customization/page.tsx @@ -1,10 +1,12 @@ import { Heading } from "@/components/global-heading"; import { ContentSettingsBox } from "./client"; import { Palette } from "@workspace/design-system/icons"; +import { createMetadata } from "@workspace/seo/metadata"; -export const metadata = { - title: "Customization Settings | Qurious", -}; +export const metadata = createMetadata({ + title: "Customization Settings", + description: "Customize your AI preferences and appearance", +}); export default function CustomizationSettingsPage() { return ( diff --git a/apps/web/app/app/(user)/settings/keys/page.tsx b/apps/web/app/app/(user)/settings/keys/page.tsx index b0620b0..15cf67b 100644 --- a/apps/web/app/app/(user)/settings/keys/page.tsx +++ b/apps/web/app/app/(user)/settings/keys/page.tsx @@ -7,10 +7,12 @@ import { CardHeader, CardTitle, } from "@workspace/design-system/components/card"; +import { createMetadata } from "@workspace/seo/metadata"; -export const metadata = { - title: "API Keys | Qurious", -}; +export const metadata = createMetadata({ + title: "API Keys", + description: "Manage your API keys for external integrations", +}); export default function KeysSettingsPage() { return ( diff --git a/apps/web/app/app/(user)/settings/webhooks/page.tsx b/apps/web/app/app/(user)/settings/webhooks/page.tsx index bed1bc7..54fd406 100644 --- a/apps/web/app/app/(user)/settings/webhooks/page.tsx +++ b/apps/web/app/app/(user)/settings/webhooks/page.tsx @@ -7,10 +7,12 @@ import { CardHeader, CardTitle, } from "@workspace/design-system/components/card"; +import { createMetadata } from "@workspace/seo/metadata"; -export const metadata = { - title: "Webhooks | Qurious", -}; +export const metadata = createMetadata({ + title: "Webhooks", + description: "Configure webhooks for real-time notifications", +}); export default function WebhooksSettingsPage() { return ( diff --git a/apps/web/app/app/icon.svg b/apps/web/app/app/icon.svg deleted file mode 100644 index 3f2531a..0000000 --- a/apps/web/app/app/icon.svg +++ /dev/null @@ -1 +0,0 @@ -
Q
\ No newline at end of file diff --git a/apps/web/app/app/layout.tsx b/apps/web/app/app/layout.tsx index 6efbc9d..dd61b2e 100644 --- a/apps/web/app/app/layout.tsx +++ b/apps/web/app/app/layout.tsx @@ -1,5 +1,4 @@ import "@workspace/design-system/styles/globals.css"; -import type { Metadata } from "next"; import { GeistSans, GeistMono } from "@workspace/design-system/font"; // Providers @@ -10,13 +9,14 @@ import { FontProvider } from "@workspace/design-system/providers/font-provider"; import { PostHogProvider } from "@/providers/posthog-provider"; import { APP_DESCRIPTION, APP_NAME } from "@workspace/design-system/content"; +import { createMetadata } from "@workspace/seo/metadata"; import { Analytics } from "@vercel/analytics/next"; -export const metadata: Metadata = { - title: APP_NAME, +export const metadata = createMetadata({ + title: "Home", description: APP_DESCRIPTION, -}; +}); export default function RootLayout({ children, diff --git a/apps/web/app/package.json b/apps/web/app/package.json index 8e1e084..da1c0a4 100644 --- a/apps/web/app/package.json +++ b/apps/web/app/package.json @@ -28,6 +28,7 @@ "@workspace/backend": "workspace:*", "@workspace/design-system": "workspace:*", "@workspace/semantic-scholar": "workspace:*", + "@workspace/seo": "workspace:*", "ai": "^6.0.68", "convex": "^1.31.7", "d3": "^7.9.0", diff --git a/apps/web/blog/app/(home)/blog/[slug]/page.tsx b/apps/web/blog/app/(home)/blog/[slug]/page.tsx index 85a9871..8450d2c 100644 --- a/apps/web/blog/app/(home)/blog/[slug]/page.tsx +++ b/apps/web/blog/app/(home)/blog/[slug]/page.tsx @@ -1,20 +1,21 @@ -import { notFound } from 'next/navigation'; -import Link from 'next/link'; -import { InlineTOC } from 'fumadocs-ui/components/inline-toc'; -import defaultMdxComponents from 'fumadocs-ui/mdx'; -import { blog } from '@/lib/source'; +import { notFound } from "next/navigation"; +import Link from "next/link"; +import { InlineTOC } from "fumadocs-ui/components/inline-toc"; +import defaultMdxComponents from "fumadocs-ui/mdx"; +import { blog } from "@/lib/source"; +import { createMetadata } from "@workspace/seo/metadata"; export async function generateMetadata(props: { - params: Promise<{ slug: string }>; - }) { - const params = await props.params; - const page = blog.getPage([params.slug]); - if (!page) notFound(); - return { - title: page.data.title, - description: page.data.description, - }; - } + params: Promise<{ slug: string }>; +}) { + const params = await props.params; + const page = blog.getPage([params.slug]); + if (!page) notFound(); + return createMetadata({ + title: page.data.title, + description: page.data.description || "Blog post", + }); +} export default async function Page(props: { params: Promise<{ slug: string }>; @@ -58,4 +59,4 @@ export function generateStaticParams(): { slug: string }[] { return blog.getPages().map((page) => ({ slug: page.slugs[0], })); -} \ No newline at end of file +} diff --git a/apps/web/help/app/(docs)/[[...slug]]/page.tsx b/apps/web/help/app/(docs)/[[...slug]]/page.tsx index 3cb6d70..64b508d 100644 --- a/apps/web/help/app/(docs)/[[...slug]]/page.tsx +++ b/apps/web/help/app/(docs)/[[...slug]]/page.tsx @@ -1,13 +1,14 @@ -import { source } from '@/lib/source'; +import { source } from "@/lib/source"; import { DocsPage, DocsBody, DocsDescription, DocsTitle, -} from 'fumadocs-ui/page'; -import { notFound } from 'next/navigation'; -import { createRelativeLink } from 'fumadocs-ui/mdx'; -import { getMDXComponents } from '@/mdx-components'; +} from "fumadocs-ui/page"; +import { notFound } from "next/navigation"; +import { createRelativeLink } from "fumadocs-ui/mdx"; +import { getMDXComponents } from "@/mdx-components"; +import { createMetadata } from "@workspace/seo/metadata"; export default async function Page(props: { params: Promise<{ slug?: string[] }>; @@ -45,8 +46,8 @@ export async function generateMetadata(props: { const page = source.getPage(params.slug); if (!page) notFound(); - return { + return createMetadata({ title: page.data.title, - description: page.data.description, - }; + description: page.data.description || "Documentation", + }); } diff --git a/apps/web/www/app/(legal)/privacy/page.tsx b/apps/web/www/app/(legal)/privacy/page.tsx index 9e11851..cd74118 100644 --- a/apps/web/www/app/(legal)/privacy/page.tsx +++ b/apps/web/www/app/(legal)/privacy/page.tsx @@ -1,11 +1,11 @@ -import type { Metadata } from "next"; import Link from "next/link"; import { APP_NAME, LEGAL_CONFIG } from "@workspace/design-system/content"; +import { createMetadata } from "@workspace/seo/metadata"; -export const metadata: Metadata = { - title: `Privacy Policy | ${APP_NAME}`, +export const metadata = createMetadata({ + title: "Privacy Policy", description: `Privacy Policy for ${APP_NAME} - Learn how we collect, use, and protect your data.`, -}; +}); export default function PrivacyPage() { return ( diff --git a/apps/web/www/app/(legal)/terms/page.tsx b/apps/web/www/app/(legal)/terms/page.tsx index c5e671a..c3822c1 100644 --- a/apps/web/www/app/(legal)/terms/page.tsx +++ b/apps/web/www/app/(legal)/terms/page.tsx @@ -1,11 +1,11 @@ -import type { Metadata } from "next"; import Link from "next/link"; import { APP_NAME, LEGAL_CONFIG } from "@workspace/design-system/content"; +import { createMetadata } from "@workspace/seo/metadata"; -export const metadata: Metadata = { - title: `Terms of Service | ${APP_NAME}`, +export const metadata = createMetadata({ + title: "Terms of Service", description: `Terms of Service for ${APP_NAME} - A research tool for the AI age.`, -}; +}); export default function TermsPage() { return ( diff --git a/apps/web/www/app/layout.tsx b/apps/web/www/app/layout.tsx index 233999c..f1fe4b5 100644 --- a/apps/web/www/app/layout.tsx +++ b/apps/web/www/app/layout.tsx @@ -1,4 +1,3 @@ -import type { Metadata } from "next"; import type { ReactNode } from "react"; import "@workspace/design-system/styles/globals.css"; @@ -10,11 +9,12 @@ import { ThemeProvider } from "@workspace/design-system/providers/theme-provider import { APP_DESCRIPTION, APP_NAME } from "@workspace/design-system/content"; import { Separator } from "@workspace/design-system/components/separator"; import { Footer } from "@/components/footer"; +import { createMetadata } from "@workspace/seo/metadata"; -export const metadata: Metadata = { +export const metadata = createMetadata({ title: APP_NAME, description: APP_DESCRIPTION, -}; +}); const BackgroundGridsAndBlob = () => { return ( diff --git a/apps/web/www/package.json b/apps/web/www/package.json index 7981af4..d720a22 100644 --- a/apps/web/www/package.json +++ b/apps/web/www/package.json @@ -11,6 +11,8 @@ "dependencies": { "@t3-oss/env-nextjs": "^0.13.8", "@workspace/design-system": "workspace:*", + "@workspace/seo": "workspace:*", + "motion": "^12.34.0", "next": "15.5.4", "next-themes": "^0.4.6", "react": "^19.0.0", diff --git a/apps/web/www/public/image.png b/apps/web/www/public/image.png new file mode 100644 index 0000000..286ec83 Binary files /dev/null and b/apps/web/www/public/image.png differ diff --git a/apps/web/www/public/logo.svg b/apps/web/www/public/logo.svg new file mode 100644 index 0000000..5344d01 --- /dev/null +++ b/apps/web/www/public/logo.svg @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/cspell.json b/cspell.json index 11bc46a..807736e 100644 --- a/cspell.json +++ b/cspell.json @@ -82,7 +82,9 @@ "worklets", "zod", "zotero", - "samhoque" + "samhoque", + "Sahil", + "sahillll" ], "ignorePaths": [ "**/*.map", diff --git a/packages/seo/metadata.ts b/packages/seo/metadata.ts new file mode 100644 index 0000000..4d13d94 --- /dev/null +++ b/packages/seo/metadata.ts @@ -0,0 +1,91 @@ +import type { Metadata } from "next"; + +type MetadataGenerator = Omit & { + title: string; + description: string; + image?: string; +}; + +const applicationName = "Qurious"; +const author: Metadata["authors"] = { + name: "Sahil Khan", + url: "https://sahilll.dev/", +}; +const publisher = "Sahil Khan"; +const twitterHandle = "@sahillll_khan"; + +const metadataBase = new URL(`https://quriousai.xyz`); + +export const createMetadata = ({ + title, + description, + image = "https://quriousai.xyz/image.png", + ...properties +}: MetadataGenerator): Metadata => { + const parsedTitle = `${title} | ${applicationName}`; + const defaultMetadata: Metadata = { + title: parsedTitle, + description, + applicationName, + icons: "https://quriousai.xyz/logo.svg", + metadataBase, + authors: [author], + creator: author.name, + keywords: [ + "Qurious", + "AI research tool", + "AI research assistant", + "research paper search engine", + "scientific paper search", + "academic research platform", + "AI literature review tool", + "Semantic Scholar alternative", + "Google Scholar alternative", + "Consensus alternative", + "chat with research papers", + "AI paper analysis", + "summarize scientific papers", + "research workflow tool", + "organize research papers", + "AI academic assistant", + ], + formatDetection: { + telephone: false, + }, + appleWebApp: { + capable: true, + statusBarStyle: "default", + title: parsedTitle, + }, + openGraph: { + title: parsedTitle, + description, + type: "website", + siteName: applicationName, + locale: "en_US", + }, + publisher, + twitter: { + card: "summary_large_image", + creator: twitterHandle, + }, + }; + + const metadata: Metadata = { ...defaultMetadata, ...properties }; + + if (image && metadata.openGraph) { + metadata.openGraph.images = [ + { + url: image, + width: 1200, + height: 630, + alt: title, + }, + ]; + if (metadata.twitter) { + metadata.twitter.images = [image]; + } + } + + return metadata; +}; diff --git a/packages/seo/package.json b/packages/seo/package.json new file mode 100644 index 0000000..58a2256 --- /dev/null +++ b/packages/seo/package.json @@ -0,0 +1,7 @@ +{ + "name": "@workspace/seo", + "packageManager": "pnpm@10.18.2", + "dependencies": { + "next": "^16.1.6" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 440db6e..a36ace8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -246,6 +246,9 @@ importers: '@workspace/semantic-scholar': specifier: workspace:* version: link:../../../packages/semantic-scholar + '@workspace/seo': + specifier: workspace:* + version: link:../../../packages/seo ai: specifier: ^6.0.68 version: 6.0.68(zod@3.25.76) @@ -532,6 +535,12 @@ importers: '@workspace/design-system': specifier: workspace:* version: link:../../../packages/design-system + '@workspace/seo': + specifier: workspace:* + version: link:../../../packages/seo + motion: + specifier: ^12.34.0 + version: 12.34.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) next: specifier: 15.5.4 version: 15.5.4(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -653,7 +662,7 @@ importers: version: 13.8.0(react@19.2.3) '@next/font': specifier: ^14.2.15 - version: 14.2.15(next@15.5.9(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) + version: 14.2.15(next@16.1.6(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) '@radix-ui/react-avatar': specifier: ^1.1.10 version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.9))(@types/react@19.2.9)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -707,7 +716,7 @@ importers: version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.9))(@types/react@19.2.9)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) geist: specifier: ^1.4.2 - version: 1.5.1(next@15.5.9(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) + version: 1.5.1(next@16.1.6(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) lucide-react: specifier: ^0.511.0 version: 0.511.0(react@19.2.3) @@ -806,6 +815,12 @@ importers: specifier: ^8.2.0 version: 8.2.0 + packages/seo: + dependencies: + next: + specifier: ^16.1.6 + version: 16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + tools/eslint: devDependencies: '@eslint/js': @@ -2984,6 +2999,9 @@ packages: '@next/env@15.5.9': resolution: {integrity: sha512-4GlTZ+EJM7WaW2HEZcyU317tIQDjkQIyENDLxYJfSWlfqguN+dHkZgyQTV/7ykvobU7yEH5gKvreNrH4B6QgIg==} + '@next/env@16.1.6': + resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==} + '@next/eslint-plugin-next@15.3.3': resolution: {integrity: sha512-VKZJEiEdpKkfBmcokGjHu0vGDG+8CehGs90tBEy/IDoDDKGngeyIStt2MmE5FYNyU9BhgR7tybNWTAJY/30u+Q==} @@ -3007,6 +3025,12 @@ packages: cpu: [arm64] os: [darwin] + '@next/swc-darwin-arm64@16.1.6': + resolution: {integrity: sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + '@next/swc-darwin-x64@15.5.4': resolution: {integrity: sha512-QOTCFq8b09ghfjRJKfb68kU9k2K+2wsC4A67psOiMn849K9ZXgCSRQr0oVHfmKnoqCbEmQWG1f2h1T2vtJJ9mA==} engines: {node: '>= 10'} @@ -3019,6 +3043,12 @@ packages: cpu: [x64] os: [darwin] + '@next/swc-darwin-x64@16.1.6': + resolution: {integrity: sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + '@next/swc-linux-arm64-gnu@15.5.4': resolution: {integrity: sha512-eRD5zkts6jS3VfE/J0Kt1VxdFqTnMc3QgO5lFE5GKN3KDI/uUpSyK3CjQHmfEkYR4wCOl0R0XrsjpxfWEA++XA==} engines: {node: '>= 10'} @@ -3031,6 +3061,12 @@ packages: cpu: [arm64] os: [linux] + '@next/swc-linux-arm64-gnu@16.1.6': + resolution: {integrity: sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + '@next/swc-linux-arm64-musl@15.5.4': resolution: {integrity: sha512-TOK7iTxmXFc45UrtKqWdZ1shfxuL4tnVAOuuJK4S88rX3oyVV4ZkLjtMT85wQkfBrOOvU55aLty+MV8xmcJR8A==} engines: {node: '>= 10'} @@ -3043,6 +3079,12 @@ packages: cpu: [arm64] os: [linux] + '@next/swc-linux-arm64-musl@16.1.6': + resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + '@next/swc-linux-x64-gnu@15.5.4': resolution: {integrity: sha512-7HKolaj+481FSW/5lL0BcTkA4Ueam9SPYWyN/ib/WGAFZf0DGAN8frNpNZYFHtM4ZstrHZS3LY3vrwlIQfsiMA==} engines: {node: '>= 10'} @@ -3055,6 +3097,12 @@ packages: cpu: [x64] os: [linux] + '@next/swc-linux-x64-gnu@16.1.6': + resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + '@next/swc-linux-x64-musl@15.5.4': resolution: {integrity: sha512-nlQQ6nfgN0nCO/KuyEUwwOdwQIGjOs4WNMjEUtpIQJPR2NUfmGpW2wkJln1d4nJ7oUzd1g4GivH5GoEPBgfsdw==} engines: {node: '>= 10'} @@ -3067,6 +3115,12 @@ packages: cpu: [x64] os: [linux] + '@next/swc-linux-x64-musl@16.1.6': + resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + '@next/swc-win32-arm64-msvc@15.5.4': resolution: {integrity: sha512-PcR2bN7FlM32XM6eumklmyWLLbu2vs+D7nJX8OAIoWy69Kef8mfiN4e8TUv2KohprwifdpFKPzIP1njuCjD0YA==} engines: {node: '>= 10'} @@ -3079,6 +3133,12 @@ packages: cpu: [arm64] os: [win32] + '@next/swc-win32-arm64-msvc@16.1.6': + resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + '@next/swc-win32-x64-msvc@15.5.4': resolution: {integrity: sha512-1ur2tSHZj8Px/KMAthmuI9FMp/YFusMMGoRNJaRZMOlSkgvLjzosSdQI0cJAKogdHl3qXUQKL9MGaYvKwA7DXg==} engines: {node: '>= 10'} @@ -3091,6 +3151,12 @@ packages: cpu: [x64] os: [win32] + '@next/swc-win32-x64-msvc@16.1.6': + resolution: {integrity: sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + '@noble/ciphers@1.3.0': resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} engines: {node: ^14.21.3 || >=16} @@ -7581,6 +7647,20 @@ packages: react-dom: optional: true + framer-motion@12.34.0: + resolution: {integrity: sha512-+/H49owhzkzQyxtn7nZeF4kdH++I2FWrESQ184Zbcw5cEqNHYkE5yxWxcTLSj5lNx3NWdbIRy5FHqUvetD8FWg==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + freeport-async@2.0.0: resolution: {integrity: sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ==} engines: {node: '>=8'} @@ -9413,6 +9493,9 @@ packages: motion-dom@12.30.0: resolution: {integrity: sha512-p6Mp+lxm+mK4O86YVyL6KAlFDVCIqpmcBt+uMVapMBqltPXpwZ5Wj2crnN2VE7lwsas0ONCPIW9YVpMigu4F5g==} + motion-dom@12.34.0: + resolution: {integrity: sha512-Lql3NuEcScRDxTAO6GgUsRHBZOWI/3fnMlkMcH5NftzcN37zJta+bpbMAV9px4Nj057TuvRooMK7QrzMCgtz6Q==} + motion-utils@12.27.2: resolution: {integrity: sha512-B55gcoL85Mcdt2IEStY5EEAsrMSVE2sI14xQ/uAdPL+mfQxhKKFaEag9JmfxedJOR4vZpBGoPeC/Gm13I/4g5Q==} @@ -9447,6 +9530,20 @@ packages: react-dom: optional: true + motion@12.34.0: + resolution: {integrity: sha512-01Sfa/zgsD/di8zA/uFW5Eb7/SPXoGyUfy+uMRMW5Spa8j0z/UbfQewAYvPMYFCXRlyD6e5aLHh76TxeeJD+RA==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -9578,6 +9675,27 @@ packages: sass: optional: true + next@16.1.6: + resolution: {integrity: sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==} + engines: {node: '>=20.9.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + nextstepjs@2.2.0: resolution: {integrity: sha512-VpUvKpIMbxBaLAMM3O8mc5Tavao4UBpKZ0+KyUGXxZhqdJt2ejS2l7pXLtlq2r62NG3EV0yv1wit5mgte7c3Vw==} peerDependencies: @@ -14842,6 +14960,8 @@ snapshots: '@next/env@15.5.9': {} + '@next/env@16.1.6': {} + '@next/eslint-plugin-next@15.3.3': dependencies: fast-glob: 3.3.1 @@ -14850,9 +14970,9 @@ snapshots: dependencies: fast-glob: 3.3.1 - '@next/font@14.2.15(next@15.5.9(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))': + '@next/font@14.2.15(next@16.1.6(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))': dependencies: - next: 15.5.9(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + next: 16.1.6(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@next/swc-darwin-arm64@15.5.4': optional: true @@ -14860,48 +14980,72 @@ snapshots: '@next/swc-darwin-arm64@15.5.7': optional: true + '@next/swc-darwin-arm64@16.1.6': + optional: true + '@next/swc-darwin-x64@15.5.4': optional: true '@next/swc-darwin-x64@15.5.7': optional: true + '@next/swc-darwin-x64@16.1.6': + optional: true + '@next/swc-linux-arm64-gnu@15.5.4': optional: true '@next/swc-linux-arm64-gnu@15.5.7': optional: true + '@next/swc-linux-arm64-gnu@16.1.6': + optional: true + '@next/swc-linux-arm64-musl@15.5.4': optional: true '@next/swc-linux-arm64-musl@15.5.7': optional: true + '@next/swc-linux-arm64-musl@16.1.6': + optional: true + '@next/swc-linux-x64-gnu@15.5.4': optional: true '@next/swc-linux-x64-gnu@15.5.7': optional: true + '@next/swc-linux-x64-gnu@16.1.6': + optional: true + '@next/swc-linux-x64-musl@15.5.4': optional: true '@next/swc-linux-x64-musl@15.5.7': optional: true + '@next/swc-linux-x64-musl@16.1.6': + optional: true + '@next/swc-win32-arm64-msvc@15.5.4': optional: true '@next/swc-win32-arm64-msvc@15.5.7': optional: true + '@next/swc-win32-arm64-msvc@16.1.6': + optional: true + '@next/swc-win32-x64-msvc@15.5.4': optional: true '@next/swc-win32-x64-msvc@15.5.7': optional: true + '@next/swc-win32-x64-msvc@16.1.6': + optional: true + '@noble/ciphers@1.3.0': {} '@noble/curves@1.9.1': @@ -17831,7 +17975,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.15 tinyrainbow: 2.0.0 - vitest: 3.2.4(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@20.19.31)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@27.4.0(@noble/hashes@1.8.0)(bufferutil@4.1.0)(utf-8-validate@5.0.10))(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vitest: 3.2.4(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@20.19.30)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@27.4.0(@noble/hashes@1.8.0)(bufferutil@4.1.0)(utf-8-validate@5.0.10))(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) '@vitest/utils@3.2.4': dependencies: @@ -20532,6 +20676,15 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) + framer-motion@12.34.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + motion-dom: 12.34.0 + motion-utils: 12.29.2 + tslib: 2.8.1 + optionalDependencies: + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + freeport-async@2.0.0: {} fresh@0.5.2: {} @@ -20876,9 +21029,9 @@ snapshots: transitivePeerDependencies: - supports-color - geist@1.5.1(next@15.5.9(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)): + geist@1.5.1(next@16.1.6(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)): dependencies: - next: 15.5.9(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + next: 16.1.6(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) generator-function@2.0.1: {} @@ -22850,6 +23003,10 @@ snapshots: dependencies: motion-utils: 12.29.2 + motion-dom@12.34.0: + dependencies: + motion-utils: 12.29.2 + motion-utils@12.27.2: {} motion-utils@12.29.2: {} @@ -22870,6 +23027,14 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) + motion@12.34.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + framer-motion: 12.34.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + tslib: 2.8.1 + optionalDependencies: + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + mri@1.2.0: {} mrmime@2.0.1: {} @@ -22969,15 +23134,15 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.5.9(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + next@15.5.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@next/env': 15.5.9 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001767 postcss: 8.4.31 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - styled-jsx: 5.1.6(@babel/core@7.28.6)(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.4) optionalDependencies: '@next/swc-darwin-arm64': 15.5.7 '@next/swc-darwin-x64': 15.5.7 @@ -22994,24 +23159,51 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.5.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + next@16.1.6(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@next/env': 15.5.9 + '@next/env': 16.1.6 '@swc/helpers': 0.5.15 + baseline-browser-mapping: 2.9.16 + caniuse-lite: 1.0.30001767 + postcss: 8.4.31 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + styled-jsx: 5.1.6(@babel/core@7.28.6)(react@19.2.3) + optionalDependencies: + '@next/swc-darwin-arm64': 16.1.6 + '@next/swc-darwin-x64': 16.1.6 + '@next/swc-linux-arm64-gnu': 16.1.6 + '@next/swc-linux-arm64-musl': 16.1.6 + '@next/swc-linux-x64-gnu': 16.1.6 + '@next/swc-linux-x64-musl': 16.1.6 + '@next/swc-win32-arm64-msvc': 16.1.6 + '@next/swc-win32-x64-msvc': 16.1.6 + '@opentelemetry/api': 1.9.0 + babel-plugin-react-compiler: 1.0.0 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + next@16.1.6(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + '@next/env': 16.1.6 + '@swc/helpers': 0.5.15 + baseline-browser-mapping: 2.9.16 caniuse-lite: 1.0.30001767 postcss: 8.4.31 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.4) optionalDependencies: - '@next/swc-darwin-arm64': 15.5.7 - '@next/swc-darwin-x64': 15.5.7 - '@next/swc-linux-arm64-gnu': 15.5.7 - '@next/swc-linux-arm64-musl': 15.5.7 - '@next/swc-linux-x64-gnu': 15.5.7 - '@next/swc-linux-x64-musl': 15.5.7 - '@next/swc-win32-arm64-msvc': 15.5.7 - '@next/swc-win32-x64-msvc': 15.5.7 + '@next/swc-darwin-arm64': 16.1.6 + '@next/swc-darwin-x64': 16.1.6 + '@next/swc-linux-arm64-gnu': 16.1.6 + '@next/swc-linux-arm64-musl': 16.1.6 + '@next/swc-linux-x64-gnu': 16.1.6 + '@next/swc-linux-x64-musl': 16.1.6 + '@next/swc-win32-arm64-msvc': 16.1.6 + '@next/swc-win32-x64-msvc': 16.1.6 '@opentelemetry/api': 1.9.0 babel-plugin-react-compiler: 1.0.0 sharp: 0.34.5