From df238dcebb5aa748c41726c36876f53b8bb975af Mon Sep 17 00:00:00 2001 From: Cypher-Aura-19 Date: Mon, 27 Jul 2026 17:35:04 +0500 Subject: [PATCH 1/2] feat(examples): add interactive Next.js App Router example --- README.md | 9 + examples/nextjs-app-router/.gitignore | 4 + examples/nextjs-app-router/README.md | 30 + examples/nextjs-app-router/next-env.d.ts | 6 + examples/nextjs-app-router/next.config.ts | 7 + examples/nextjs-app-router/package.json | 23 + examples/nextjs-app-router/pnpm-lock.yaml | 923 ++++++++++++++++++ .../nextjs-app-router/pnpm-workspace.yaml | 3 + .../app/email-preview/PreviewDashboard.tsx | 308 ++++++ .../src/app/email-preview/page.tsx | 27 + .../src/app/email-preview/raw/route.ts | 18 + examples/nextjs-app-router/src/app/layout.tsx | 24 + examples/nextjs-app-router/src/app/page.tsx | 26 + .../src/emails/welcome-email.tsx | 172 ++++ .../src/utils/render-server.ts | 34 + examples/nextjs-app-router/tsconfig.json | 21 + pnpm-workspace.yaml | 1 + 17 files changed, 1636 insertions(+) create mode 100644 examples/nextjs-app-router/.gitignore create mode 100644 examples/nextjs-app-router/README.md create mode 100644 examples/nextjs-app-router/next-env.d.ts create mode 100644 examples/nextjs-app-router/next.config.ts create mode 100644 examples/nextjs-app-router/package.json create mode 100644 examples/nextjs-app-router/pnpm-lock.yaml create mode 100644 examples/nextjs-app-router/pnpm-workspace.yaml create mode 100644 examples/nextjs-app-router/src/app/email-preview/PreviewDashboard.tsx create mode 100644 examples/nextjs-app-router/src/app/email-preview/page.tsx create mode 100644 examples/nextjs-app-router/src/app/email-preview/raw/route.ts create mode 100644 examples/nextjs-app-router/src/app/layout.tsx create mode 100644 examples/nextjs-app-router/src/app/page.tsx create mode 100644 examples/nextjs-app-router/src/emails/welcome-email.tsx create mode 100644 examples/nextjs-app-router/src/utils/render-server.ts create mode 100644 examples/nextjs-app-router/tsconfig.json diff --git a/README.md b/README.md index 0e941e69..e5d26a91 100644 --- a/README.md +++ b/README.md @@ -216,8 +216,17 @@ For the full API reference, component props, design patterns, and common mistake | [`@unlayer-internal/shared-elements`](./packages/shared) | Framework-agnostic shared logic | Internal | | [`@unlayer/elements-demo`](./packages/demo) | Demo application | — | +## Examples + +Runnable projects you can clone and experiment with: + +| Example | Description | +|---------|-------------| +| [`examples/nextjs-app-router`](./examples/nextjs-app-router) | Next.js 15 App Router — renders an email with `renderToHtml()` in a Server Component, previews it at `/email-preview`, and serves the raw HTML from a Route Handler | + ## Development + ```bash # Prerequisites: Node.js (see .nvmrc), pnpm 9+ diff --git a/examples/nextjs-app-router/.gitignore b/examples/nextjs-app-router/.gitignore new file mode 100644 index 00000000..c3a54e7a --- /dev/null +++ b/examples/nextjs-app-router/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +.next/ +package-lock.json +tsconfig.tsbuildinfo diff --git a/examples/nextjs-app-router/README.md b/examples/nextjs-app-router/README.md new file mode 100644 index 00000000..229f321d --- /dev/null +++ b/examples/nextjs-app-router/README.md @@ -0,0 +1,30 @@ +# Next.js App Router Example + +Renders an Unlayer Elements email to HTML inside a Next.js 15 App Router **Server Component**, then previews it in the browser. + +## Run it + +From this directory: + +```bash +pnpm install +pnpm dev +``` + +Then open: + +- — the email rendered in an interactive preview dashboard (Desktop/Mobile view toggles, Raw HTML / Plain Text view) +- — the raw HTML string, served as `text/html` from a Route Handler + +## Architecture + +| File | Purpose | +|------|---------| +| `src/emails/welcome-email.tsx` | A realistic transactional email as a plain component tree, parameterized by props | +| `src/app/email-preview/page.tsx` | A Server Component calling `renderToHtml()` and `renderToPlainText()`, passing the strings to the client-side layout | +| `src/app/email-preview/PreviewDashboard.tsx` | Client-side dashboard layout managing viewport resizing, copy to clipboard, and tab switching | +| `src/app/email-preview/raw/route.ts` | A Route Handler returning the rendered HTML — the shape production code usually takes | + +### Note on Server Components + +The template components and `renderToHtml()` function run completely on the server. The component tree is never shipped to the browser; only the resulting HTML/plain-text strings are. diff --git a/examples/nextjs-app-router/next-env.d.ts b/examples/nextjs-app-router/next-env.d.ts new file mode 100644 index 00000000..830fb594 --- /dev/null +++ b/examples/nextjs-app-router/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/nextjs-app-router/next.config.ts b/examples/nextjs-app-router/next.config.ts new file mode 100644 index 00000000..b5fcf027 --- /dev/null +++ b/examples/nextjs-app-router/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + serverExternalPackages: ["@unlayer/react-elements"], +}; + +export default nextConfig; diff --git a/examples/nextjs-app-router/package.json b/examples/nextjs-app-router/package.json new file mode 100644 index 00000000..216ec99d --- /dev/null +++ b/examples/nextjs-app-router/package.json @@ -0,0 +1,23 @@ +{ + "name": "@unlayer/example-nextjs-app-router", + "version": "0.0.0", + "private": true, + "description": "Next.js App Router example rendering an Elements email with renderToHtml()", + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "@unlayer/react-elements": "^0.1.20", + "next": "15.5.3", + "react": "19.1.0", + "react-dom": "19.1.0" + }, + "devDependencies": { + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "typescript": "^5" + } +} diff --git a/examples/nextjs-app-router/pnpm-lock.yaml b/examples/nextjs-app-router/pnpm-lock.yaml new file mode 100644 index 00000000..785c4979 --- /dev/null +++ b/examples/nextjs-app-router/pnpm-lock.yaml @@ -0,0 +1,923 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@unlayer/react-elements': + specifier: ^0.1.20 + version: 0.1.20(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.9.3) + next: + specifier: 15.5.3 + version: 15.5.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: + specifier: 19.1.0 + version: 19.1.0 + react-dom: + specifier: 19.1.0 + version: 19.1.0(react@19.1.0) + devDependencies: + '@types/node': + specifier: ^20 + version: 20.19.43 + '@types/react': + specifier: ^19 + version: 19.2.17 + '@types/react-dom': + specifier: ^19 + version: 19.2.3(@types/react@19.2.17) + typescript: + specifier: ^5 + version: 5.9.3 + +packages: + + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@lexical/clipboard@0.48.0': + resolution: {integrity: sha512-xO2trk6+yBl8XXa/VNe20kXczmPxFoWtUHjidbBLEtlGBj+mo63pJj6H5o/WlZsoMKmIOJxwxsn2ejrS8G0/7A==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/dragon@0.48.0': + resolution: {integrity: sha512-uPuu7fVca9vmL/Oz30CRZ7FIPIodwMrTgNsRmV8jE6Qd6a7RNiTW7r3+EhbhIdkLb/sjcWsYyOMyUR1TJAB0wQ==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/extension@0.48.0': + resolution: {integrity: sha512-4uBObgz84mVbQWiumndmIhkuJL0ojHiMwFSvSUM/FCo1YMVIZvpI56blI0y+2Vix/oLui9EgVQSJjjWV4NAszw==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/headless@0.48.0': + resolution: {integrity: sha512-GvSFcmsRU4whY/ctyAxFV2MuYKIDt5w951GDS4QtV9R0iZLnZcVmr/Fd7DV23BX+DJt4sdfuGAEbDIPBxWJPWA==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/html@0.48.0': + resolution: {integrity: sha512-uBxlgKl4YgSNEgHJSshdBqtGDzruWdx1ewop+u6faT67qHUdP3P0cUXIrG6NToDWvsL6fzCstAbN76PMER1Pnw==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/internal@0.48.0': + resolution: {integrity: sha512-sRwg53K7N0ZQ7KNAvcCY38LSwGizbXP1zlR1lIojZp0GoqHWNvR+vL49t1wYXu1nXx3Osf4ilHHm+aGcwq5hTw==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/link@0.48.0': + resolution: {integrity: sha512-E0UDmNLUXs/yMCnnE7hbFO0CvhWghmqa+qqPksFfzLkpMHdPpdS1yg59YEbYoNHLi/DXIu4cFRvpHIEuooxwNg==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/list@0.48.0': + resolution: {integrity: sha512-9Qe/Vur44v9F9enj55SUzf79FVsijcGOQug7SpiIU8ekLr7JNzcilKYBYcZ6etGEo7bqQHsYMHXeJcSBbCI2zA==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/rich-text@0.48.0': + resolution: {integrity: sha512-QMXFnwCKAQ4yzxvx5FwmANcx3K+NaBkGTxAVD8s8pOKDD/U5rzDS1iIvhH6TLWaFp7VzvLmLB+Sl1Ie/RnkaDQ==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/selection@0.48.0': + resolution: {integrity: sha512-Uc0wTrEtHcYK6z/aHHjkgH3vX/R4Bf8mO+qH3VbxfSAKYzNYktM0j+ZGdq5kIEL4frnw/9SulNCXlH7xpjuDgA==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/utils@0.48.0': + resolution: {integrity: sha512-W4k4P+y6jmRfna8+ad4X+iMd5h8es5PC3bUw5tbi7MRApxaaFG/0w+uJiZVSwbT2Q6JnA2xhBaqzPgt/Gn6djg==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@next/env@15.5.3': + resolution: {integrity: sha512-RSEDTRqyihYXygx/OJXwvVupfr9m04+0vH8vyy0HfZ7keRto6VX9BbEk0J2PUk0VGy6YhklJUSrgForov5F9pw==} + + '@next/swc-darwin-arm64@15.5.3': + resolution: {integrity: sha512-nzbHQo69+au9wJkGKTU9lP7PXv0d1J5ljFpvb+LnEomLtSbJkbZyEs6sbF3plQmiOB2l9OBtN2tNSvCH1nQ9Jg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@15.5.3': + resolution: {integrity: sha512-w83w4SkOOhekJOcA5HBvHyGzgV1W/XvOfpkrxIse4uPWhYTTRwtGEM4v/jiXwNSJvfRvah0H8/uTLBKRXlef8g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@15.5.3': + resolution: {integrity: sha512-+m7pfIs0/yvgVu26ieaKrifV8C8yiLe7jVp9SpcIzg7XmyyNE7toC1fy5IOQozmr6kWl/JONC51osih2RyoXRw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-musl@15.5.3': + resolution: {integrity: sha512-u3PEIzuguSenoZviZJahNLgCexGFhso5mxWCrrIMdvpZn6lkME5vc/ADZG8UUk5K1uWRy4hqSFECrON6UKQBbQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@next/swc-linux-x64-gnu@15.5.3': + resolution: {integrity: sha512-lDtOOScYDZxI2BENN9m0pfVPJDSuUkAD1YXSvlJF0DKwZt0WlA7T7o3wrcEr4Q+iHYGzEaVuZcsIbCps4K27sA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-musl@15.5.3': + resolution: {integrity: sha512-9vWVUnsx9PrY2NwdVRJ4dUURAQ8Su0sLRPqcCCxtX5zIQUBES12eRVHq6b70bbfaVaxIDGJN2afHui0eDm+cLg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@next/swc-win32-arm64-msvc@15.5.3': + resolution: {integrity: sha512-1CU20FZzY9LFQigRi6jM45oJMU3KziA5/sSG+dXeVaTm661snQP6xu3ykGxxwU5sLG3sh14teO/IOEPVsQMRfA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@15.5.3': + resolution: {integrity: sha512-JMoLAq3n3y5tKXPQwCK5c+6tmwkuFDa2XAxz8Wm4+IVthdBZdZGh+lmiLUHg9f9IDwIQpUjp+ysd6OkYTyZRZw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@preact/signals-core@1.14.4': + resolution: {integrity: sha512-HNB6HYeYKhQbJ1aKl+YRjrS4+QWHLKX6qKoUsfS/m0vqzsVaEBiZiaKbG/e+NKk2ch5ALQr/ihWaMHxiCuuWHA==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@types/node@20.19.43': + resolution: {integrity: sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.17': + resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/whatwg-mimetype@3.0.2': + resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} + + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + + '@unlayer/exporters@1.455.0': + resolution: {integrity: sha512-IJUQmrGlBig6OyRURkTeXm3sSD/leYD86kwzhJB4EgodUTty67yxjkS+Nyu6C+SRU4EwdfdiFswxNxtw4ttuMw==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@unlayer/types': '>=1.455.0' + + '@unlayer/react-elements@0.1.20': + resolution: {integrity: sha512-jhI5/IozTUcEg7U/W7i3UL/Gk2xzEs/wqN2OaJ2IGnjKGT7mC5f3MSVRWZgaJiYvqqbrkEn7K6KwwAZ3Zf45Yw==} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + '@unlayer/types@1.455.0': + resolution: {integrity: sha512-WHRNCpErzixSENMVqy8oyXA9l091iu3WJpl/sGlQfV64r86b/WNjBgc7vG2uT3/XOWS0AynGT0Kn+aJjsdAR6g==} + + buffer-image-size@0.6.4: + resolution: {integrity: sha512-nEh+kZOPY1w+gcCMobZ6ETUp9WfibndnosbpwB1iJk/8Gt5ZF2bhS6+B6bPYz424KtwsR6Rflc3tCz1/ghX2dQ==} + engines: {node: '>=4.0'} + + caniuse-lite@1.0.30001806: + resolution: {integrity: sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + + happy-dom@20.11.1: + resolution: {integrity: sha512-XSt8tMzbW9ymE7687xztkO1ckR7qJNQ3LywY9vlYGhGi3zXrGBHuUo2Cl1ztZaICW+1eAGdkLbj6iwVqDT33kg==} + engines: {node: '>=20.0.0'} + + lexical@0.48.0: + resolution: {integrity: sha512-KK4Tyr/cPsleoZ7XvhGRiRmcrZidSmoFUdIXK9nPubIifoC+80Dc5THyc4xtGKtsW24S1TsHzk5gmfBU+TxmEg==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + next@15.5.3: + resolution: {integrity: sha512-r/liNAx16SQj4D+XH/oI1dlpv9tdKJ6cONYPwwcCC46f2NjpaRWY+EKCzULfgQYV6YKXjHBchff2IZBSlZmJNw==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details. + 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 + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + react-dom@19.1.0: + resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} + peerDependencies: + react: ^19.1.0 + + react@19.1.0: + resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} + engines: {node: '>=0.10.0'} + + scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + + ws@8.21.1: + resolution: {integrity: sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + +snapshots: + + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.11.3 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@lexical/clipboard@0.48.0(typescript@5.9.3)': + dependencies: + '@lexical/extension': 0.48.0(typescript@5.9.3) + '@lexical/html': 0.48.0(typescript@5.9.3) + '@lexical/internal': 0.48.0(typescript@5.9.3) + '@lexical/list': 0.48.0(typescript@5.9.3) + '@lexical/selection': 0.48.0(typescript@5.9.3) + '@lexical/utils': 0.48.0(typescript@5.9.3) + '@types/trusted-types': 2.0.7 + lexical: 0.48.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@lexical/dragon@0.48.0(typescript@5.9.3)': + dependencies: + '@lexical/extension': 0.48.0(typescript@5.9.3) + lexical: 0.48.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@lexical/extension@0.48.0(typescript@5.9.3)': + dependencies: + '@lexical/internal': 0.48.0(typescript@5.9.3) + '@lexical/utils': 0.48.0(typescript@5.9.3) + '@preact/signals-core': 1.14.4 + lexical: 0.48.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@lexical/headless@0.48.0(typescript@5.9.3)': + dependencies: + '@lexical/internal': 0.48.0(typescript@5.9.3) + happy-dom: 20.11.1 + lexical: 0.48.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@lexical/html@0.48.0(typescript@5.9.3)': + dependencies: + '@lexical/extension': 0.48.0(typescript@5.9.3) + '@lexical/internal': 0.48.0(typescript@5.9.3) + '@lexical/selection': 0.48.0(typescript@5.9.3) + '@lexical/utils': 0.48.0(typescript@5.9.3) + lexical: 0.48.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@lexical/internal@0.48.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@lexical/link@0.48.0(typescript@5.9.3)': + dependencies: + '@lexical/extension': 0.48.0(typescript@5.9.3) + '@lexical/html': 0.48.0(typescript@5.9.3) + '@lexical/internal': 0.48.0(typescript@5.9.3) + '@lexical/utils': 0.48.0(typescript@5.9.3) + lexical: 0.48.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@lexical/list@0.48.0(typescript@5.9.3)': + dependencies: + '@lexical/extension': 0.48.0(typescript@5.9.3) + '@lexical/html': 0.48.0(typescript@5.9.3) + '@lexical/internal': 0.48.0(typescript@5.9.3) + '@lexical/utils': 0.48.0(typescript@5.9.3) + lexical: 0.48.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@lexical/rich-text@0.48.0(typescript@5.9.3)': + dependencies: + '@lexical/clipboard': 0.48.0(typescript@5.9.3) + '@lexical/dragon': 0.48.0(typescript@5.9.3) + '@lexical/extension': 0.48.0(typescript@5.9.3) + '@lexical/html': 0.48.0(typescript@5.9.3) + '@lexical/selection': 0.48.0(typescript@5.9.3) + '@lexical/utils': 0.48.0(typescript@5.9.3) + lexical: 0.48.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@lexical/selection@0.48.0(typescript@5.9.3)': + dependencies: + '@lexical/internal': 0.48.0(typescript@5.9.3) + lexical: 0.48.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@lexical/utils@0.48.0(typescript@5.9.3)': + dependencies: + '@lexical/internal': 0.48.0(typescript@5.9.3) + '@lexical/selection': 0.48.0(typescript@5.9.3) + lexical: 0.48.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@next/env@15.5.3': {} + + '@next/swc-darwin-arm64@15.5.3': + optional: true + + '@next/swc-darwin-x64@15.5.3': + optional: true + + '@next/swc-linux-arm64-gnu@15.5.3': + optional: true + + '@next/swc-linux-arm64-musl@15.5.3': + optional: true + + '@next/swc-linux-x64-gnu@15.5.3': + optional: true + + '@next/swc-linux-x64-musl@15.5.3': + optional: true + + '@next/swc-win32-arm64-msvc@15.5.3': + optional: true + + '@next/swc-win32-x64-msvc@15.5.3': + optional: true + + '@preact/signals-core@1.14.4': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@types/node@20.19.43': + dependencies: + undici-types: 6.21.0 + + '@types/react-dom@19.2.3(@types/react@19.2.17)': + dependencies: + '@types/react': 19.2.17 + + '@types/react@19.2.17': + dependencies: + csstype: 3.2.3 + + '@types/trusted-types@2.0.7': {} + + '@types/whatwg-mimetype@3.0.2': {} + + '@types/ws@8.18.1': + dependencies: + '@types/node': 20.19.43 + + '@unlayer/exporters@1.455.0(@unlayer/types@1.455.0)(typescript@5.9.3)': + dependencies: + '@lexical/headless': 0.48.0(typescript@5.9.3) + '@lexical/html': 0.48.0(typescript@5.9.3) + '@lexical/link': 0.48.0(typescript@5.9.3) + '@lexical/list': 0.48.0(typescript@5.9.3) + '@lexical/rich-text': 0.48.0(typescript@5.9.3) + '@lexical/selection': 0.48.0(typescript@5.9.3) + '@lexical/utils': 0.48.0(typescript@5.9.3) + '@unlayer/types': 1.455.0 + lexical: 0.48.0(typescript@5.9.3) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + + '@unlayer/react-elements@0.1.20(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.9.3)': + dependencies: + '@unlayer/exporters': 1.455.0(@unlayer/types@1.455.0)(typescript@5.9.3) + '@unlayer/types': 1.455.0 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + + '@unlayer/types@1.455.0': {} + + buffer-image-size@0.6.4: + dependencies: + '@types/node': 20.19.43 + + caniuse-lite@1.0.30001806: {} + + client-only@0.0.1: {} + + csstype@3.2.3: {} + + detect-libc@2.1.2: + optional: true + + entities@7.0.1: {} + + happy-dom@20.11.1: + dependencies: + '@types/node': 20.19.43 + '@types/whatwg-mimetype': 3.0.2 + '@types/ws': 8.18.1 + buffer-image-size: 0.6.4 + entities: 7.0.1 + whatwg-mimetype: 3.0.0 + ws: 8.21.1 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + lexical@0.48.0(typescript@5.9.3): + dependencies: + '@lexical/internal': 0.48.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + nanoid@3.3.16: {} + + next@15.5.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + '@next/env': 15.5.3 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001806 + postcss: 8.4.31 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + styled-jsx: 5.1.6(react@19.1.0) + optionalDependencies: + '@next/swc-darwin-arm64': 15.5.3 + '@next/swc-darwin-x64': 15.5.3 + '@next/swc-linux-arm64-gnu': 15.5.3 + '@next/swc-linux-arm64-musl': 15.5.3 + '@next/swc-linux-x64-gnu': 15.5.3 + '@next/swc-linux-x64-musl': 15.5.3 + '@next/swc-win32-arm64-msvc': 15.5.3 + '@next/swc-win32-x64-msvc': 15.5.3 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + picocolors@1.1.1: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.16 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + react-dom@19.1.0(react@19.1.0): + dependencies: + react: 19.1.0 + scheduler: 0.26.0 + + react@19.1.0: {} + + scheduler@0.26.0: {} + + semver@7.8.5: + optional: true + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + optional: true + + source-map-js@1.2.1: {} + + styled-jsx@5.1.6(react@19.1.0): + dependencies: + client-only: 0.0.1 + react: 19.1.0 + + tslib@2.8.1: {} + + typescript@5.9.3: {} + + undici-types@6.21.0: {} + + whatwg-mimetype@3.0.0: {} + + ws@8.21.1: {} diff --git a/examples/nextjs-app-router/pnpm-workspace.yaml b/examples/nextjs-app-router/pnpm-workspace.yaml new file mode 100644 index 00000000..d18b8cbd --- /dev/null +++ b/examples/nextjs-app-router/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +packages: [] +allowBuilds: + sharp: set this to true or false diff --git a/examples/nextjs-app-router/src/app/email-preview/PreviewDashboard.tsx b/examples/nextjs-app-router/src/app/email-preview/PreviewDashboard.tsx new file mode 100644 index 00000000..6aeaefdc --- /dev/null +++ b/examples/nextjs-app-router/src/app/email-preview/PreviewDashboard.tsx @@ -0,0 +1,308 @@ +"use client"; + +import { useState } from "react"; +import Link from "next/link"; + +interface PreviewDashboardProps { + initialHtml: string; + initialText: string; + recipientName: string; +} + +type Tab = "preview" | "raw" | "text"; +type Viewport = "desktop" | "mobile"; + +export default function PreviewDashboard({ + initialHtml, + initialText, + recipientName, +}: PreviewDashboardProps) { + const [activeTab, setActiveTab] = useState("preview"); + const [viewport, setViewport] = useState("desktop"); + const [copying, setCopying] = useState(false); + + const handleCopy = async () => { + const textToCopy = activeTab === "raw" ? initialHtml : initialText; + try { + await navigator.clipboard.writeText(textToCopy); + setCopying(true); + setTimeout(() => setCopying(false), 2000); + } catch (err) { + console.error("Failed to copy text", err); + } + }; + + return ( +
+ {/* Top Navigation & Info */} +
+

+ + ← back to home + +

+
+
+

Welcome Email

+

+ Rendered on the server with renderToHtml() ( + {(initialHtml.length / 1024).toFixed(1)} KB) +

+
+
+ + Open Raw HTML ↗ + +
+
+
+ + {/* Control Bar: Tabs & Viewport */} +
+ {/* Format Selector Tabs */} +
+ + + +
+ + {/* Action Controls (Viewport/Copy) */} +
+ {activeTab === "preview" && ( +
+ + +
+ )} + + {activeTab !== "preview" && ( + + )} +
+
+ + {/* Main Content Area */} +
+ {activeTab === "preview" && ( +
+