diff --git a/examples/example-app-router-patterns/.gitignore b/examples/example-app-router-patterns/.gitignore new file mode 100644 index 000000000..04239e7d0 --- /dev/null +++ b/examples/example-app-router-patterns/.gitignore @@ -0,0 +1,4 @@ +/node_modules +/.next/ +.DS_Store +tsconfig.tsbuildinfo diff --git a/examples/example-app-router-patterns/README.md b/examples/example-app-router-patterns/README.md new file mode 100644 index 000000000..6c3beabe0 --- /dev/null +++ b/examples/example-app-router-patterns/README.md @@ -0,0 +1,9 @@ +# example-app-router-patterns + +This example demonstrates various use cases and patterns for using `next-intl` with the App Router. + +## Deploy your own + +By deploying to [Vercel](https://vercel.com), you can check out the example in action. Note that you'll be prompted to create a new GitHub repository as part of this, allowing you to make subsequent changes. + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/amannn/next-intl/tree/main/examples/example-app-router-patterns) diff --git a/examples/example-app-router-patterns/eslint.config.mjs b/examples/example-app-router-patterns/eslint.config.mjs new file mode 100644 index 000000000..144292198 --- /dev/null +++ b/examples/example-app-router-patterns/eslint.config.mjs @@ -0,0 +1,22 @@ +import {dirname} from 'path'; +import {fileURLToPath} from 'url'; +import {FlatCompat} from '@eslint/eslintrc'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname +}); + +const eslintConfig = [ + ...compat.extends('next/core-web-vitals', 'next/typescript'), + { + rules: { + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/ban-ts-comment': 'off' + } + } +]; + +export default eslintConfig; diff --git a/examples/example-app-router-patterns/mdx-components.tsx b/examples/example-app-router-patterns/mdx-components.tsx new file mode 100644 index 000000000..49eea7a75 --- /dev/null +++ b/examples/example-app-router-patterns/mdx-components.tsx @@ -0,0 +1,6 @@ +import type { MDXComponents } from 'mdx/types'; +import { Code } from '@/components/code/code'; + +export function useMDXComponents(components: MDXComponents): MDXComponents { + return { Code, ...components }; +} diff --git a/examples/example-app-router-patterns/messages/de.json b/examples/example-app-router-patterns/messages/de.json new file mode 100644 index 000000000..e453dea88 --- /dev/null +++ b/examples/example-app-router-patterns/messages/de.json @@ -0,0 +1,28 @@ +{ + "Layout": { + "title": "next-intl Playground", + "tagline": "Übersetzungen, Formatierung, Routing und Patterns mit Next.js.", + "examples": "Beispiele" + }, + "Nav": { + "translations": "Übersetzungen", + "serverComponents": "Server-Komponenten", + "serverComponentsDescription": "Übersetzte Strings in Server-Komponenten lesen.", + "clientComponents": "Client-Komponenten", + "clientComponentsDescription": "Übersetzungen in interaktiven Client-Komponenten nutzen." + }, + "ServerComponentsPage": { + "title": "Server-Komponenten", + "subtitle": "Übersetzungen", + "output": "Ausgabe", + "greeting": "Hallo, Welt!" + }, + "ClientComponentsPage": { + "title": "Client-Komponenten", + "subtitle": "Übersetzungen", + "output": "Ausgabe", + "label": "Dein Name", + "placeholder": "Frodo", + "greeting": "Hallo, {name}!" + } +} diff --git a/examples/example-app-router-patterns/messages/en.json b/examples/example-app-router-patterns/messages/en.json new file mode 100644 index 000000000..8556a49e2 --- /dev/null +++ b/examples/example-app-router-patterns/messages/en.json @@ -0,0 +1,28 @@ +{ + "Layout": { + "title": "next-intl playground", + "tagline": "Translations, formatting, routing and patterns with Next.js.", + "examples": "Examples" + }, + "Nav": { + "translations": "Translations", + "serverComponents": "Server Components", + "serverComponentsDescription": "Read translated strings inside Server Components.", + "clientComponents": "Client Components", + "clientComponentsDescription": "Use translations in interactive Client Components." + }, + "ServerComponentsPage": { + "title": "Server Components", + "subtitle": "Translations", + "output": "Output", + "greeting": "Hello, world!" + }, + "ClientComponentsPage": { + "title": "Client Components", + "subtitle": "Translations", + "output": "Output", + "label": "Your name", + "placeholder": "Frodo", + "greeting": "Hello, {name}!" + } +} diff --git a/examples/example-app-router-patterns/next-env.d.ts b/examples/example-app-router-patterns/next-env.d.ts new file mode 100644 index 000000000..830fb594c --- /dev/null +++ b/examples/example-app-router-patterns/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/examples/example-app-router-patterns/next.config.mjs b/examples/example-app-router-patterns/next.config.mjs new file mode 100644 index 000000000..6e14b0cdb --- /dev/null +++ b/examples/example-app-router-patterns/next.config.mjs @@ -0,0 +1,26 @@ +import createMDX from '@next/mdx'; +import {remarkCodeHike, recmaCodeHike} from 'codehike/mdx'; +import createNextIntlPlugin from 'next-intl/plugin'; + +/** @type {import('codehike/mdx').CodeHikeConfig} */ +const chConfig = { + components: {code: 'Code'} +}; + +const withMDX = createMDX({ + extension: /\.mdx?$/, + options: { + remarkPlugins: [[remarkCodeHike, chConfig]], + recmaPlugins: [[recmaCodeHike, chConfig]], + jsx: true + } +}); + +const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts'); + +/** @type {import('next').NextConfig} */ +const nextConfig = { + pageExtensions: ['ts', 'tsx', 'mdx'] +}; + +export default withNextIntl(withMDX(nextConfig)); diff --git a/examples/example-app-router-patterns/package.json b/examples/example-app-router-patterns/package.json new file mode 100644 index 000000000..3c7324727 --- /dev/null +++ b/examples/example-app-router-patterns/package.json @@ -0,0 +1,51 @@ +{ + "name": "example-app-router-patterns", + "private": true, + "scripts": { + "dev": "next dev", + "lint": "eslint src && prettier src --check", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "@mdx-js/loader": "^3.1.0", + "@mdx-js/react": "^3.1.0", + "@next/mdx": "^15.5.4", + "clsx": "^2.1.1", + "codehike": "^1.0.7", + "lucide-react": "^0.545.0", + "next": "^15.5.0", + "next-intl": "^4.0.0", + "next-themes": "^0.4.6", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "tailwindcss": "^4.1.12" + }, + "devDependencies": { + "@eslint/eslintrc": "^3.1.0", + "@tailwindcss/postcss": "^4.1.12", + "@types/mdx": "^2.0.13", + "@types/node": "^20.14.5", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "eslint": "9.11.1", + "eslint-config-next": "^15.5.0", + "postcss": "^8.5.3", + "prettier": "^3.3.3", + "prettier-plugin-organize-imports": "^4.2.0", + "prettier-plugin-tailwindcss": "^0.6.14", + "typescript": "^5.5.3" + }, + "prettier": { + "singleQuote": true, + "bracketSpacing": false, + "trailingComma": "none", + "plugins": [ + "prettier-plugin-organize-imports", + "prettier-plugin-tailwindcss" + ] + }, + "engines": { + "node": ">=20.0.0" + } +} diff --git a/examples/example-app-router-patterns/postcss.config.mjs b/examples/example-app-router-patterns/postcss.config.mjs new file mode 100644 index 000000000..313840505 --- /dev/null +++ b/examples/example-app-router-patterns/postcss.config.mjs @@ -0,0 +1,6 @@ +const config = { + plugins: { + '@tailwindcss/postcss': {} + } +}; +export default config; diff --git a/examples/example-app-router-patterns/src/app/[locale]/layout.tsx b/examples/example-app-router-patterns/src/app/[locale]/layout.tsx new file mode 100644 index 000000000..71a10278a --- /dev/null +++ b/examples/example-app-router-patterns/src/app/[locale]/layout.tsx @@ -0,0 +1,34 @@ +import {PlaygroundByline} from '@/components/playground/byline'; +import {PlaygroundSidebar} from '@/components/playground/sidebar'; +import {routing} from '@/i18n/routing'; +import {hasLocale} from 'next-intl'; +import {setRequestLocale} from 'next-intl/server'; +import {notFound} from 'next/navigation'; +import type {ReactNode} from 'react'; + +export function generateStaticParams() { + return routing.locales.map((locale) => ({locale})); +} + +type Props = { + children: ReactNode; + params: Promise<{locale: string}>; +}; + +export default async function LocaleLayout({children, params}: Props) { + const {locale} = await params; + if (!hasLocale(routing.locales, locale)) notFound(); + setRequestLocale(locale); + + return ( + <> + +
+
+ {children} + +
+
+ + ); +} diff --git a/examples/example-app-router-patterns/src/app/[locale]/page.tsx b/examples/example-app-router-patterns/src/app/[locale]/page.tsx new file mode 100644 index 000000000..447121f5c --- /dev/null +++ b/examples/example-app-router-patterns/src/app/[locale]/page.tsx @@ -0,0 +1,71 @@ +import {PlaygroundBoundary} from '@/components/playground/boundary'; +import {LinkStatus} from '@/components/playground/link-status'; +import {Link} from '@/i18n/navigation'; +import {sections} from '@/lib/nav'; +import {ArrowRight} from 'lucide-react'; +import {useTranslations} from 'next-intl'; +import {setRequestLocale} from 'next-intl/server'; + +type Props = { + params: Promise<{locale: string}>; +}; + +export default async function HomePage({params}: Props) { + const {locale} = await params; + setRequestLocale(locale); + return ; +} + +function Home() { + const t = useTranslations('Layout'); + const tNav = useTranslations('Nav'); + + return ( +
+
+

+ {t('title')} +

+

+ {t('tagline')} +

+
+ + {sections.map((section) => { + const Icon = section.icon; + return ( +
+
+ + {tNav(section.titleKey)} +
+
+ {section.items.map((item) => ( + +
+ + {tNav(item.titleKey)} + + + +
+
+ {tNav(item.descriptionKey)} +
+ + ))} +
+
+ ); + })} +
+
+ ); +} diff --git a/examples/example-app-router-patterns/src/app/[locale]/translations/client-components/client-example.tsx b/examples/example-app-router-patterns/src/app/[locale]/translations/client-components/client-example.tsx new file mode 100644 index 000000000..bcbade947 --- /dev/null +++ b/examples/example-app-router-patterns/src/app/[locale]/translations/client-components/client-example.tsx @@ -0,0 +1,30 @@ +'use client'; + +import {useTranslations} from 'next-intl'; +import {useState} from 'react'; + +export function ClientExample() { + const t = useTranslations('ClientComponentsPage'); + const [name, setName] = useState(''); + + return ( +
+ + setName(e.target.value)} + placeholder={t('placeholder')} + className="border-border bg-background w-full max-w-xs rounded-md border px-3 py-2 text-sm" + /> +

+ {t('greeting', {name: name || t('placeholder')})} +

+
+ ); +} diff --git a/examples/example-app-router-patterns/src/app/[locale]/translations/client-components/content.mdx b/examples/example-app-router-patterns/src/app/[locale]/translations/client-components/content.mdx new file mode 100644 index 000000000..742f789f8 --- /dev/null +++ b/examples/example-app-router-patterns/src/app/[locale]/translations/client-components/content.mdx @@ -0,0 +1,20 @@ +- `useTranslations` works the same in Client Components, so interactive UI can read messages too. +- ICU arguments like `{name}` are resolved in the browser as state changes — try typing below. + +```tsx app/greet.tsx +'use client'; +import {useState} from 'react'; +import {useTranslations} from 'next-intl'; + +export function Greet() { + const t = useTranslations('ClientComponentsPage'); + const [name, setName] = useState('Frodo'); + return ( + <> + setName(e.target.value)} /> + // !mark +

{t('greeting', {name})}

+ + ); +} +``` diff --git a/examples/example-app-router-patterns/src/app/[locale]/translations/client-components/page.tsx b/examples/example-app-router-patterns/src/app/[locale]/translations/client-components/page.tsx new file mode 100644 index 000000000..9b3812dbc --- /dev/null +++ b/examples/example-app-router-patterns/src/app/[locale]/translations/client-components/page.tsx @@ -0,0 +1,51 @@ +import {PlaygroundBoundary} from '@/components/playground/boundary'; +import {GitHubLink} from '@/components/playground/github-link'; +import {useTranslations} from 'next-intl'; +import {setRequestLocale} from 'next-intl/server'; +import {ClientExample} from './client-example'; +import Content from './content.mdx'; + +type Props = { + params: Promise<{locale: string}>; +}; + +export default async function ClientComponentsPage({params}: Props) { + const {locale} = await params; + setRequestLocale(locale); + return ; +} + +function ClientComponentsView() { + const t = useTranslations('ClientComponentsPage'); + + return ( +
+
+

+ {t('subtitle')} +

+

+ {t('title')} +

+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ ); +} diff --git a/examples/example-app-router-patterns/src/app/[locale]/translations/server-components/content.mdx b/examples/example-app-router-patterns/src/app/[locale]/translations/server-components/content.mdx new file mode 100644 index 000000000..bacf1a0a7 --- /dev/null +++ b/examples/example-app-router-patterns/src/app/[locale]/translations/server-components/content.mdx @@ -0,0 +1,12 @@ +- Call `useTranslations` from a Server Component to read messages — it works in both `async` and non-async components. +- Messages stay on the server, so no translation runtime is shipped to the client. + +```tsx app/page.tsx +import {useTranslations} from 'next-intl'; + +export default function Page() { + // !mark + const t = useTranslations('ServerComponentsPage'); + return

{t('greeting')}

; +} +``` diff --git a/examples/example-app-router-patterns/src/app/[locale]/translations/server-components/page.tsx b/examples/example-app-router-patterns/src/app/[locale]/translations/server-components/page.tsx new file mode 100644 index 000000000..2e1d4d3cc --- /dev/null +++ b/examples/example-app-router-patterns/src/app/[locale]/translations/server-components/page.tsx @@ -0,0 +1,51 @@ +import {PlaygroundBoundary} from '@/components/playground/boundary'; +import {GitHubLink} from '@/components/playground/github-link'; +import {useTranslations} from 'next-intl'; +import {setRequestLocale} from 'next-intl/server'; +import Content from './content.mdx'; +import {ServerExample} from './server-example'; + +type Props = { + params: Promise<{locale: string}>; +}; + +export default async function ServerComponentsPage({params}: Props) { + const {locale} = await params; + setRequestLocale(locale); + return ; +} + +function ServerComponentsView() { + const t = useTranslations('ServerComponentsPage'); + + return ( +
+
+

+ {t('subtitle')} +

+

+ {t('title')} +

+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ ); +} diff --git a/examples/example-app-router-patterns/src/app/[locale]/translations/server-components/server-example.tsx b/examples/example-app-router-patterns/src/app/[locale]/translations/server-components/server-example.tsx new file mode 100644 index 000000000..4519fa616 --- /dev/null +++ b/examples/example-app-router-patterns/src/app/[locale]/translations/server-components/server-example.tsx @@ -0,0 +1,9 @@ +import {useTranslations} from 'next-intl'; + +// A non-async Server Component — `useTranslations` works here too. +export function ServerExample() { + const t = useTranslations('ServerComponentsPage'); + return ( +

