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.
+
+[](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 (
+ <>
+
+
+ >
+ );
+}
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 (
+
+
+ {t('label')}
+
+
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 (
+
+ );
+}
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 (
+
+ );
+}
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
+
+
+
+
+
+
+ setIsOpen(!isOpen)}
+ aria-expanded={isOpen}
+ aria-controls="playground-nav"
+ aria-label={isOpen ? 'Close navigation' : 'Open navigation'}
+ className="text-muted-foreground hover:bg-muted hover:text-foreground flex size-8 items-center justify-center rounded-md transition-colors lg:hidden"
+ >
+ {isOpen ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+ {sections.map((section) => {
+ const Icon = section.icon;
+ return (
+
+
+
+ {t(section.titleKey)}
+
+
+ {section.items.map((item) => {
+ const active = pathname === item.slug;
+ return (
+
+ {active && (
+
+ )}
+
+ {t(item.titleKey)}
+
+
+
+ );
+ })}
+
+
+ );
+ })}
+
+
+
+ );
+}
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 (
+ setTheme(isDark ? 'light' : 'dark')}
+ aria-label={isDark ? 'Switch to light theme' : 'Switch to dark theme'}
+ className="text-muted-foreground hover:bg-muted hover:text-foreground flex size-8 items-center justify-center rounded-md transition-colors"
+ >
+ {isDark ? (
+
+ ) : (
+
+ )}
+
+ );
+}
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