{t('greeting')}

+ ); +} diff --git a/examples/example-app-router-patterns/src/app/design/DesignColorSwatch.tsx b/examples/example-app-router-patterns/src/app/design/DesignColorSwatch.tsx new file mode 100644 index 000000000..7f6222457 --- /dev/null +++ b/examples/example-app-router-patterns/src/app/design/DesignColorSwatch.tsx @@ -0,0 +1,15 @@ +import clsx from 'clsx'; + +type Props = { + className: string; + value: string; +}; + +export default function DesignColorSwatch({className, value}: Props) { + return ( +
+
+
{value}
+
+ ); +} diff --git a/examples/example-app-router-patterns/src/app/design/DesignSection.tsx b/examples/example-app-router-patterns/src/app/design/DesignSection.tsx new file mode 100644 index 000000000..433cbf251 --- /dev/null +++ b/examples/example-app-router-patterns/src/app/design/DesignSection.tsx @@ -0,0 +1,17 @@ +import {ReactNode} from 'react'; + +type Props = { + children: ReactNode; + title: string; +}; + +export default function DesignSection({children, title}: Props) { + return ( +
+

+ {title} +

+ {children} +
+ ); +} diff --git a/examples/example-app-router-patterns/src/app/design/page.tsx b/examples/example-app-router-patterns/src/app/design/page.tsx new file mode 100644 index 000000000..1fcd139d5 --- /dev/null +++ b/examples/example-app-router-patterns/src/app/design/page.tsx @@ -0,0 +1,170 @@ +// Documentation page for the next-intl design system + +import DesignColorSwatch from './DesignColorSwatch'; +import DesignSection from './DesignSection'; + +export default function DesignPage() { + return ( +
+
+

+ Design system +

+
+ +
+
+

+ Blue (primary) +

+
+ + + + + + + + + + +
+
+
+

Gray

+
+ + + + + + + + + + +
+
+
+
+ +
+
+
+

+ Title large +

+

+ Title normal +

+

Title description

+

+ Title caption +

+

+ Title small +

+

+ Headline +

+

+ Headline caption +

+

Body large

+

Body large muted

+

+ Body with{' '} + + a link + +

+

Body muted

+

Label

+

+ Label muted +

+

+ Inline code +

+
+
+
+
+

+ Title large +

+

+ Title normal +

+

Title description

+

+ Title caption +

+

+ Title small +

+

Headline

+

+ Headline caption +

+

Body large

+

Body large muted

+

+ Body with{' '} + + a link + +

+

Body muted

+

Label

+

+ Label muted +

+

+ Inline code +

+
+
+
+
+ +
+
+
+

+ Title caption +

+

+ Title normal +

+

+ Title description +

+
+
+
+
+

+ Title caption +

+

+ Title normal +

+

+ Title description +

+
+
+
+
+
+
+
+ ); +} diff --git a/examples/example-app-router-patterns/src/app/favicon.ico b/examples/example-app-router-patterns/src/app/favicon.ico new file mode 100644 index 000000000..4ddd8fff7 Binary files /dev/null and b/examples/example-app-router-patterns/src/app/favicon.ico differ diff --git a/examples/example-app-router-patterns/src/app/globals.css b/examples/example-app-router-patterns/src/app/globals.css new file mode 100644 index 000000000..c5213ed73 --- /dev/null +++ b/examples/example-app-router-patterns/src/app/globals.css @@ -0,0 +1,243 @@ +@import 'tailwindcss'; + +@custom-variant dark (&:is(.dark *)); + +@theme { + --color-white: #ffffff; + + --color-gray-50: #f7f7f8; + --color-gray-100: #ebebef; + --color-gray-200: #d1d1db; + --color-gray-300: #a9a9bc; + --color-gray-400: #8a8aa3; + --color-gray-500: #6c6c89; + --color-gray-600: #55556d; + --color-gray-700: #3f3f50; + --color-gray-800: #282833; + --color-gray-900: #121217; + + --color-blue-300: #70d2ff; + --color-blue-700: #008fd6; + + --font-mono: + Monaco, ui-monospace, SFMono-Regular, Menlo, Consolas, Liberation Mono, + Courier New, monospace; +} + +/* Semantic tokens flip under `.dark` for runtime theme switching. */ +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-border: var(--sidebar-border); +} + +:root { + --background: var(--color-gray-50); + --foreground: var(--color-gray-900); + --card: var(--color-white); + --card-foreground: var(--color-gray-900); + --popover: var(--color-white); + --popover-foreground: var(--color-gray-900); + --primary: var(--color-blue-700); + --primary-foreground: var(--color-white); + --secondary: var(--color-gray-200); + --secondary-foreground: var(--color-gray-900); + --muted: var(--color-gray-200); + --muted-foreground: var(--color-gray-600); + --accent: var(--color-blue-300); + --accent-foreground: var(--color-gray-900); + --border: var(--color-gray-200); + --input: var(--color-gray-200); + --ring: var(--color-blue-700); + --sidebar: var(--color-gray-50); + --sidebar-foreground: var(--color-gray-900); + --sidebar-border: var(--color-gray-200); +} + +.dark { + --background: var(--color-gray-900); + --foreground: var(--color-gray-50); + --card: var(--color-gray-800); + --card-foreground: var(--color-gray-50); + --popover: var(--color-gray-800); + --popover-foreground: var(--color-gray-50); + --primary: var(--color-blue-300); + --primary-foreground: var(--color-gray-900); + --secondary: var(--color-gray-700); + --secondary-foreground: var(--color-gray-50); + --muted: var(--color-gray-700); + --muted-foreground: var(--color-gray-300); + --accent: var(--color-blue-700); + --accent-foreground: var(--color-gray-50); + --border: var(--color-gray-700); + --input: var(--color-gray-700); + --ring: var(--color-blue-300); + --sidebar: var(--color-gray-900); + --sidebar-foreground: var(--color-gray-50); + --sidebar-border: var(--color-gray-700); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground antialiased; + } + button:not([disabled]), + [role='button']:not([disabled]) { + cursor: pointer; + } +} + +/* Subtle dot-grid backdrop for the "output" boundary box */ +.dotgrid { + background-image: radial-gradient( + circle at center, + color-mix(in oklch, var(--muted-foreground) 28%, transparent) 1px, + transparent 1px + ); + background-size: 14px 14px; + background-position: 0 0; +} + +/* MDX content typography (scoped — no @tailwindcss/typography needed) */ +.mdx-content { + color: var(--foreground); + font-size: 0.95rem; + line-height: 1.65; +} + +.mdx-content > * + * { + margin-top: 1rem; +} + +.mdx-content p { + color: var(--muted-foreground); +} + +.mdx-content ul { + list-style: disc; + padding-left: 1.25rem; + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.mdx-content li { + color: var(--muted-foreground); +} + +.mdx-content li::marker { + color: var(--muted-foreground); +} + +.mdx-content :not(pre) > code { + font-family: var(--font-mono); + font-size: 0.85em; + background: var(--muted); + color: var(--foreground); + padding: 0.1em 0.35em; + border-radius: 0.25rem; + border: 1px solid var(--border); +} + +.mdx-content a { + color: var(--primary); + text-decoration: underline; + text-decoration-style: dotted; + text-underline-offset: 3px; +} + +.mdx-content a:hover { + text-decoration-style: solid; +} + +.mdx-content h2 { + font-size: 1.25rem; + font-weight: 600; + letter-spacing: -0.01em; + color: var(--foreground); + margin-top: 1.75rem; +} + +.mdx-content h3 { + font-size: 1rem; + font-weight: 600; + color: var(--foreground); + margin-top: 1.25rem; +} + +/* Code Hike — github-from-css theme variables */ +:root { + --ch-0: light; + --ch-1: #6e7781; + --ch-2: #0550ae; + --ch-3: #953800; + --ch-4: #24292f; + --ch-5: #8250df; + --ch-6: #116329; + --ch-7: #cf222e; + --ch-8: #0a3069; + --ch-9: #82071e; + --ch-10: #f6f8fa; + --ch-11: #ffebe9; + --ch-12: #ffd8b5; + --ch-13: #eaeef2; + --ch-14: #57606a; + --ch-15: #ffffff; + --ch-16: #eaeef2; + --ch-17: #fdf2f8; + --ch-18: #1f883d; + --ch-19: #cf222e; + --ch-20: #8250df; + --ch-21: #fff8c5; + --ch-22: #fbf0a4; + --ch-23: #6e7781; + --ch-24: #ffffffe6; +} + +.dark { + --ch-0: dark; + --ch-1: #8b949e; + --ch-2: #79c0ff; + --ch-3: #ffa657; + --ch-4: #c9d1d9; + --ch-5: #d2a8ff; + --ch-6: #7ee787; + --ch-7: #ff7b72; + --ch-8: #a5d6ff; + --ch-9: #ffa198; + --ch-10: #f0f6fc; + --ch-11: #490202; + --ch-12: #5a1e02; + --ch-13: #161b22; + --ch-14: #8b949e; + --ch-15: #0d1117; + --ch-16: #30363d; + --ch-17: #261d2d; + --ch-18: #56d364; + --ch-19: #f85149; + --ch-20: #d2a8ff; + --ch-21: #5a1e02; + --ch-22: #693e00; + --ch-23: #8b949e; + --ch-24: #1f6feb1a; +} diff --git a/examples/example-app-router-patterns/src/app/layout.tsx b/examples/example-app-router-patterns/src/app/layout.tsx new file mode 100644 index 000000000..3166a307b --- /dev/null +++ b/examples/example-app-router-patterns/src/app/layout.tsx @@ -0,0 +1,40 @@ +import {clsx} from 'clsx'; +import type {Metadata} from 'next'; +import {NextIntlClientProvider} from 'next-intl'; +import {getLocale} from 'next-intl/server'; +import {ThemeProvider} from 'next-themes'; +import {Inter} from 'next/font/google'; +import type {ReactNode} from 'react'; +import './globals.css'; + +const inter = Inter({ + subsets: ['latin'], + variable: '--font-inter' +}); + +export const metadata: Metadata = { + title: 'next-intl playground', + description: + 'Explore translations, formatting, routing and patterns with next-intl.' +}; + +export default async function RootLayout({children}: {children: ReactNode}) { + const locale = await getLocale(); + + return ( + + + + + {children} + + + + + ); +} diff --git a/examples/example-app-router-patterns/src/assets/logo.tsx b/examples/example-app-router-patterns/src/assets/logo.tsx new file mode 100644 index 000000000..5c0143ae6 --- /dev/null +++ b/examples/example-app-router-patterns/src/assets/logo.tsx @@ -0,0 +1,32 @@ +// The next-intl globe mark, matching the logo used in the docs. Uses +// `currentColor` so the color can be controlled via the `text-*` utility. + +export function Logo({className}: {className?: string}) { + return ( + + + + + + + + + + ); +} diff --git a/examples/example-app-router-patterns/src/components/code/annotations/index.ts b/examples/example-app-router-patterns/src/components/code/annotations/index.ts new file mode 100644 index 000000000..eb38e6fd8 --- /dev/null +++ b/examples/example-app-router-patterns/src/components/code/annotations/index.ts @@ -0,0 +1 @@ +export {mark} from './mark'; diff --git a/examples/example-app-router-patterns/src/components/code/annotations/mark.tsx b/examples/example-app-router-patterns/src/components/code/annotations/mark.tsx new file mode 100644 index 000000000..60dbd5355 --- /dev/null +++ b/examples/example-app-router-patterns/src/components/code/annotations/mark.tsx @@ -0,0 +1,35 @@ +import type {AnnotationHandler} from 'codehike/code'; +import {InnerLine} from 'codehike/code'; + +export const mark: AnnotationHandler = { + name: 'mark', + Line: ({annotation, ...props}) => { + const color = annotation?.query || 'rgb(14 165 233)'; + return ( +
+ +
+ ); + }, + Inline: ({annotation, children}) => { + const color = annotation?.query || 'rgb(14 165 233)'; + return ( + + {children} + + ); + } +}; diff --git a/examples/example-app-router-patterns/src/components/code/code.tsx b/examples/example-app-router-patterns/src/components/code/code.tsx new file mode 100644 index 000000000..1eef7522c --- /dev/null +++ b/examples/example-app-router-patterns/src/components/code/code.tsx @@ -0,0 +1,25 @@ +import {PlaygroundBoundary} from '@/components/playground/boundary'; +import {Pre, type RawCode, highlight} from 'codehike/code'; +import {mark} from './annotations'; + +export async function Code({codeblock}: {codeblock: RawCode}) { + const highlighted = await highlight(codeblock, 'github-from-css'); + + const pre = ( +
+  );
+
+  if (codeblock.meta) {
+    return (
+      
+        {pre}
+      
+    );
+  }
+
+  return 
{pre}
; +} diff --git a/examples/example-app-router-patterns/src/components/playground/boundary.tsx b/examples/example-app-router-patterns/src/components/playground/boundary.tsx new file mode 100644 index 000000000..ed07d31d9 --- /dev/null +++ b/examples/example-app-router-patterns/src/components/playground/boundary.tsx @@ -0,0 +1,43 @@ +import clsx from 'clsx'; +import type React from 'react'; + +export const PlaygroundBoundary = ({ + children, + label, + className, + innerClassName, + size = 'default', + variant = 'plain' +}: { + children: React.ReactNode; + label?: string | string[]; + className?: string; + innerClassName?: string; + size?: 'default' | 'compact'; + variant?: 'plain' | 'dotgrid'; +}) => { + return ( +
+ {label && ( +
+ {(typeof label === 'string' ? [label] : label).map((text) => ( + + {text} + + ))} +
+ )} +
{children}
+
+ ); +}; diff --git a/examples/example-app-router-patterns/src/components/playground/byline.tsx b/examples/example-app-router-patterns/src/components/playground/byline.tsx new file mode 100644 index 000000000..c20004ab8 --- /dev/null +++ b/examples/example-app-router-patterns/src/components/playground/byline.tsx @@ -0,0 +1,35 @@ +import {BookOpen, Github} from 'lucide-react'; + +const links = [ + { + href: 'https://github.com/amannn/next-intl/tree/main/examples/example-app-router-patterns', + label: 'Source code', + Icon: Github + }, + { + href: 'https://next-intl.dev/docs/getting-started', + label: 'Docs', + Icon: BookOpen + } +]; + +export function PlaygroundByline() { + return ( +
+
+ {links.map(({href, label, Icon}) => ( + + + {label} + + ))} +
+
+ ); +} diff --git a/examples/example-app-router-patterns/src/components/playground/github-link.tsx b/examples/example-app-router-patterns/src/components/playground/github-link.tsx new file mode 100644 index 000000000..e21a8fb1c --- /dev/null +++ b/examples/example-app-router-patterns/src/components/playground/github-link.tsx @@ -0,0 +1,22 @@ +import {ArrowUpRight, Github} from 'lucide-react'; + +export function GitHubLink({path}: {path: string}) { + // Encode segments so dynamic ones like `[locale]` work as a GitHub URL + const href = `https://github.com/amannn/next-intl/tree/main/${path + .split('/') + .map((segment) => encodeURIComponent(segment)) + .join('/')}`; + + return ( + + + View on GitHub + + + ); +} diff --git a/examples/example-app-router-patterns/src/components/playground/link-status.tsx b/examples/example-app-router-patterns/src/components/playground/link-status.tsx new file mode 100644 index 000000000..6f449bee3 --- /dev/null +++ b/examples/example-app-router-patterns/src/components/playground/link-status.tsx @@ -0,0 +1,15 @@ +'use client'; + +import {useLinkStatus} from 'next/link'; + +export function LinkStatus() { + const {pending} = useLinkStatus(); + if (!pending) return null; + return ( + + ); +} diff --git a/examples/example-app-router-patterns/src/components/playground/locale-switcher.tsx b/examples/example-app-router-patterns/src/components/playground/locale-switcher.tsx new file mode 100644 index 000000000..245940b9f --- /dev/null +++ b/examples/example-app-router-patterns/src/components/playground/locale-switcher.tsx @@ -0,0 +1,39 @@ +'use client'; + +import {Link, usePathname} from '@/i18n/navigation'; +import {routing} from '@/i18n/routing'; +import {clsx} from 'clsx'; +import {useLocale} from 'next-intl'; +import {useParams} from 'next/navigation'; + +export function LocaleSwitcher() { + const locale = useLocale(); + const pathname = usePathname(); + const params = useParams(); + + return ( +
+ {routing.locales.map((loc) => ( + + {loc} + + ))} +
+ ); +} diff --git a/examples/example-app-router-patterns/src/components/playground/sidebar.tsx b/examples/example-app-router-patterns/src/components/playground/sidebar.tsx new file mode 100644 index 000000000..a3d7c7b7e --- /dev/null +++ b/examples/example-app-router-patterns/src/components/playground/sidebar.tsx @@ -0,0 +1,107 @@ +'use client'; + +import {Logo} from '@/assets/logo'; +import {Link, usePathname} from '@/i18n/navigation'; +import {sections} from '@/lib/nav'; +import {clsx} from 'clsx'; +import {Menu, X} from 'lucide-react'; +import {useTranslations} from 'next-intl'; +import {useState} from 'react'; +import {LinkStatus} from './link-status'; +import {LocaleSwitcher} from './locale-switcher'; +import {ThemeToggle} from './theme-toggle'; + +export function PlaygroundSidebar() { + const [isOpen, setIsOpen] = useState(false); + const pathname = usePathname(); + const t = useTranslations('Nav'); + const close = () => setIsOpen(false); + + return ( +
+
+ + + + Playground + + + +
+ + + +
+
+ +
+ +
+
+ ); +} diff --git a/examples/example-app-router-patterns/src/components/playground/theme-toggle.tsx b/examples/example-app-router-patterns/src/components/playground/theme-toggle.tsx new file mode 100644 index 000000000..710565f26 --- /dev/null +++ b/examples/example-app-router-patterns/src/components/playground/theme-toggle.tsx @@ -0,0 +1,24 @@ +'use client'; + +import {Moon, Sun} from 'lucide-react'; +import {useTheme} from 'next-themes'; + +export function ThemeToggle() { + const {resolvedTheme, setTheme} = useTheme(); + const isDark = resolvedTheme === 'dark'; + + return ( + + ); +} diff --git a/examples/example-app-router-patterns/src/i18n/navigation.ts b/examples/example-app-router-patterns/src/i18n/navigation.ts new file mode 100644 index 000000000..6b3a3576c --- /dev/null +++ b/examples/example-app-router-patterns/src/i18n/navigation.ts @@ -0,0 +1,5 @@ +import {createNavigation} from 'next-intl/navigation'; +import {routing} from './routing'; + +export const {Link, redirect, usePathname, useRouter, getPathname} = + createNavigation(routing); diff --git a/examples/example-app-router-patterns/src/i18n/request.ts b/examples/example-app-router-patterns/src/i18n/request.ts new file mode 100644 index 000000000..82dbdacf4 --- /dev/null +++ b/examples/example-app-router-patterns/src/i18n/request.ts @@ -0,0 +1,15 @@ +import {hasLocale} from 'next-intl'; +import {getRequestConfig} from 'next-intl/server'; +import {routing} from './routing'; + +export default getRequestConfig(async ({requestLocale}) => { + const requested = await requestLocale; + const locale = hasLocale(routing.locales, requested) + ? requested + : routing.defaultLocale; + + return { + locale, + messages: (await import(`../../messages/${locale}.json`)).default + }; +}); diff --git a/examples/example-app-router-patterns/src/i18n/routing.ts b/examples/example-app-router-patterns/src/i18n/routing.ts new file mode 100644 index 000000000..b6d765b6a --- /dev/null +++ b/examples/example-app-router-patterns/src/i18n/routing.ts @@ -0,0 +1,6 @@ +import {defineRouting} from 'next-intl/routing'; + +export const routing = defineRouting({ + locales: ['en', 'de'], + defaultLocale: 'en' +}); diff --git a/examples/example-app-router-patterns/src/lib/nav.ts b/examples/example-app-router-patterns/src/lib/nav.ts new file mode 100644 index 000000000..8ae17c57f --- /dev/null +++ b/examples/example-app-router-patterns/src/lib/nav.ts @@ -0,0 +1,33 @@ +import {Languages, type LucideIcon} from 'lucide-react'; + +export type NavItem = { + // Keys into the `Nav` namespace so labels can be translated + titleKey: string; + descriptionKey: string; + slug: string; +}; + +export type NavSection = { + titleKey: string; + icon: LucideIcon; + items: Array; +}; + +export const sections: Array = [ + { + titleKey: 'translations', + icon: Languages, + items: [ + { + titleKey: 'serverComponents', + descriptionKey: 'serverComponentsDescription', + slug: '/translations/server-components' + }, + { + titleKey: 'clientComponents', + descriptionKey: 'clientComponentsDescription', + slug: '/translations/client-components' + } + ] + } +]; diff --git a/examples/example-app-router-patterns/src/middleware.ts b/examples/example-app-router-patterns/src/middleware.ts new file mode 100644 index 000000000..7ae8d6402 --- /dev/null +++ b/examples/example-app-router-patterns/src/middleware.ts @@ -0,0 +1,9 @@ +import createMiddleware from 'next-intl/middleware'; +import {routing} from './i18n/routing'; + +export default createMiddleware(routing); + +export const config = { + // Skip API routes, Next internals, the `/design` reference page and files + matcher: ['/((?!api|_next|design|.*\\..*).*)'] +}; diff --git a/examples/example-app-router-patterns/tsconfig.json b/examples/example-app-router-patterns/tsconfig.json new file mode 100644 index 000000000..d72a167c8 --- /dev/null +++ b/examples/example-app-router-patterns/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "allowArbitraryExtensions": true, + "target": "es2015", + "lib": ["dom", "dom.iterable", "esnext"], + "strict": true, + "allowJs": true, + "skipLibCheck": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "Bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": ["node_modules"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 702c28688..f0d9d35dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -446,6 +446,85 @@ importers: specifier: ^6.0.0 version: 6.0.2 + examples/example-app-router-patterns: + dependencies: + '@mdx-js/loader': + specifier: ^3.1.0 + version: 3.1.1(webpack@5.104.1) + '@mdx-js/react': + specifier: ^3.1.0 + version: 3.1.1(@types/react@19.2.14)(react@19.2.3) + '@next/mdx': + specifier: ^15.5.4 + version: 15.5.18(@mdx-js/loader@3.1.1(webpack@5.104.1))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.3)) + clsx: + specifier: ^2.1.1 + version: 2.1.1 + codehike: + specifier: ^1.0.7 + version: 1.1.0 + lucide-react: + specifier: ^0.545.0 + version: 0.545.0(react@19.2.3) + next: + specifier: ^15.5.0 + version: 15.5.18(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + next-intl: + specifier: ^4.0.0 + version: link:../../packages/next-intl + next-themes: + specifier: ^0.4.6 + version: 0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: + specifier: ^19.0.0 + version: 19.2.3 + react-dom: + specifier: ^19.0.0 + version: 19.2.3(react@19.2.3) + tailwindcss: + specifier: ^4.1.12 + version: 4.2.4 + devDependencies: + '@eslint/eslintrc': + specifier: ^3.1.0 + version: 3.3.3 + '@tailwindcss/postcss': + specifier: ^4.1.12 + version: 4.2.4 + '@types/mdx': + specifier: ^2.0.13 + version: 2.0.13 + '@types/node': + specifier: ^20.14.5 + version: 20.19.29 + '@types/react': + specifier: ^19.0.0 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.0.0 + version: 19.2.3(@types/react@19.2.14) + eslint: + specifier: 9.11.1 + version: 9.11.1(jiti@2.6.1) + eslint-config-next: + specifier: ^15.5.0 + version: 15.5.18(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3) + postcss: + specifier: ^8.5.3 + version: 8.5.6 + prettier: + specifier: ^3.3.3 + version: 3.8.0 + prettier-plugin-organize-imports: + specifier: ^4.2.0 + version: 4.3.0(prettier@3.8.0)(typescript@5.9.3) + prettier-plugin-tailwindcss: + specifier: ^0.6.14 + version: 0.6.14(prettier-plugin-organize-imports@4.3.0(prettier@3.8.0)(typescript@5.9.3))(prettier@3.8.0) + typescript: + specifier: ^5.5.3 + version: 5.9.3 + examples/example-app-router-playground: dependencies: '@radix-ui/react-dropdown-menu': @@ -1762,6 +1841,9 @@ packages: '@chevrotain/utils@11.0.3': resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==} + '@code-hike/lighter@1.0.1': + resolution: {integrity: sha512-mccvcsk5UTScRrE02oBz1/qzckyhD8YE3VQlQv++2bSVVZgNuCUX8MpokSCi5OmfRAAxbj6kmNiqq1Um8eXPrw==} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -3040,12 +3122,29 @@ packages: '@next/env@14.2.35': resolution: {integrity: sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==} + '@next/env@15.5.18': + resolution: {integrity: sha512-hAV85Ckd9QR6RvH04MEKwsfLTksvFpO47j9xwtoIuvuPnlwecpSi+uZTtm8HirVbtlI2Fnz//xpcSTjFdyJk+g==} + '@next/env@16.2.2': resolution: {integrity: sha512-LqSGz5+xGk9EL/iBDr2yo/CgNQV6cFsNhRR2xhSXYh7B/hb4nePCxlmDvGEKG30NMHDFf0raqSyOZiQrO7BkHQ==} + '@next/eslint-plugin-next@15.5.18': + resolution: {integrity: sha512-w4MYq8M26a8PNrfto0JosLf5/3ssln1rsyP96g2DkC8uFVymStM5DLSz5ElxxrPRg2XnTMnFo3kREFlhYvxhWw==} + '@next/eslint-plugin-next@16.2.2': resolution: {integrity: sha512-IOPbWzDQ+76AtjZioaCjpIY72xNSDMnarZ2GMQ4wjNLvnJEJHqxQwGFhgnIWLV9klb4g/+amg88Tk5OXVpyLTw==} + '@next/mdx@15.5.18': + resolution: {integrity: sha512-vslfcoGsX330qhcFMfksM2xPE1zCd5OGG4E47EBHH4asCG9l39CNoKv6X906kAgzvACHBKGcTxv1wlLVnagUjA==} + peerDependencies: + '@mdx-js/loader': '>=0.15.0' + '@mdx-js/react': '>=0.15.0' + peerDependenciesMeta: + '@mdx-js/loader': + optional: true + '@mdx-js/react': + optional: true + '@next/mdx@16.2.2': resolution: {integrity: sha512-2CbRTXE6sJ7zDAaKXknb5FrrPs46iJeMPzuoBXsAOV/XVnxABGD4mSDusn0VuCoII/KjUZ+zsuo2VFbchYQXng==} peerDependencies: @@ -3081,6 +3180,12 @@ packages: cpu: [arm64] os: [darwin] + '@next/swc-darwin-arm64@15.5.18': + resolution: {integrity: sha512-w0WvQf1n+txiwns/9pwIQteCJpZTbxzO2SE0FLcwuD4v0WEh1JPOjdyxWL21XwJsdpx8cFRjyzxzCS/siP7HcQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + '@next/swc-darwin-arm64@16.2.2': resolution: {integrity: sha512-B92G3ulrwmkDSEJEp9+XzGLex5wC1knrmCSIylyVeiAtCIfvEJYiN3v5kXPlYt5R4RFlsfO/v++aKV63Acrugg==} engines: {node: '>= 10'} @@ -3099,6 +3204,12 @@ packages: cpu: [x64] os: [darwin] + '@next/swc-darwin-x64@15.5.18': + resolution: {integrity: sha512-znn71QmDuxm+BOaglihMZfvyySMnNljkVIY5Z2TCssBmm+WqL6c19VhtH5ktFkHa8EZ2bnTUpcNcmNSQsg67og==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + '@next/swc-darwin-x64@16.2.2': resolution: {integrity: sha512-7ZwSgNKJNQiwW0CKhNm9B1WS2L1Olc4B2XY0hPYCAL3epFnugMhuw5TMWzMilQ3QCZcCHoYm9NGWTHbr5REFxw==} engines: {node: '>= 10'} @@ -3129,6 +3240,12 @@ packages: cpu: [arm64] os: [linux] + '@next/swc-linux-arm64-gnu@15.5.18': + resolution: {integrity: sha512-yPPe5MNL+igZUa+OsqQJisqSfh6oarIuA1Q0BDxljGJhRQyZeP+WRHh7rs/jZUGMh5aY0YdIjXZG0VohkKkUdw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + '@next/swc-linux-arm64-gnu@16.2.2': resolution: {integrity: sha512-c3m8kBHMziMgo2fICOP/cd/5YlrxDU5YYjAJeQLyFsCqVF8xjOTH/QYG4a2u48CvvZZSj1eHQfBCbyh7kBr30Q==} engines: {node: '>= 10'} @@ -3147,6 +3264,12 @@ packages: cpu: [arm64] os: [linux] + '@next/swc-linux-arm64-musl@15.5.18': + resolution: {integrity: sha512-glaCczEWIrHsokFZ3pP08U4BpKxwIdnT+txdOM32OBgpL9Yw4aqx8NejmgtZQZOdstQ5f0L3CasIZudzCuD+nw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + '@next/swc-linux-arm64-musl@16.2.2': resolution: {integrity: sha512-VKLuscm0P/mIfzt+SDdn2+8TNNJ7f0qfEkA+az7OqQbjzKdBxAHs0UvuiVoCtbwX+dqMEL9U54b5wQ/aN3dHeg==} engines: {node: '>= 10'} @@ -3165,6 +3288,12 @@ packages: cpu: [x64] os: [linux] + '@next/swc-linux-x64-gnu@15.5.18': + resolution: {integrity: sha512-oUfg2EgJmU3R0OCOWiokGFUTvZiPfXtriXiuF3YNxRoROCdgvTedHIzYoeKH34gsZxS/V7mHbfq2hpAHwhH1/A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + '@next/swc-linux-x64-gnu@16.2.2': resolution: {integrity: sha512-kU3OPHJq6sBUjOk7wc5zJ7/lipn8yGldMoAv4z67j6ov6Xo/JvzA7L7LCsyzzsXmgLEhk3Qkpwqaq/1+XpNR3g==} engines: {node: '>= 10'} @@ -3183,6 +3312,12 @@ packages: cpu: [x64] os: [linux] + '@next/swc-linux-x64-musl@15.5.18': + resolution: {integrity: sha512-JLxSP3KTd9iu/bvUMQxH7RJo9xKSHf55/6RPE4a6FTSZygGn7uvZbCej0AHXydwkggQGSD9UddSjwv6Xz5ESfA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + '@next/swc-linux-x64-musl@16.2.2': resolution: {integrity: sha512-CKXRILyErMtUftp+coGcZ38ZwE/Aqq45VMCcRLr2I4OXKrgxIBDXHnBgeX/UMil0S09i2JXaDL3Q+TN8D/cKmg==} engines: {node: '>= 10'} @@ -3201,6 +3336,12 @@ packages: cpu: [arm64] os: [win32] + '@next/swc-win32-arm64-msvc@15.5.18': + resolution: {integrity: sha512-ir1v7enP52K2HNz3tQQvwF+x7VNxBk1ciiZ18WBPvxf4C59IqdfmHPJYK3vH7rSxpuCVw/8C712wTXNAtEp+NA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + '@next/swc-win32-arm64-msvc@16.2.2': resolution: {integrity: sha512-sS/jSk5VUoShUqINJFvNjVT7JfR5ORYj/+/ZpOYbbIohv/lQfduWnGAycq2wlknbOql2xOR0DoV0s6Xfcy49+g==} engines: {node: '>= 10'} @@ -3231,6 +3372,12 @@ packages: cpu: [x64] os: [win32] + '@next/swc-win32-x64-msvc@15.5.18': + resolution: {integrity: sha512-LIu5me6QTANCd25E7I5uIEfvgQ06RK7tvHAbYo3zCb3VpxQEPvMcSpd87NwUABDT6MbGPdEGR5VRiK4PPTJhQg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + '@next/swc-win32-x64-msvc@16.2.2': resolution: {integrity: sha512-aHaKceJgdySReT7qeck5oShucxWRiiEuwCGK8HHALe6yZga8uyFpLkPgaRw3kkF04U7ROogL/suYCNt/+CuXGA==} engines: {node: '>= 10'} @@ -4048,6 +4195,9 @@ packages: '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@rushstack/eslint-patch@1.16.1': + resolution: {integrity: sha512-TvZbIpeKqGQQ7X0zSCvPH9riMSFQFSggnfBjFZ1mEoILW+UuXCKwOoPcgjMwiUtRqFZ8jWhPJc4um14vC6I4ag==} + '@schummar/icu-type-parser@1.21.5': resolution: {integrity: sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==} @@ -5351,6 +5501,9 @@ packages: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} + ansi-sequence-parser@1.1.1: + resolution: {integrity: sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==} + ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -5905,6 +6058,9 @@ packages: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + codehike@1.1.0: + resolution: {integrity: sha512-hOxqmTHjiOxhlcVEuDTCoAQ8TW358HVrNKlOwuKcnbwkuTpbGtwj5TnQ7AZjnZiQvJ3LeXohrd1E7qfYYN0Rdg==} + collapse-white-space@2.1.0: resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} @@ -6514,6 +6670,10 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + diff@5.2.2: + resolution: {integrity: sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==} + engines: {node: '>=0.3.1'} + diffie-hellman@5.0.3: resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} @@ -6763,6 +6923,15 @@ packages: peerDependencies: eslint: ^9.0.0 + eslint-config-next@15.5.18: + resolution: {integrity: sha512-HuoJU6uUPD00eyiud78IBnT4HLhztFj2V+ild2Uon5ZUrYZKe0Olu2QRD99e9IgL4/H1eg5Onka3BsfRW2U0Xw==} + peerDependencies: + eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + eslint-config-next@16.2.2: resolution: {integrity: sha512-6VlvEhwoug2JpVgjZDhyXrJXUEuPY++TddzIpTaIRvlvlXXFgvQUtm3+Zr84IjFm0lXtJt73w19JA08tOaZVwg==} peerDependencies: @@ -8614,6 +8783,11 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lucide-react@0.545.0: + resolution: {integrity: sha512-7r1/yUuflQDSt4f1bpn5ZAocyIxcTyVyBBChSVtBKn5M+392cPmI5YJMWOJKk/HUWGm5wg83chlAZtCcGbEZtw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -9158,6 +9332,27 @@ packages: sass: optional: true + next@15.5.18: + resolution: {integrity: sha512-eKL8zUJkX9Y5lE+RX/2YJoItVdGlIscyVyboeD9wSpp0PaGqjoA4tTpT2qPqz9ax+5IzGESyLSeZ/RCwbSZ2uQ==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.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 + next@16.2.2: resolution: {integrity: sha512-i6AJdyVa4oQjyvX/6GeER8dpY/xlIV+4NMv/svykcLtURJSy/WzDnnUk/TM4d0uewFHK7xSQz4TbIwPgjky+3A==} engines: {node: '>=20.9.0'} @@ -9785,6 +9980,77 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prettier-plugin-organize-imports@4.3.0: + resolution: {integrity: sha512-FxFz0qFhyBsGdIsb697f/EkvHzi5SZOhWAjxcx2dLt+Q532bAlhswcXGYB1yzjZ69kW8UoadFBw7TyNwlq96Iw==} + peerDependencies: + prettier: '>=2.0' + typescript: '>=2.9' + vue-tsc: ^2.1.0 || 3 + peerDependenciesMeta: + vue-tsc: + optional: true + + prettier-plugin-tailwindcss@0.6.14: + resolution: {integrity: sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==} + engines: {node: '>=14.21.3'} + peerDependencies: + '@ianvs/prettier-plugin-sort-imports': '*' + '@prettier/plugin-hermes': '*' + '@prettier/plugin-oxc': '*' + '@prettier/plugin-pug': '*' + '@shopify/prettier-plugin-liquid': '*' + '@trivago/prettier-plugin-sort-imports': '*' + '@zackad/prettier-plugin-twig': '*' + prettier: ^3.0 + prettier-plugin-astro: '*' + prettier-plugin-css-order: '*' + prettier-plugin-import-sort: '*' + prettier-plugin-jsdoc: '*' + prettier-plugin-marko: '*' + prettier-plugin-multiline-arrays: '*' + prettier-plugin-organize-attributes: '*' + prettier-plugin-organize-imports: '*' + prettier-plugin-sort-imports: '*' + prettier-plugin-style-order: '*' + prettier-plugin-svelte: '*' + peerDependenciesMeta: + '@ianvs/prettier-plugin-sort-imports': + optional: true + '@prettier/plugin-hermes': + optional: true + '@prettier/plugin-oxc': + optional: true + '@prettier/plugin-pug': + optional: true + '@shopify/prettier-plugin-liquid': + optional: true + '@trivago/prettier-plugin-sort-imports': + optional: true + '@zackad/prettier-plugin-twig': + optional: true + prettier-plugin-astro: + optional: true + prettier-plugin-css-order: + optional: true + prettier-plugin-import-sort: + optional: true + prettier-plugin-jsdoc: + optional: true + prettier-plugin-marko: + optional: true + prettier-plugin-multiline-arrays: + optional: true + prettier-plugin-organize-attributes: + optional: true + prettier-plugin-organize-imports: + optional: true + prettier-plugin-sort-imports: + optional: true + prettier-plugin-style-order: + optional: true + prettier-plugin-svelte: + optional: true + prettier@3.8.0: resolution: {integrity: sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==} engines: {node: '>=14'} @@ -13041,6 +13307,10 @@ snapshots: '@chevrotain/utils@11.0.3': {} + '@code-hike/lighter@1.0.1': + dependencies: + ansi-sequence-parser: 1.1.1 + '@colors/colors@1.5.0': optional: true @@ -14324,6 +14594,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@mdx-js/loader@3.1.1(webpack@5.104.1)': + dependencies: + '@mdx-js/mdx': 3.0.1 + source-map: 0.7.4 + optionalDependencies: + webpack: 5.104.1 + transitivePeerDependencies: + - supports-color + '@mdx-js/mdx@3.0.1': dependencies: '@types/estree': 1.0.8 @@ -14477,12 +14756,25 @@ snapshots: '@next/env@14.2.35': {} + '@next/env@15.5.18': {} + '@next/env@16.2.2': {} + '@next/eslint-plugin-next@15.5.18': + dependencies: + fast-glob: 3.3.1 + '@next/eslint-plugin-next@16.2.2': dependencies: fast-glob: 3.3.1 + '@next/mdx@15.5.18(@mdx-js/loader@3.1.1(webpack@5.104.1))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.3))': + dependencies: + source-map: 0.7.6 + optionalDependencies: + '@mdx-js/loader': 3.1.1(webpack@5.104.1) + '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.3) + '@next/mdx@16.2.2(@mdx-js/loader@3.1.1(webpack@5.104.1(esbuild@0.25.1)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.3))': dependencies: source-map: 0.7.6 @@ -14502,6 +14794,9 @@ snapshots: '@next/swc-darwin-arm64@14.2.33': optional: true + '@next/swc-darwin-arm64@15.5.18': + optional: true + '@next/swc-darwin-arm64@16.2.2': optional: true @@ -14511,6 +14806,9 @@ snapshots: '@next/swc-darwin-x64@14.2.33': optional: true + '@next/swc-darwin-x64@15.5.18': + optional: true + '@next/swc-darwin-x64@16.2.2': optional: true @@ -14526,6 +14824,9 @@ snapshots: '@next/swc-linux-arm64-gnu@14.2.33': optional: true + '@next/swc-linux-arm64-gnu@15.5.18': + optional: true + '@next/swc-linux-arm64-gnu@16.2.2': optional: true @@ -14535,6 +14836,9 @@ snapshots: '@next/swc-linux-arm64-musl@14.2.33': optional: true + '@next/swc-linux-arm64-musl@15.5.18': + optional: true + '@next/swc-linux-arm64-musl@16.2.2': optional: true @@ -14544,6 +14848,9 @@ snapshots: '@next/swc-linux-x64-gnu@14.2.33': optional: true + '@next/swc-linux-x64-gnu@15.5.18': + optional: true + '@next/swc-linux-x64-gnu@16.2.2': optional: true @@ -14553,6 +14860,9 @@ snapshots: '@next/swc-linux-x64-musl@14.2.33': optional: true + '@next/swc-linux-x64-musl@15.5.18': + optional: true + '@next/swc-linux-x64-musl@16.2.2': optional: true @@ -14562,6 +14872,9 @@ snapshots: '@next/swc-win32-arm64-msvc@14.2.33': optional: true + '@next/swc-win32-arm64-msvc@15.5.18': + optional: true + '@next/swc-win32-arm64-msvc@16.2.2': optional: true @@ -14577,6 +14890,9 @@ snapshots: '@next/swc-win32-x64-msvc@14.2.33': optional: true + '@next/swc-win32-x64-msvc@15.5.18': + optional: true + '@next/swc-win32-x64-msvc@16.2.2': optional: true @@ -15424,6 +15740,8 @@ snapshots: '@rtsao/scc@1.1.0': {} + '@rushstack/eslint-patch@1.16.1': {} + '@schummar/icu-type-parser@1.21.5': {} '@sec-ant/readable-stream@0.4.1': {} @@ -16487,6 +16805,22 @@ snapshots: - supports-color optional: true + '@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/type-utils': 8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.53.0 + eslint: 9.11.1(jiti@2.6.1) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@6.0.2))(eslint@9.11.1(jiti@2.6.1))(typescript@6.0.2)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -16569,6 +16903,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.53.0 + debug: 4.4.3 + eslint: 9.11.1(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@6.0.2)': dependencies: '@typescript-eslint/scope-manager': 8.53.0 @@ -16613,6 +16959,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.53.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.53.0(typescript@5.9.3) + '@typescript-eslint/types': 8.53.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/project-service@8.53.0(typescript@6.0.2)': dependencies: '@typescript-eslint/tsconfig-utils': 8.53.0(typescript@6.0.2) @@ -16632,7 +16987,6 @@ snapshots: dependencies: '@typescript-eslint/types': 8.53.0 '@typescript-eslint/visitor-keys': 8.53.0 - optional: true '@typescript-eslint/tsconfig-utils@8.46.2(typescript@5.9.3)': dependencies: @@ -16642,6 +16996,10 @@ snapshots: dependencies: typescript: 6.0.2 + '@typescript-eslint/tsconfig-utils@8.53.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@typescript-eslint/tsconfig-utils@8.53.0(typescript@6.0.2)': dependencies: typescript: 6.0.2 @@ -16708,6 +17066,18 @@ snapshots: - supports-color optional: true + '@typescript-eslint/type-utils@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.11.1(jiti@2.6.1) + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/type-utils@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@6.0.2)': dependencies: '@typescript-eslint/types': 8.53.0 @@ -16736,8 +17106,7 @@ snapshots: '@typescript-eslint/types@8.46.2': {} - '@typescript-eslint/types@8.53.0': - optional: true + '@typescript-eslint/types@8.53.0': {} '@typescript-eslint/typescript-estree@8.46.2(typescript@5.9.3)': dependencies: @@ -16771,6 +17140,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@8.53.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.53.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.53.0(typescript@5.9.3) + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/visitor-keys': 8.53.0 + debug: 4.4.3 + minimatch: 9.0.5 + semver: 7.7.3 + tinyglobby: 0.2.15 + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/typescript-estree@8.53.0(typescript@6.0.2)': dependencies: '@typescript-eslint/project-service': 8.53.0(typescript@6.0.2) @@ -16843,6 +17227,17 @@ snapshots: - supports-color optional: true + '@typescript-eslint/utils@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.11.1(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) + eslint: 9.11.1(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@6.0.2)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.11.1(jiti@2.6.1)) @@ -16876,7 +17271,6 @@ snapshots: dependencies: '@typescript-eslint/types': 8.53.0 eslint-visitor-keys: 4.2.1 - optional: true '@typescript/vfs@1.6.2(typescript@6.0.2)': dependencies: @@ -17327,6 +17721,8 @@ snapshots: ansi-regex@6.2.2: {} + ansi-sequence-parser@1.1.1: {} + ansi-styles@3.2.1: dependencies: color-convert: 1.9.3 @@ -18009,6 +18405,16 @@ snapshots: co@4.6.0: {} + codehike@1.1.0: + dependencies: + '@code-hike/lighter': 1.0.1 + diff: 5.2.2 + estree-util-visit: 2.0.0 + mdast-util-mdx-jsx: 3.2.0 + unist-util-visit: 5.0.0 + transitivePeerDependencies: + - supports-color + collapse-white-space@2.1.0: {} collect-v8-coverage@1.0.3: {} @@ -18667,6 +19073,8 @@ snapshots: diff-sequences@29.6.3: {} + diff@5.2.2: {} + diffie-hellman@5.0.3: dependencies: bn.js: 4.12.1 @@ -19140,6 +19548,26 @@ snapshots: - typescript - vitest + eslint-config-next@15.5.18(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@next/eslint-plugin-next': 15.5.18 + '@rushstack/eslint-patch': 1.16.1 + '@typescript-eslint/eslint-plugin': 8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.11.1(jiti@2.6.1) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0)(eslint@9.11.1(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.11.1(jiti@2.6.1)) + eslint-plugin-jsx-a11y: 6.10.0(eslint@9.11.1(jiti@2.6.1)) + eslint-plugin-react: 7.37.1(eslint@9.11.1(jiti@2.6.1)) + eslint-plugin-react-hooks: 5.0.0(eslint@9.11.1(jiti@2.6.1)) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + eslint-config-next@16.2.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: '@next/eslint-plugin-next': 16.2.2 @@ -19207,6 +19635,25 @@ snapshots: - eslint-import-resolver-webpack - supports-color + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0)(eslint@9.11.1(jiti@2.6.1)): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.3 + enhanced-resolve: 5.18.1 + eslint: 9.11.1(jiti@2.6.1) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0)(eslint@9.11.1(jiti@2.6.1)))(eslint@9.11.1(jiti@2.6.1)) + fast-glob: 3.3.3 + get-tsconfig: 4.7.5 + is-bun-module: 1.2.1 + is-glob: 4.0.3 + optionalDependencies: + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.11.1(jiti@2.6.1)) + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-node + - eslint-import-resolver-webpack + - supports-color + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@6.0.2))(eslint-plugin-import@2.32.0)(eslint@9.11.1(jiti@2.6.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 @@ -19275,6 +19722,17 @@ snapshots: transitivePeerDependencies: - supports-color + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0)(eslint@9.11.1(jiti@2.6.1)))(eslint@9.11.1(jiti@2.6.1)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.11.1(jiti@2.6.1) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0)(eslint@9.11.1(jiti@2.6.1)) + transitivePeerDependencies: + - supports-color + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@6.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@6.0.2))(eslint-plugin-import@2.32.0)(eslint@9.11.1(jiti@2.6.1)))(eslint@9.11.1(jiti@2.6.1)): dependencies: debug: 3.2.7 @@ -19354,6 +19812,35 @@ snapshots: - eslint-import-resolver-webpack - supports-color + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.6.3)(eslint@9.11.1(jiti@2.6.1)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.11.1(jiti@2.6.1) + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0)(eslint@9.11.1(jiti@2.6.1)))(eslint@9.11.1(jiti@2.6.1)) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@5.9.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.11.1(jiti@2.6.1))(typescript@6.0.2))(eslint-import-resolver-typescript@3.6.3)(eslint@9.11.1(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 @@ -20599,7 +21086,7 @@ snapshots: estree-util-is-identifier-name: 3.0.0 hast-util-whitespace: 3.0.0 mdast-util-mdx-expression: 2.0.1 - mdast-util-mdx-jsx: 3.1.3 + mdast-util-mdx-jsx: 3.2.0 mdast-util-mdxjs-esm: 2.0.1 property-information: 6.5.0 space-separated-tokens: 2.0.2 @@ -22230,6 +22717,10 @@ snapshots: dependencies: yallist: 3.1.1 + lucide-react@0.545.0(react@19.2.3): + dependencies: + react: 19.2.3 + lz-string@1.5.0: {} magic-string@0.30.10: @@ -23116,6 +23607,11 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + next-themes@0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + next-validate-link@1.6.4: dependencies: gray-matter: 4.0.3 @@ -23183,6 +23679,31 @@ snapshots: - '@babel/core' - babel-plugin-macros + next@15.5.18(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + '@next/env': 15.5.18 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001764 + 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': 15.5.18 + '@next/swc-darwin-x64': 15.5.18 + '@next/swc-linux-arm64-gnu': 15.5.18 + '@next/swc-linux-arm64-musl': 15.5.18 + '@next/swc-linux-x64-gnu': 15.5.18 + '@next/swc-linux-x64-musl': 15.5.18 + '@next/swc-win32-arm64-msvc': 15.5.18 + '@next/swc-win32-x64-msvc': 15.5.18 + '@opentelemetry/api': 1.9.0 + '@playwright/test': 1.57.0 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + next@16.2.2(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: '@next/env': 16.2.2 @@ -23955,6 +24476,17 @@ snapshots: prelude-ls@1.2.1: {} + prettier-plugin-organize-imports@4.3.0(prettier@3.8.0)(typescript@5.9.3): + dependencies: + prettier: 3.8.0 + typescript: 5.9.3 + + prettier-plugin-tailwindcss@0.6.14(prettier-plugin-organize-imports@4.3.0(prettier@3.8.0)(typescript@5.9.3))(prettier@3.8.0): + dependencies: + prettier: 3.8.0 + optionalDependencies: + prettier-plugin-organize-imports: 4.3.0(prettier@3.8.0)(typescript@5.9.3) + prettier@3.8.0: {} pretty-error@4.0.0: @@ -25455,6 +25987,16 @@ snapshots: optionalDependencies: esbuild: 0.25.1 + terser-webpack-plugin@5.3.16(webpack@5.104.1): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + jest-worker: 27.5.1 + schema-utils: 4.3.3 + serialize-javascript: 6.0.2 + terser: 5.45.0 + webpack: 5.104.1 + optional: true + terser@5.36.0: dependencies: '@jridgewell/source-map': 0.3.6 @@ -25594,6 +26136,10 @@ snapshots: dependencies: typescript: 6.0.2 + ts-api-utils@2.4.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + ts-api-utils@2.4.0(typescript@6.0.2): dependencies: typescript: 6.0.2 @@ -26521,6 +27067,39 @@ snapshots: - uglify-js optional: true + webpack@5.104.1: + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.15.0 + acorn-import-phases: 1.0.4(acorn@8.15.0) + browserslist: 4.28.1 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.18.4 + es-module-lexer: 2.0.0 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.1 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 4.3.3 + tapable: 2.3.0 + terser-webpack-plugin: 5.3.16(webpack@5.104.1) + watchpack: 2.5.1 + webpack-sources: 3.3.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + optional: true + webpack@5.104.1(esbuild@0.25.1): dependencies: '@types/eslint-scope': 3.7.7 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 75b9196a5..422c835aa 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,3 +4,4 @@ packages: - 'e2e/*' - 'docs' - 'tools' + - 'playground' \ No newline at end of file