From 8bf5d06be111e15c0acb07714fb8b931f1cefd58 Mon Sep 17 00:00:00 2001 From: liaibo Date: Tue, 18 Nov 2025 06:58:49 +0800 Subject: [PATCH 1/2] Initial commit from Create Next App --- .gitignore | 41 + README.md | 36 + eslint.config.mjs | 18 + next.config.ts | 7 + package.json | 26 + pnpm-lock.yaml | 4026 +++++++++++++++++++++++++++++++++++++++++++ postcss.config.mjs | 7 + public/file.svg | 1 + public/globe.svg | 1 + public/next.svg | 1 + public/vercel.svg | 1 + public/window.svg | 1 + src/app/favicon.ico | Bin 0 -> 25931 bytes src/app/globals.css | 26 + src/app/layout.tsx | 34 + src/app/page.tsx | 65 + tsconfig.json | 34 + 17 files changed, 4325 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 eslint.config.mjs create mode 100644 next.config.ts create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 postcss.config.mjs create mode 100644 public/file.svg create mode 100644 public/globe.svg create mode 100644 public/next.svg create mode 100644 public/vercel.svg create mode 100644 public/window.svg create mode 100644 src/app/favicon.ico create mode 100644 src/app/globals.css create mode 100644 src/app/layout.tsx create mode 100644 src/app/page.tsx create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..5ef6a520 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/README.md b/README.md new file mode 100644 index 00000000..e215bc4c --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..05e726d1 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), +]); + +export default eslintConfig; diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 00000000..e9ffa308 --- /dev/null +++ b/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + /* config options here */ +}; + +export default nextConfig; diff --git a/package.json b/package.json new file mode 100644 index 00000000..b4a80332 --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "wolai-frontend", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint" + }, + "dependencies": { + "next": "16.0.3", + "react": "19.2.0", + "react-dom": "19.2.0" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.0.3", + "tailwindcss": "^4", + "typescript": "^5" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 00000000..2fcaeb93 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,4026 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + next: + specifier: 16.0.3 + version: 16.0.3(@babel/core@7.28.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: + specifier: 19.2.0 + version: 19.2.0 + react-dom: + specifier: 19.2.0 + version: 19.2.0(react@19.2.0) + devDependencies: + '@tailwindcss/postcss': + specifier: ^4 + version: 4.1.17 + '@types/node': + specifier: ^20 + version: 20.19.25 + '@types/react': + specifier: ^19 + version: 19.2.5 + '@types/react-dom': + specifier: ^19 + version: 19.2.3(@types/react@19.2.5) + eslint: + specifier: ^9 + version: 9.39.1(jiti@2.6.1) + eslint-config-next: + specifier: 16.0.3 + version: 16.0.3(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + tailwindcss: + specifier: ^4 + version: 4.1.17 + typescript: + specifier: ^5 + version: 5.9.3 + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.28.5': + resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.4': + resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + + '@emnapi/core@1.7.1': + resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} + + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.1': + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.1': + resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + 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] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@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] + + '@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] + + '@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] + + '@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] + + '@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] + + '@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] + + '@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] + + '@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] + + '@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] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + + '@next/env@16.0.3': + resolution: {integrity: sha512-IqgtY5Vwsm14mm/nmQaRMmywCU+yyMIYfk3/MHZ2ZTJvwVbBn3usZnjMi1GacrMVzVcAxJShTCpZlPs26EdEjQ==} + + '@next/eslint-plugin-next@16.0.3': + resolution: {integrity: sha512-6sPWmZetzFWMsz7Dhuxsdmbu3fK+/AxKRtj7OB0/3OZAI2MHB/v2FeYh271LZ9abvnM1WIwWc/5umYjx0jo5sQ==} + + '@next/swc-darwin-arm64@16.0.3': + resolution: {integrity: sha512-MOnbd92+OByu0p6QBAzq1ahVWzF6nyfiH07dQDez4/Nku7G249NjxDVyEfVhz8WkLiOEU+KFVnqtgcsfP2nLXg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@16.0.3': + resolution: {integrity: sha512-i70C4O1VmbTivYdRlk+5lj9xRc2BlK3oUikt3yJeHT1unL4LsNtN7UiOhVanFdc7vDAgZn1tV/9mQwMkWOJvHg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@16.0.3': + resolution: {integrity: sha512-O88gCZ95sScwD00mn/AtalyCoykhhlokxH/wi1huFK+rmiP5LAYVs/i2ruk7xST6SuXN4NI5y4Xf5vepb2jf6A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-arm64-musl@16.0.3': + resolution: {integrity: sha512-CEErFt78S/zYXzFIiv18iQCbRbLgBluS8z1TNDQoyPi8/Jr5qhR3e8XHAIxVxPBjDbEMITprqELVc5KTfFj0gg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-x64-gnu@16.0.3': + resolution: {integrity: sha512-Tc3i+nwt6mQ+Dwzcri/WNDj56iWdycGVh5YwwklleClzPzz7UpfaMw1ci7bLl6GRYMXhWDBfe707EXNjKtiswQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-linux-x64-musl@16.0.3': + resolution: {integrity: sha512-zTh03Z/5PBBPdTurgEtr6nY0vI9KR9Ifp/jZCcHlODzwVOEKcKRBtQIGrkc7izFgOMuXDEJBmirwpGqdM/ZixA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-win32-arm64-msvc@16.0.3': + resolution: {integrity: sha512-Jc1EHxtZovcJcg5zU43X3tuqzl/sS+CmLgjRP28ZT4vk869Ncm2NoF8qSTaL99gh6uOzgM99Shct06pSO6kA6g==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@16.0.3': + resolution: {integrity: sha512-N7EJ6zbxgIYpI/sWNzpVKRMbfEGgsWuOIvzkML7wxAAZhPk1Msxuo/JDu1PKjWGrAoOLaZcIX5s+/pF5LIbBBg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tailwindcss/node@4.1.17': + resolution: {integrity: sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==} + + '@tailwindcss/oxide-android-arm64@4.1.17': + resolution: {integrity: sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.17': + resolution: {integrity: sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.17': + resolution: {integrity: sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.17': + resolution: {integrity: sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': + resolution: {integrity: sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': + resolution: {integrity: sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.17': + resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.17': + resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.17': + resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.17': + resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': + resolution: {integrity: sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.17': + resolution: {integrity: sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.17': + resolution: {integrity: sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==} + engines: {node: '>= 10'} + + '@tailwindcss/postcss@4.1.17': + resolution: {integrity: sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/node@20.19.25': + resolution: {integrity: sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==} + + '@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.5': + resolution: {integrity: sha512-keKxkZMqnDicuvFoJbzrhbtdLSPhj/rZThDlKWCDbgXmUg0rEUFtRssDXKYmtXluZlIqiC5VqkCgRwzuyLHKHw==} + + '@typescript-eslint/eslint-plugin@8.47.0': + resolution: {integrity: sha512-fe0rz9WJQ5t2iaLfdbDc9T80GJy0AeO453q8C3YCilnGozvOyCG5t+EZtg7j7D88+c3FipfP/x+wzGnh1xp8ZA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.47.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.47.0': + resolution: {integrity: sha512-lJi3PfxVmo0AkEY93ecfN+r8SofEqZNGByvHAI3GBLrvt1Cw6H5k1IM02nSzu0RfUafr2EvFSw0wAsZgubNplQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.47.0': + resolution: {integrity: sha512-2X4BX8hUeB5JcA1TQJ7GjcgulXQ+5UkNb0DL8gHsHUHdFoiCTJoYLTpib3LtSDPZsRET5ygN4qqIWrHyYIKERA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.47.0': + resolution: {integrity: sha512-a0TTJk4HXMkfpFkL9/WaGTNuv7JWfFTQFJd6zS9dVAjKsojmv9HT55xzbEpnZoY+VUb+YXLMp+ihMLz/UlZfDg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.47.0': + resolution: {integrity: sha512-ybUAvjy4ZCL11uryalkKxuT3w3sXJAuWhOoGS3T/Wu+iUu1tGJmk5ytSY8gbdACNARmcYEB0COksD2j6hfGK2g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.47.0': + resolution: {integrity: sha512-QC9RiCmZ2HmIdCEvhd1aJELBlD93ErziOXXlHEZyuBo3tBiAZieya0HLIxp+DoDWlsQqDawyKuNEhORyku+P8A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.47.0': + resolution: {integrity: sha512-nHAE6bMKsizhA2uuYZbEbmp5z2UpffNrPEqiKIeN7VsV6UY/roxanWfoRrf6x/k9+Obf+GQdkm0nPU+vnMXo9A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.47.0': + resolution: {integrity: sha512-k6ti9UepJf5NpzCjH31hQNLHQWupTRPhZ+KFF8WtTuTpy7uHPfeg2NM7cP27aCGajoEplxJDFVCEm9TGPYyiVg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.47.0': + resolution: {integrity: sha512-g7XrNf25iL4TJOiPqatNuaChyqt49a/onq5YsJ9+hXeugK+41LVg7AxikMfM02PC6jbNtZLCJj6AUcQXJS/jGQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.47.0': + resolution: {integrity: sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.11.0: + resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} + engines: {node: '>=4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + baseline-browser-mapping@2.8.29: + resolution: {integrity: sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA==} + hasBin: true + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.0: + resolution: {integrity: sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001755: + resolution: {integrity: sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + electron-to-chromium@1.5.255: + resolution: {integrity: sha512-Z9oIp4HrFF/cZkDPMpz2XSuVpc1THDpT4dlmATFlJUIBVCy9Vap5/rIXsASP1CscBacBqhabwh8vLctqBwEerQ==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-next@16.0.3: + resolution: {integrity: sha512-5F6qDjcZldf0Y0ZbqvWvap9xzYUxyDf7/of37aeyhvkrQokj/4bT1JYWZdlWUr283aeVa+s52mPq9ogmGg+5dw==} + peerDependencies: + eslint: '>=9.0.0' + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-import-resolver-typescript@3.10.1: + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jsx-a11y@6.10.2: + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-react-hooks@7.0.1: + resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.39.1: + resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.4.0: + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-bun-module@2.0.0: + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + next@16.0.3: + resolution: {integrity: sha512-Ka0/iNBblPFcIubTA1Jjh6gvwqfjrGq1Y2MTI5lbjeLIAfmC+p5bQmojpRZqgHHVu5cG4+qdIiwXiBSm/8lZ3w==} + engines: {node: '>=20.9.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-dom@19.2.0: + resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} + peerDependencies: + react: ^19.2.0 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react@19.2.0: + resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} + engines: {node: '>=0.10.0'} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stable-hash@0.0.5: + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + 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 + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tailwindcss@4.1.17: + resolution: {integrity: sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typescript-eslint@8.47.0: + resolution: {integrity: sha512-Lwe8i2XQ3WoMjua/r1PHrCTpkubPYJCAfOurtn+mtTzqB6jNd+14n9UN1bJ4s3F49x9ixAm0FLflB/JzQ57M8Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + + update-browserslist-db@1.1.4: + resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + zod@4.1.12: + resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.5': {} + + '@babel/core@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@emnapi/core@1.7.1': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.7.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.6.1))': + dependencies: + eslint: 9.39.1(jiti@2.6.1) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.1': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@img/colour@1.0.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.7.1 + 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 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.7.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@next/env@16.0.3': {} + + '@next/eslint-plugin-next@16.0.3': + dependencies: + fast-glob: 3.3.1 + + '@next/swc-darwin-arm64@16.0.3': + optional: true + + '@next/swc-darwin-x64@16.0.3': + optional: true + + '@next/swc-linux-arm64-gnu@16.0.3': + optional: true + + '@next/swc-linux-arm64-musl@16.0.3': + optional: true + + '@next/swc-linux-x64-gnu@16.0.3': + optional: true + + '@next/swc-linux-x64-musl@16.0.3': + optional: true + + '@next/swc-win32-arm64-msvc@16.0.3': + optional: true + + '@next/swc-win32-x64-msvc@16.0.3': + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@nolyfill/is-core-module@1.0.39': {} + + '@rtsao/scc@1.1.0': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/node@4.1.17': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.1.17 + + '@tailwindcss/oxide-android-arm64@4.1.17': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.17': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.17': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.17': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.17': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.17': + optional: true + + '@tailwindcss/oxide@4.1.17': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.17 + '@tailwindcss/oxide-darwin-arm64': 4.1.17 + '@tailwindcss/oxide-darwin-x64': 4.1.17 + '@tailwindcss/oxide-freebsd-x64': 4.1.17 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.17 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.17 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.17 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.17 + '@tailwindcss/oxide-linux-x64-musl': 4.1.17 + '@tailwindcss/oxide-wasm32-wasi': 4.1.17 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.17 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.17 + + '@tailwindcss/postcss@4.1.17': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.1.17 + '@tailwindcss/oxide': 4.1.17 + postcss: 8.5.6 + tailwindcss: 4.1.17 + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/estree@1.0.8': {} + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/node@20.19.25': + dependencies: + undici-types: 6.21.0 + + '@types/react-dom@19.2.3(@types/react@19.2.5)': + dependencies: + '@types/react': 19.2.5 + + '@types/react@19.2.5': + dependencies: + csstype: 3.2.3 + + '@typescript-eslint/eslint-plugin@8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.47.0 + '@typescript-eslint/type-utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.47.0 + eslint: 9.39.1(jiti@2.6.1) + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.47.0 + '@typescript-eslint/types': 8.47.0 + '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.47.0 + debug: 4.4.3 + eslint: 9.39.1(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.47.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.47.0(typescript@5.9.3) + '@typescript-eslint/types': 8.47.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.47.0': + dependencies: + '@typescript-eslint/types': 8.47.0 + '@typescript-eslint/visitor-keys': 8.47.0 + + '@typescript-eslint/tsconfig-utils@8.47.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.47.0 + '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.1(jiti@2.6.1) + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.47.0': {} + + '@typescript-eslint/typescript-estree@8.47.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.47.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.47.0(typescript@5.9.3) + '@typescript-eslint/types': 8.47.0 + '@typescript-eslint/visitor-keys': 8.47.0 + debug: 4.4.3 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.3 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.47.0 + '@typescript-eslint/types': 8.47.0 + '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.47.0': + dependencies: + '@typescript-eslint/types': 8.47.0 + eslint-visitor-keys: 4.2.1 + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + ast-types-flow@0.0.8: {} + + async-function@1.0.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axe-core@4.11.0: {} + + axobject-query@4.1.0: {} + + balanced-match@1.0.2: {} + + baseline-browser-mapping@2.8.29: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.0: + dependencies: + baseline-browser-mapping: 2.8.29 + caniuse-lite: 1.0.30001755 + electron-to-chromium: 1.5.255 + node-releases: 2.0.27 + update-browserslist-db: 1.1.4(browserslist@4.28.0) + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001755: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + client-only@0.0.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} + + damerau-levenshtein@1.0.8: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + detect-libc@2.1.2: {} + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + electron-to-chromium@1.5.255: {} + + emoji-regex@9.2.2: {} + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + es-abstract@1.24.0: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + safe-array-concat: 1.1.3 + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-next@16.0.3(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@next/eslint-plugin-next': 16.0.3 + eslint: 9.39.1(jiti@2.6.1) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-react-hooks: 7.0.1(eslint@9.39.1(jiti@2.6.1)) + globals: 16.4.0 + typescript-eslint: 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.3 + eslint: 9.39.1(jiti@2.6.1) + get-tsconfig: 4.13.0 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.15 + unrs-resolver: 1.11.1 + optionalDependencies: + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)) + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.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.39.1(jiti@2.6.1) + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.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.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.1(jiti@2.6.1)): + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.11.0 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.39.1(jiti@2.6.1) + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + + eslint-plugin-react-hooks@7.0.1(eslint@9.39.1(jiti@2.6.1)): + dependencies: + '@babel/core': 7.28.5 + '@babel/parser': 7.28.5 + eslint: 9.39.1(jiti@2.6.1) + hermes-parser: 0.25.1 + zod: 4.1.12 + zod-validation-error: 4.0.2(zod@4.1.12) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react@7.37.5(eslint@9.39.1(jiti@2.6.1)): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 9.39.1(jiti@2.6.1) + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.39.1(jiti@2.6.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.39.1 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.1 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.1: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + + gensync@1.0.0-beta.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + get-tsconfig@4.13.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globals@16.4.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-bun-module@2.0.0: + dependencies: + semver: 7.7.3 + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jiti@2.6.1: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + json5@2.2.3: {} + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + language-subtag-registry@0.3.23: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.23 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: + optional: true + + lightningcss-darwin-x64@1.30.2: + optional: true + + lightningcss-freebsd-x64@1.30.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.2: + optional: true + + lightningcss-linux-x64-musl@1.30.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + math-intrinsics@1.1.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + next@16.0.3(@babel/core@7.28.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + '@next/env': 16.0.3 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001755 + postcss: 8.4.31 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + styled-jsx: 5.1.6(@babel/core@7.28.5)(react@19.2.0) + optionalDependencies: + '@next/swc-darwin-arm64': 16.0.3 + '@next/swc-darwin-x64': 16.0.3 + '@next/swc-linux-arm64-gnu': 16.0.3 + '@next/swc-linux-arm64-musl': 16.0.3 + '@next/swc-linux-x64-gnu': 16.0.3 + '@next/swc-linux-x64-musl': 16.0.3 + '@next/swc-win32-arm64-msvc': 16.0.3 + '@next/swc-win32-x64-msvc': 16.0.3 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + node-releases@2.0.27: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + possible-typed-array-names@1.1.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + react-dom@19.2.0(react@19.2.0): + dependencies: + react: 19.2.0 + scheduler: 0.27.0 + + react-is@16.13.1: {} + + react@19.2.0: {} + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@2.0.0-next.5: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + semver@7.7.3: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + sharp@0.34.5: + dependencies: + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 + 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 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + source-map-js@1.2.1: {} + + stable-hash@0.0.5: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + strip-bom@3.0.0: {} + + strip-json-comments@3.1.1: {} + + styled-jsx@5.1.6(@babel/core@7.28.5)(react@19.2.0): + dependencies: + client-only: 0.0.1 + react: 19.2.0 + optionalDependencies: + '@babel/core': 7.28.5 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tailwindcss@4.1.17: {} + + tapable@2.3.0: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-api-utils@2.1.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript-eslint@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@6.21.0: {} + + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + + update-browserslist-db@1.1.4(browserslist@4.28.0): + dependencies: + browserslist: 4.28.0 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + yallist@3.1.1: {} + + yocto-queue@0.1.0: {} + + zod-validation-error@4.0.2(zod@4.1.12): + dependencies: + zod: 4.1.12 + + zod@4.1.12: {} diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 00000000..61e36849 --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/public/file.svg b/public/file.svg new file mode 100644 index 00000000..004145cd --- /dev/null +++ b/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/globe.svg b/public/globe.svg new file mode 100644 index 00000000..567f17b0 --- /dev/null +++ b/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/next.svg b/public/next.svg new file mode 100644 index 00000000..5174b28c --- /dev/null +++ b/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/vercel.svg b/public/vercel.svg new file mode 100644 index 00000000..77053960 --- /dev/null +++ b/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/window.svg b/public/window.svg new file mode 100644 index 00000000..b2b2a44f --- /dev/null +++ b/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/favicon.ico b/src/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 zcmeHv30#a{`}aL_*G&7qml|y<+KVaDM2m#dVr!KsA!#An?kSQM(q<_dDNCpjEux83 zLb9Z^XxbDl(w>%i@8hT6>)&Gu{h#Oeyszu?xtw#Zb1mO{pgX9699l+Qppw7jXaYf~-84xW z)w4x8?=youko|}Vr~(D$UXIbiXABHh`p1?nn8Po~fxRJv}|0e(BPs|G`(TT%kKVJAdg5*Z|x0leQq0 zkdUBvb#>9F()jo|T~kx@OM8$9wzs~t2l;K=woNssA3l6|sx2r3+kdfVW@e^8e*E}v zA1y5{bRi+3Z`uD3{F7LgFJDdvm;nJilkzDku>BwXH(8ItVCXk*-lSJnR?-2UN%hJ){&rlvg`CDTj z)Bzo!3v7Ou#83zEDEFcKt(f1E0~=rqeEbTnMvWR#{+9pg%7G8y>u1OVRUSoox-ovF z2Ydma(;=YuBY(eI|04{hXzZD6_f(v~H;C~y5=DhAC{MMS>2fm~1H_t2$56pc$NH8( z5bH|<)71dV-_oCHIrzrT`2s-5w_+2CM0$95I6X8p^r!gHp+j_gd;9O<1~CEQQGS8) zS9Qh3#p&JM-G8rHekNmKVewU;pJRcTAog68KYo^dRo}(M>36U4Us zfgYWSiHZL3;lpWT=zNAW>Dh#mB!_@Lg%$ms8N-;aPqMn+C2HqZgz&9~Eu z4|Kp<`$q)Uw1R?y(~S>ePdonHxpV1#eSP1B;Ogo+-Pk}6#0GsZZ5!||ev2MGdh}_m z{DeR7?0-1^zVs&`AV6Vt;r3`I`OI_wgs*w=eO%_#7Kepl{B@xiyCANc(l zzIyd4y|c6PXWq9-|KM8(zIk8LPk(>a)zyFWjhT!$HJ$qX1vo@d25W<fvZQ2zUz5WRc(UnFMKHwe1| zWmlB1qdbiA(C0jmnV<}GfbKtmcu^2*P^O?MBLZKt|As~ge8&AAO~2K@zbXelK|4T<{|y4`raF{=72kC2Kn(L4YyenWgrPiv z@^mr$t{#X5VuIMeL!7Ab6_kG$&#&5p*Z{+?5U|TZ`B!7llpVmp@skYz&n^8QfPJzL z0G6K_OJM9x+Wu2gfN45phANGt{7=C>i34CV{Xqlx(fWpeAoj^N0Biu`w+MVcCUyU* zDZuzO0>4Z6fbu^T_arWW5n!E45vX8N=bxTVeFoep_G#VmNlQzAI_KTIc{6>c+04vr zx@W}zE5JNSU>!THJ{J=cqjz+4{L4A{Ob9$ZJ*S1?Ggg3klFp!+Y1@K+pK1DqI|_gq z5ZDXVpge8-cs!o|;K73#YXZ3AShj50wBvuq3NTOZ`M&qtjj#GOFfgExjg8Gn8>Vq5 z`85n+9|!iLCZF5$HJ$Iu($dm?8~-ofu}tEc+-pyke=3!im#6pk_Wo8IA|fJwD&~~F zc16osQ)EBo58U7XDuMexaPRjU@h8tXe%S{fA0NH3vGJFhuyyO!Uyl2^&EOpX{9As0 zWj+P>{@}jxH)8|r;2HdupP!vie{sJ28b&bo!8`D^x}TE$%zXNb^X1p@0PJ86`dZyj z%ce7*{^oo+6%&~I!8hQy-vQ7E)0t0ybH4l%KltWOo~8cO`T=157JqL(oq_rC%ea&4 z2NcTJe-HgFjNg-gZ$6!Y`SMHrlj}Etf7?r!zQTPPSv}{so2e>Fjs1{gzk~LGeesX%r(Lh6rbhSo_n)@@G-FTQy93;l#E)hgP@d_SGvyCp0~o(Y;Ee8{ zdVUDbHm5`2taPUOY^MAGOw*>=s7=Gst=D+p+2yON!0%Hk` zz5mAhyT4lS*T3LS^WSxUy86q&GnoHxzQ6vm8)VS}_zuqG?+3td68_x;etQAdu@sc6 zQJ&5|4(I?~3d-QOAODHpZ=hlSg(lBZ!JZWCtHHSj`0Wh93-Uk)_S%zsJ~aD>{`A0~ z9{AG(e|q3g5B%wYKRxiL2Y$8(4w6bzchKuloQW#e&S3n+P- z8!ds-%f;TJ1>)v)##>gd{PdS2Oc3VaR`fr=`O8QIO(6(N!A?pr5C#6fc~Ge@N%Vvu zaoAX2&(a6eWy_q&UwOhU)|P3J0Qc%OdhzW=F4D|pt0E4osw;%<%Dn58hAWD^XnZD= z>9~H(3bmLtxpF?a7su6J7M*x1By7YSUbxGi)Ot0P77`}P3{)&5Un{KD?`-e?r21!4vTTnN(4Y6Lin?UkSM z`MXCTC1@4A4~mvz%Rh2&EwY))LeoT=*`tMoqcEXI>TZU9WTP#l?uFv+@Dn~b(>xh2 z;>B?;Tz2SR&KVb>vGiBSB`@U7VIWFSo=LDSb9F{GF^DbmWAfpms8Sx9OX4CnBJca3 zlj9(x!dIjN?OG1X4l*imJNvRCk}F%!?SOfiOq5y^mZW)jFL@a|r-@d#f7 z2gmU8L3IZq0ynIws=}~m^#@&C%J6QFo~Mo4V`>v7MI-_!EBMMtb%_M&kvAaN)@ZVw z+`toz&WG#HkWDjnZE!6nk{e-oFdL^$YnbOCN}JC&{$#$O27@|Tn-skXr)2ml2~O!5 zX+gYoxhoc7qoU?C^3~&!U?kRFtnSEecWuH0B0OvLodgUAi}8p1 zrO6RSXHH}DMc$&|?D004DiOVMHV8kXCP@7NKB zgaZq^^O<7PoKEp72kby@W0Z!Y*Ay{&vfg#C&gG@YVR9g?FEocMUi1gSN$+V+ayF45{a zuDZDTN}mS|;BO%gEf}pjBfN2-gIrU#G5~cucA;dokXW89%>AyXJJI z9X4UlIWA|ZYHgbI z5?oFk@A=Ik7lrEQPDH!H+b`7_Y~aDb_qa=B2^Y&Ow41cU=4WDd40dp5(QS-WMN-=Y z9g;6_-JdNU;|6cPwf$ak*aJIcwL@1n$#l~zi{c{EW?T;DaW*E8DYq?Umtz{nJ&w-M zEMyTDrC&9K$d|kZe2#ws6)L=7K+{ zQw{XnV6UC$6-rW0emqm8wJoeZK)wJIcV?dST}Z;G0Arq{dVDu0&4kd%N!3F1*;*pW zR&qUiFzK=@44#QGw7k1`3t_d8&*kBV->O##t|tonFc2YWrL7_eqg+=+k;!F-`^b8> z#KWCE8%u4k@EprxqiV$VmmtiWxDLgnGu$Vs<8rppV5EajBXL4nyyZM$SWVm!wnCj-B!Wjqj5-5dNXukI2$$|Bu3Lrw}z65Lc=1G z^-#WuQOj$hwNGG?*CM_TO8Bg-1+qc>J7k5c51U8g?ZU5n?HYor;~JIjoWH-G>AoUP ztrWWLbRNqIjW#RT*WqZgPJXU7C)VaW5}MiijYbABmzoru6EmQ*N8cVK7a3|aOB#O& zBl8JY2WKfmj;h#Q!pN%9o@VNLv{OUL?rixHwOZuvX7{IJ{(EdPpuVFoQqIOa7giLVkBOKL@^smUA!tZ1CKRK}#SSM)iQHk)*R~?M!qkCruaS!#oIL1c z?J;U~&FfH#*98^G?i}pA{ z9Jg36t4=%6mhY(quYq*vSxptes9qy|7xSlH?G=S@>u>Ebe;|LVhs~@+06N<4CViBk zUiY$thvX;>Tby6z9Y1edAMQaiH zm^r3v#$Q#2T=X>bsY#D%s!bhs^M9PMAcHbCc0FMHV{u-dwlL;a1eJ63v5U*?Q_8JO zT#50!RD619#j_Uf))0ooADz~*9&lN!bBDRUgE>Vud-i5ck%vT=r^yD*^?Mp@Q^v+V zG#-?gKlr}Eeqifb{|So?HM&g91P8|av8hQoCmQXkd?7wIJwb z_^v8bbg`SAn{I*4bH$u(RZ6*xUhuA~hc=8czK8SHEKTzSxgbwi~9(OqJB&gwb^l4+m`k*Q;_?>Y-APi1{k zAHQ)P)G)f|AyjSgcCFps)Fh6Bca*Xznq36!pV6Az&m{O8$wGFD? zY&O*3*J0;_EqM#jh6^gMQKpXV?#1?>$ml1xvh8nSN>-?H=V;nJIwB07YX$e6vLxH( zqYwQ>qxwR(i4f)DLd)-$P>T-no_c!LsN@)8`e;W@)-Hj0>nJ-}Kla4-ZdPJzI&Mce zv)V_j;(3ERN3_@I$N<^|4Lf`B;8n+bX@bHbcZTopEmDI*Jfl)-pFDvo6svPRoo@(x z);_{lY<;);XzT`dBFpRmGrr}z5u1=pC^S-{ce6iXQlLGcItwJ^mZx{m$&DA_oEZ)B{_bYPq-HA zcH8WGoBG(aBU_j)vEy+_71T34@4dmSg!|M8Vf92Zj6WH7Q7t#OHQqWgFE3ARt+%!T z?oLovLVlnf?2c7pTc)~cc^($_8nyKwsN`RA-23ed3sdj(ys%pjjM+9JrctL;dy8a( z@en&CQmnV(()bu|Y%G1-4a(6x{aLytn$T-;(&{QIJB9vMox11U-1HpD@d(QkaJdEb zG{)+6Dos_L+O3NpWo^=gR?evp|CqEG?L&Ut#D*KLaRFOgOEK(Kq1@!EGcTfo+%A&I z=dLbB+d$u{sh?u)xP{PF8L%;YPPW53+@{>5W=Jt#wQpN;0_HYdw1{ksf_XhO4#2F= zyPx6Lx2<92L-;L5PD`zn6zwIH`Jk($?Qw({erA$^bC;q33hv!d!>%wRhj# zal^hk+WGNg;rJtb-EB(?czvOM=H7dl=vblBwAv>}%1@{}mnpUznfq1cE^sgsL0*4I zJ##!*B?=vI_OEVis5o+_IwMIRrpQyT_Sq~ZU%oY7c5JMIADzpD!Upz9h@iWg_>>~j zOLS;wp^i$-E?4<_cp?RiS%Rd?i;f*mOz=~(&3lo<=@(nR!_Rqiprh@weZlL!t#NCc zO!QTcInq|%#>OVgobj{~ixEUec`E25zJ~*DofsQdzIa@5^nOXj2T;8O`l--(QyU^$t?TGY^7#&FQ+2SS3B#qK*k3`ye?8jUYSajE5iBbJls75CCc(m3dk{t?- zopcER9{Z?TC)mk~gpi^kbbu>b-+a{m#8-y2^p$ka4n60w;Sc2}HMf<8JUvhCL0B&Btk)T`ctE$*qNW8L$`7!r^9T+>=<=2qaq-;ll2{`{Rg zc5a0ZUI$oG&j-qVOuKa=*v4aY#IsoM+1|c4Z)<}lEDvy;5huB@1RJPquU2U*U-;gu z=En2m+qjBzR#DEJDO`WU)hdd{Vj%^0V*KoyZ|5lzV87&g_j~NCjwv0uQVqXOb*QrQ zy|Qn`hxx(58c70$E;L(X0uZZ72M1!6oeg)(cdKO ze0gDaTz+ohR-#d)NbAH4x{I(21yjwvBQfmpLu$)|m{XolbgF!pmsqJ#D}(ylp6uC> z{bqtcI#hT#HW=wl7>p!38sKsJ`r8}lt-q%Keqy%u(xk=yiIJiUw6|5IvkS+#?JTBl z8H5(Q?l#wzazujH!8o>1xtn8#_w+397*_cy8!pQGP%K(Ga3pAjsaTbbXJlQF_+m+-UpUUent@xM zg%jqLUExj~o^vQ3Gl*>wh=_gOr2*|U64_iXb+-111aH}$TjeajM+I20xw(((>fej-@CIz4S1pi$(#}P7`4({6QS2CaQS4NPENDp>sAqD z$bH4KGzXGffkJ7R>V>)>tC)uax{UsN*dbeNC*v}#8Y#OWYwL4t$ePR?VTyIs!wea+ z5Urmc)X|^`MG~*dS6pGSbU+gPJoq*^a=_>$n4|P^w$sMBBy@f*Z^Jg6?n5?oId6f{ z$LW4M|4m502z0t7g<#Bx%X;9<=)smFolV&(V^(7Cv2-sxbxopQ!)*#ZRhTBpx1)Fc zNm1T%bONzv6@#|dz(w02AH8OXe>kQ#1FMCzO}2J_mST)+ExmBr9cva-@?;wnmWMOk z{3_~EX_xadgJGv&H@zK_8{(x84`}+c?oSBX*Ge3VdfTt&F}yCpFP?CpW+BE^cWY0^ zb&uBN!Ja3UzYHK-CTyA5=L zEMW{l3Usky#ly=7px648W31UNV@K)&Ub&zP1c7%)`{);I4b0Q<)B}3;NMG2JH=X$U zfIW4)4n9ZM`-yRj67I)YSLDK)qfUJ_ij}a#aZN~9EXrh8eZY2&=uY%2N0UFF7<~%M zsB8=erOWZ>Ct_#^tHZ|*q`H;A)5;ycw*IcmVxi8_0Xk}aJA^ath+E;xg!x+As(M#0=)3!NJR6H&9+zd#iP(m0PIW8$ z1Y^VX`>jm`W!=WpF*{ioM?C9`yOR>@0q=u7o>BP-eSHqCgMDj!2anwH?s%i2p+Q7D zzszIf5XJpE)IG4;d_(La-xenmF(tgAxK`Y4sQ}BSJEPs6N_U2vI{8=0C_F?@7<(G; zo$~G=8p+076G;`}>{MQ>t>7cm=zGtfbdDXm6||jUU|?X?CaE?(<6bKDYKeHlz}DA8 zXT={X=yp_R;HfJ9h%?eWvQ!dRgz&Su*JfNt!Wu>|XfU&68iRikRrHRW|ZxzRR^`eIGt zIeiDgVS>IeExKVRWW8-=A=yA`}`)ZkWBrZD`hpWIxBGkh&f#ijr449~m`j6{4jiJ*C!oVA8ZC?$1RM#K(_b zL9TW)kN*Y4%^-qPpMP7d4)o?Nk#>aoYHT(*g)qmRUb?**F@pnNiy6Fv9rEiUqD(^O zzyS?nBrX63BTRYduaG(0VVG2yJRe%o&rVrLjbxTaAFTd8s;<<@Qs>u(<193R8>}2_ zuwp{7;H2a*X7_jryzriZXMg?bTuegABb^87@SsKkr2)0Gyiax8KQWstw^v#ix45EVrcEhr>!NMhprl$InQMzjSFH54x5k9qHc`@9uKQzvL4ihcq{^B zPrVR=o_ic%Y>6&rMN)hTZsI7I<3&`#(nl+3y3ys9A~&^=4?PL&nd8)`OfG#n zwAMN$1&>K++c{^|7<4P=2y(B{jJsQ0a#U;HTo4ZmWZYvI{+s;Td{Yzem%0*k#)vjpB zia;J&>}ICate44SFYY3vEelqStQWFihx%^vQ@Do(sOy7yR2@WNv7Y9I^yL=nZr3mb zXKV5t@=?-Sk|b{XMhA7ZGB@2hqsx}4xwCW!in#C zI@}scZlr3-NFJ@NFaJlhyfcw{k^vvtGl`N9xSo**rDW4S}i zM9{fMPWo%4wYDG~BZ18BD+}h|GQKc-g^{++3MY>}W_uq7jGHx{mwE9fZiPCoxN$+7 zrODGGJrOkcPQUB(FD5aoS4g~7#6NR^ma7-!>mHuJfY5kTe6PpNNKC9GGRiu^L31uG z$7v`*JknQHsYB!Tm_W{a32TM099djW%5e+j0Ve_ct}IM>XLF1Ap+YvcrLV=|CKo6S zb+9Nl3_YdKP6%Cxy@6TxZ>;4&nTneadr z_ES90ydCev)LV!dN=#(*f}|ZORFdvkYBni^aLbUk>BajeWIOcmHP#8S)*2U~QKI%S zyrLmtPqb&TphJ;>yAxri#;{uyk`JJqODDw%(Z=2`1uc}br^V%>j!gS)D*q*f_-qf8&D;W1dJgQMlaH5er zN2U<%Smb7==vE}dDI8K7cKz!vs^73o9f>2sgiTzWcwY|BMYHH5%Vn7#kiw&eItCqa zIkR2~Q}>X=Ar8W|^Ms41Fm8o6IB2_j60eOeBB1Br!boW7JnoeX6Gs)?7rW0^5psc- zjS16yb>dFn>KPOF;imD}e!enuIniFzv}n$m2#gCCv4jM#ArwlzZ$7@9&XkFxZ4n!V zj3dyiwW4Ki2QG{@i>yuZXQizw_OkZI^-3otXC{!(lUpJF33gI60ak;Uqitp74|B6I zgg{b=Iz}WkhCGj1M=hu4#Aw173YxIVbISaoc z-nLZC*6Tgivd5V`K%GxhBsp@SUU60-rfc$=wb>zdJzXS&-5(NRRodFk;Kxk!S(O(a0e7oY=E( zAyS;Ow?6Q&XA+cnkCb{28_1N8H#?J!*$MmIwLq^*T_9-z^&UE@A(z9oGYtFy6EZef LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/src/app/globals.css b/src/app/globals.css new file mode 100644 index 00000000..a2dc41ec --- /dev/null +++ b/src/app/globals.css @@ -0,0 +1,26 @@ +@import "tailwindcss"; + +:root { + --background: #ffffff; + --foreground: #171717; +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #0a0a0a; + --foreground: #ededed; + } +} + +body { + background: var(--background); + color: var(--foreground); + font-family: Arial, Helvetica, sans-serif; +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx new file mode 100644 index 00000000..f7fa87eb --- /dev/null +++ b/src/app/layout.tsx @@ -0,0 +1,34 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx new file mode 100644 index 00000000..295f8fdf --- /dev/null +++ b/src/app/page.tsx @@ -0,0 +1,65 @@ +import Image from "next/image"; + +export default function Home() { + return ( +
+
+ Next.js logo +
+

+ To get started, edit the page.tsx file. +

+

+ Looking for a starting point or more instructions? Head over to{" "} + + Templates + {" "} + or the{" "} + + Learning + {" "} + center. +

+
+ +
+
+ ); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..cf9c65d3 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts", + "**/*.mts" + ], + "exclude": ["node_modules"] +} From 38a8dc93d1637f502e5e179bca93716f126e534d Mon Sep 17 00:00:00 2001 From: liaibo Date: Sun, 23 Nov 2025 10:45:45 +0800 Subject: [PATCH 2/2] chore: remove luckysheet integration --- components.json | 22 + dev-3001.err | 78 + dev-3001.out | 60 + frontend-3001.err | 1 + frontend-3001.out | 11 + frontend.err | 12 + frontend.out | 6 + package.json | 49 +- pnpm-lock.yaml | 4649 +++++++++++++++++ src/app/(app)/documents/[id]/loading.tsx | 11 + src/app/(app)/documents/[id]/page.tsx | 61 + src/app/(app)/layout.tsx | 55 + src/app/(auth)/login/page.tsx | 91 + src/app/api/.gitkeep | 0 src/app/api/documents/create-child/route.ts | 99 + src/app/api/documents/create/route.ts | 123 + src/app/api/documents/delete/route.ts | 36 + src/app/api/documents/duplicate/route.ts | 74 + src/app/api/documents/embed/route.ts | 76 + src/app/api/documents/empty-trash/route.ts | 53 + src/app/api/documents/move/route.ts | 37 + src/app/api/documents/options/route.ts | 61 + src/app/api/documents/purge/route.ts | 33 + src/app/api/documents/restore/route.ts | 38 + src/app/api/documents/save/route.ts | 32 + src/app/api/documents/stats/route.ts | 40 + src/app/api/documents/title/route.ts | 32 + src/app/api/media/assets/route.ts | 92 + src/app/api/media/ocr/route.ts | 43 + src/app/api/media/upload/route.ts | 82 + src/app/api/references/backlinks/route.ts | 50 + src/app/api/references/record/route.ts | 68 + src/app/api/search/documents/route.ts | 303 ++ src/app/api/search/recent/route.ts | 54 + src/app/api/sidebar/route.ts | 47 + src/app/api/workspaces/switch/route.ts | 54 + src/app/globals.css | 408 +- src/app/layout.tsx | 35 +- src/app/page.tsx | 102 +- src/components/bottom-toolbar.tsx | 36 + src/components/breadcrumb.tsx | 63 + src/components/common/.gitkeep | 0 src/components/document-task-panel.tsx | 87 + src/components/editor/.gitkeep | 0 src/components/editor/blocknote-editor.tsx | 585 +++ .../editor/blocks/AdvancedTodoBlock.tsx | 56 + src/components/editor/blocks/MediaBlock.tsx | 498 ++ .../editor/blocks/PageReferenceBlock.tsx | 114 + .../editor/blocks/ProgressBlock.tsx | 50 + src/components/editor/document-content.tsx | 259 + .../editor/document-history-drawer.tsx | 51 + src/components/editor/document-shell.tsx | 37 + src/components/editor/document-toc.tsx | 48 + .../editor/menus/CustomSideMenu.tsx | 335 ++ .../editor/menus/CustomSlashMenu.tsx | 343 ++ .../editor/page-backlinks-panel.tsx | 77 + .../editor/page-options-sidebar.tsx | 228 + src/components/editor/schema.ts | 36 + src/components/media/image-picker-context.tsx | 78 + src/components/media/image-picker-dialog.tsx | 392 ++ src/components/mindmap/.gitkeep | 0 src/components/mobile-sidebar-trigger.tsx | 19 + src/components/providers/query-provider.tsx | 31 + .../providers/supabase-provider.tsx | 18 + src/components/reference/page-hover-card.tsx | 39 + src/components/search/search-palette.tsx | 654 +++ src/components/sidebar/.gitkeep | 0 src/components/sidebar/private-tree.tsx | 257 + src/components/sidebar/sidebar.tsx | 1077 ++++ src/components/sidebar/types.ts | 19 + src/components/ui/avatar.tsx | 53 + src/components/ui/badge.tsx | 46 + src/components/ui/button.tsx | 60 + src/components/ui/card.tsx | 92 + src/components/ui/command.tsx | 184 + src/components/ui/dialog.tsx | 152 + src/components/ui/drawer.tsx | 135 + src/components/ui/dropdown-menu.tsx | 257 + src/components/ui/hover-card.tsx | 30 + src/components/ui/input.tsx | 21 + src/components/ui/label.tsx | 24 + src/components/ui/popover.tsx | 48 + src/components/ui/scroll-area.tsx | 58 + src/components/ui/separator.tsx | 28 + src/components/ui/sheet.tsx | 139 + src/components/ui/skeleton.tsx | 13 + src/components/ui/tabs.tsx | 66 + src/components/ui/textarea.tsx | 18 + src/components/ui/toggle.tsx | 47 + src/hooks/.gitkeep | 0 src/hooks/use-backend-health.ts | 40 + src/hooks/use-backlinks.ts | 61 + src/hooks/use-debounced-callback.ts | 41 + src/hooks/use-document-search.ts | 34 + src/hooks/use-reference-composer.ts | 77 + src/hooks/use-sidebar-data.ts | 28 + src/lib/document-content.ts | 30 + src/lib/documents.ts | 63 + src/lib/search/record-recent.ts | 14 + src/lib/search/request.test.ts | 45 + src/lib/search/request.ts | 38 + src/lib/search/shortcuts.test.ts | 17 + src/lib/search/shortcuts.ts | 17 + src/lib/search/snippet.test.ts | 14 + src/lib/search/snippet.ts | 24 + src/lib/server-cookies.ts | 46 + src/lib/sidebar-tree.ts | 141 + src/lib/supabase/client.ts | 13 + src/lib/supabase/server.ts | 16 + src/lib/utils.ts | 6 + src/lib/workspaces.ts | 142 + src/store/.gitkeep | 0 src/store/editor-bridge.ts | 25 + src/store/page-layout.ts | 18 + src/store/search-palette.ts | 109 + src/store/sidebar.ts | 59 + src/types/document.ts | 9 + src/types/media.ts | 27 + src/types/page-options.ts | 15 + src/types/references.ts | 13 + src/types/search.ts | 47 + src/types/supabase.ts | 532 ++ start-4000.err | 0 start-4000.out | 11 + tsconfig.json | 1 + vitest.config.ts | 9 + 126 files changed, 15824 insertions(+), 94 deletions(-) create mode 100644 components.json create mode 100644 dev-3001.err create mode 100644 dev-3001.out create mode 100644 frontend-3001.err create mode 100644 frontend-3001.out create mode 100644 frontend.err create mode 100644 frontend.out create mode 100644 src/app/(app)/documents/[id]/loading.tsx create mode 100644 src/app/(app)/documents/[id]/page.tsx create mode 100644 src/app/(app)/layout.tsx create mode 100644 src/app/(auth)/login/page.tsx create mode 100644 src/app/api/.gitkeep create mode 100644 src/app/api/documents/create-child/route.ts create mode 100644 src/app/api/documents/create/route.ts create mode 100644 src/app/api/documents/delete/route.ts create mode 100644 src/app/api/documents/duplicate/route.ts create mode 100644 src/app/api/documents/embed/route.ts create mode 100644 src/app/api/documents/empty-trash/route.ts create mode 100644 src/app/api/documents/move/route.ts create mode 100644 src/app/api/documents/options/route.ts create mode 100644 src/app/api/documents/purge/route.ts create mode 100644 src/app/api/documents/restore/route.ts create mode 100644 src/app/api/documents/save/route.ts create mode 100644 src/app/api/documents/stats/route.ts create mode 100644 src/app/api/documents/title/route.ts create mode 100644 src/app/api/media/assets/route.ts create mode 100644 src/app/api/media/ocr/route.ts create mode 100644 src/app/api/media/upload/route.ts create mode 100644 src/app/api/references/backlinks/route.ts create mode 100644 src/app/api/references/record/route.ts create mode 100644 src/app/api/search/documents/route.ts create mode 100644 src/app/api/search/recent/route.ts create mode 100644 src/app/api/sidebar/route.ts create mode 100644 src/app/api/workspaces/switch/route.ts create mode 100644 src/components/bottom-toolbar.tsx create mode 100644 src/components/breadcrumb.tsx create mode 100644 src/components/common/.gitkeep create mode 100644 src/components/document-task-panel.tsx create mode 100644 src/components/editor/.gitkeep create mode 100644 src/components/editor/blocknote-editor.tsx create mode 100644 src/components/editor/blocks/AdvancedTodoBlock.tsx create mode 100644 src/components/editor/blocks/MediaBlock.tsx create mode 100644 src/components/editor/blocks/PageReferenceBlock.tsx create mode 100644 src/components/editor/blocks/ProgressBlock.tsx create mode 100644 src/components/editor/document-content.tsx create mode 100644 src/components/editor/document-history-drawer.tsx create mode 100644 src/components/editor/document-shell.tsx create mode 100644 src/components/editor/document-toc.tsx create mode 100644 src/components/editor/menus/CustomSideMenu.tsx create mode 100644 src/components/editor/menus/CustomSlashMenu.tsx create mode 100644 src/components/editor/page-backlinks-panel.tsx create mode 100644 src/components/editor/page-options-sidebar.tsx create mode 100644 src/components/editor/schema.ts create mode 100644 src/components/media/image-picker-context.tsx create mode 100644 src/components/media/image-picker-dialog.tsx create mode 100644 src/components/mindmap/.gitkeep create mode 100644 src/components/mobile-sidebar-trigger.tsx create mode 100644 src/components/providers/query-provider.tsx create mode 100644 src/components/providers/supabase-provider.tsx create mode 100644 src/components/reference/page-hover-card.tsx create mode 100644 src/components/search/search-palette.tsx create mode 100644 src/components/sidebar/.gitkeep create mode 100644 src/components/sidebar/private-tree.tsx create mode 100644 src/components/sidebar/sidebar.tsx create mode 100644 src/components/sidebar/types.ts create mode 100644 src/components/ui/avatar.tsx create mode 100644 src/components/ui/badge.tsx create mode 100644 src/components/ui/button.tsx create mode 100644 src/components/ui/card.tsx create mode 100644 src/components/ui/command.tsx create mode 100644 src/components/ui/dialog.tsx create mode 100644 src/components/ui/drawer.tsx create mode 100644 src/components/ui/dropdown-menu.tsx create mode 100644 src/components/ui/hover-card.tsx create mode 100644 src/components/ui/input.tsx create mode 100644 src/components/ui/label.tsx create mode 100644 src/components/ui/popover.tsx create mode 100644 src/components/ui/scroll-area.tsx create mode 100644 src/components/ui/separator.tsx create mode 100644 src/components/ui/sheet.tsx create mode 100644 src/components/ui/skeleton.tsx create mode 100644 src/components/ui/tabs.tsx create mode 100644 src/components/ui/textarea.tsx create mode 100644 src/components/ui/toggle.tsx create mode 100644 src/hooks/.gitkeep create mode 100644 src/hooks/use-backend-health.ts create mode 100644 src/hooks/use-backlinks.ts create mode 100644 src/hooks/use-debounced-callback.ts create mode 100644 src/hooks/use-document-search.ts create mode 100644 src/hooks/use-reference-composer.ts create mode 100644 src/hooks/use-sidebar-data.ts create mode 100644 src/lib/document-content.ts create mode 100644 src/lib/documents.ts create mode 100644 src/lib/search/record-recent.ts create mode 100644 src/lib/search/request.test.ts create mode 100644 src/lib/search/request.ts create mode 100644 src/lib/search/shortcuts.test.ts create mode 100644 src/lib/search/shortcuts.ts create mode 100644 src/lib/search/snippet.test.ts create mode 100644 src/lib/search/snippet.ts create mode 100644 src/lib/server-cookies.ts create mode 100644 src/lib/sidebar-tree.ts create mode 100644 src/lib/supabase/client.ts create mode 100644 src/lib/supabase/server.ts create mode 100644 src/lib/utils.ts create mode 100644 src/lib/workspaces.ts create mode 100644 src/store/.gitkeep create mode 100644 src/store/editor-bridge.ts create mode 100644 src/store/page-layout.ts create mode 100644 src/store/search-palette.ts create mode 100644 src/store/sidebar.ts create mode 100644 src/types/document.ts create mode 100644 src/types/media.ts create mode 100644 src/types/page-options.ts create mode 100644 src/types/references.ts create mode 100644 src/types/search.ts create mode 100644 src/types/supabase.ts create mode 100644 start-4000.err create mode 100644 start-4000.out create mode 100644 vitest.config.ts diff --git a/components.json b/components.json new file mode 100644 index 00000000..edcaef26 --- /dev/null +++ b/components.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": {} +} diff --git a/dev-3001.err b/dev-3001.err new file mode 100644 index 00000000..a3d18b4e --- /dev/null +++ b/dev-3001.err @@ -0,0 +1,78 @@ +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\node_modules__pnpm_ecee5139._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +Error: Route "/documents/[id]" used `params.id`. `params` is a Promise and must be unwrapped with `await` or `React.use()` before accessing its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis + at DocumentPage (F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js:120:150) +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\node_modules__pnpm_ecee5139._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +Error: Route "/documents/[id]" used `params.id`. `params` is a Promise and must be unwrapped with `await` or `React.use()` before accessing its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis + at DocumentPage (F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js:120:150) +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\node_modules__pnpm_ecee5139._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +Error: Route "/documents/[id]" used `params.id`. `params` is a Promise and must be unwrapped with `await` or `React.use()` before accessing its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis + at DocumentPage (F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js:120:150) +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\node_modules__pnpm_ecee5139._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +Error: Route "/documents/[id]" used `params.id`. `params` is a Promise and must be unwrapped with `await` or `React.use()` before accessing its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis + at DocumentPage (F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js:120:150) +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\node_modules__pnpm_ecee5139._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +Error: Route "/documents/[id]" used `params.id`. `params` is a Promise and must be unwrapped with `await` or `React.use()` before accessing its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis + at DocumentPage (F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js:120:150) +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\node_modules__pnpm_ecee5139._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +Error: Route "/documents/[id]" used `params.id`. `params` is a Promise and must be unwrapped with `await` or `React.use()` before accessing its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis + at DocumentPage (F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js:120:150) +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\node_modules__pnpm_ecee5139._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +Error: Route "/documents/[id]" used `params.id`. `params` is a Promise and must be unwrapped with `await` or `React.use()` before accessing its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis + at DocumentPage (F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js:120:150) +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\node_modules__pnpm_ecee5139._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +Error: Route "/documents/[id]" used `params.id`. `params` is a Promise and must be unwrapped with `await` or `React.use()` before accessing its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis + at DocumentPage (F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js:120:150) +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\node_modules__pnpm_ecee5139._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +Error: Route "/documents/[id]" used `params.id`. `params` is a Promise and must be unwrapped with `await` or `React.use()` before accessing its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis + at DocumentPage (F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js:120:150) +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\node_modules__pnpm_ecee5139._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +Error: Route "/documents/[id]" used `params.id`. `params` is a Promise and must be unwrapped with `await` or `React.use()` before accessing its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis + at DocumentPage (F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js:120:150) +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\node_modules__pnpm_ecee5139._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +Error: Route "/documents/[id]" used `params.id`. `params` is a Promise and must be unwrapped with `await` or `React.use()` before accessing its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis + at DocumentPage (F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__d0423852._.js:120:150) +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server. +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\2536e_@blocknote_react_dist_blocknote-react_65a5c21f.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +F:\SOFT\MNOTE\wolai-frontend\node_modules\.pnpm\next@16.0.3_@babel+core@7.2_a6e7fe7b2107bfd5c9e45031e322c5c3\node_modules\next\dist\compiled\next-server\app-page-turbo.runtime.dev.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__c5e4d87b._.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed + ⨯ ReferenceError: window is not defined + at (F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\2536e_@blocknote_react_dist_blocknote-react_65a5c21f.js:421:9) + at Se (F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\2536e_@blocknote_react_dist_blocknote-react_65a5c21f.js:419:354) + at BlockNoteEditor (F:\SOFT\MNOTE\wolai-frontend\.next\dev\server\chunks\ssr\[root-of-the-server]__c5e4d87b._.js:87:315) { + digest: '2629247923' +} diff --git a/dev-3001.out b/dev-3001.out new file mode 100644 index 00000000..ec7079e8 --- /dev/null +++ b/dev-3001.out @@ -0,0 +1,60 @@ + +> wolai-frontend@0.1.0 dev F:\SOFT\MNOTE\wolai-frontend +> next dev "--port" "3001" + + ▲ Next.js 16.0.3 (Turbopack) + - Local: http://localhost:3001 + - Network: http://192.168.121.1:3001 + - Environments: .env.local + + ✓ Starting... + ✓ Ready in 729ms + GET /login 200 in 2.3s (compile: 2.1s, render: 265ms) + GET / 200 in 613ms (compile: 365ms, render: 248ms) + GET /documents/2b01d6b7-dc39-49b9-97bb-0be59956e6fb 200 in 3.4s (compile: 2.9s, render: 473ms) + GET /documents/2b01d6b7-dc39-49b9-97bb-0be59956e6fb 200 in 442ms (compile: 26ms, render: 415ms) + GET /documents/1f256e20-0ef4-4090-9bec-954fcd799a4c 200 in 245ms (compile: 25ms, render: 220ms) + POST /api/documents/create 200 in 424ms (compile: 311ms, render: 113ms) + GET /documents/880f0a7a-e894-465b-a64d-bea1afa3da48 200 in 62ms (compile: 27ms, render: 34ms) + GET /documents/1f256e20-0ef4-4090-9bec-954fcd799a4c 200 in 68ms (compile: 22ms, render: 47ms) + GET /documents/e8b15472-3665-425e-b945-0de6bc9a15fb 200 in 56ms (compile: 22ms, render: 35ms) + GET /documents/880f0a7a-e894-465b-a64d-bea1afa3da48 200 in 56ms (compile: 22ms, render: 34ms) + GET / 307 in 297ms (compile: 2ms, render: 295ms) + GET /documents/2b01d6b7-dc39-49b9-97bb-0be59956e6fb 200 in 222ms (compile: 23ms, render: 199ms) + GET / 307 in 102ms (compile: 3ms, render: 99ms) + GET /login 200 in 53ms (compile: 3ms, render: 49ms) + GET / 200 in 20ms (compile: 3ms, render: 17ms) + GET /login 200 in 35ms (compile: 4ms, render: 31ms) + GET /login 200 in 18ms (compile: 2ms, render: 15ms) + GET / 200 in 20ms (compile: 3ms, render: 17ms) + GET /login 200 in 34ms (compile: 3ms, render: 31ms) + GET /login 200 in 18ms (compile: 2ms, render: 16ms) + GET / 307 in 108ms (compile: 3ms, render: 105ms) + GET /login 200 in 57ms (compile: 5ms, render: 52ms) + GET / 307 in 193ms (compile: 3ms, render: 190ms) + GET /documents/2b01d6b7-dc39-49b9-97bb-0be59956e6fb 200 in 125ms (compile: 23ms, render: 102ms) + GET / 200 in 27ms (compile: 4ms, render: 23ms) + GET /login 200 in 34ms (compile: 3ms, render: 31ms) + GET /login 200 in 19ms (compile: 3ms, render: 16ms) + GET / 200 in 19ms (compile: 3ms, render: 16ms) + GET /login 200 in 39ms (compile: 3ms, render: 36ms) + GET /login 200 in 19ms (compile: 3ms, render: 16ms) + GET / 200 in 20ms (compile: 3ms, render: 18ms) + GET /login 200 in 40ms (compile: 9ms, render: 31ms) + GET /login 200 in 19ms (compile: 2ms, render: 17ms) + GET / 200 in 27ms (compile: 5ms, render: 22ms) + GET /login 200 in 41ms (compile: 3ms, render: 37ms) + GET /login 200 in 21ms (compile: 2ms, render: 18ms) + GET / 200 in 23ms (compile: 3ms, render: 20ms) + GET /login 200 in 40ms (compile: 3ms, render: 37ms) + GET /login 200 in 22ms (compile: 3ms, render: 19ms) + GET /documents/2b01d6b7-dc39-49b9-97bb-0be59956e6fb 307 in 181ms (compile: 29ms, render: 152ms) + GET /login 200 in 60ms (compile: 3ms, render: 57ms) + ✓ Compiled in 90ms + GET /login 200 in 235ms (compile: 93ms, render: 142ms) + GET /login 200 in 42ms (compile: 3ms, render: 39ms) + GET / 200 in 175ms (compile: 93ms, render: 82ms) + GET /documents/2b01d6b7-dc39-49b9-97bb-0be59956e6fb 200 in 313ms (compile: 125ms, render: 188ms) + GET /documents/2b01d6b7-dc39-49b9-97bb-0be59956e6fb 200 in 67ms (compile: 4ms, render: 64ms) + GET /documents/2b01d6b7-dc39-49b9-97bb-0be59956e6fb 200 in 235ms (compile: 118ms, render: 117ms) + GET /documents/2b01d6b7-dc39-49b9-97bb-0be59956e6fb 200 in 611ms (compile: 24ms, render: 587ms) diff --git a/frontend-3001.err b/frontend-3001.err new file mode 100644 index 00000000..3438401f --- /dev/null +++ b/frontend-3001.err @@ -0,0 +1 @@ +^C \ No newline at end of file diff --git a/frontend-3001.out b/frontend-3001.out new file mode 100644 index 00000000..10e564f3 --- /dev/null +++ b/frontend-3001.out @@ -0,0 +1,11 @@ + +> wolai-frontend@0.1.0 dev F:\SOFT\MNOTE\wolai-frontend +> next dev "--port" "3001" + + ▲ Next.js 16.0.3 (Turbopack) + - Local: http://localhost:3001 + - Network: http://192.168.121.1:3001 + - Environments: .env.local + + ✓ Starting... + ✓ Ready in 876ms diff --git a/frontend.err b/frontend.err new file mode 100644 index 00000000..20dd8848 --- /dev/null +++ b/frontend.err @@ -0,0 +1,12 @@ + ⨯ Failed to start server +F:\SOFT\MNOTE\wolai-frontend\node_modules\.pnpm\next@16.0.3_@babel+core@7.2_a6e7fe7b2107bfd5c9e45031e322c5c3\node_modules\next\dist\server\lib\start-server.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +F:\SOFT\MNOTE\wolai-frontend\node_modules\.pnpm\next@16.0.3_@babel+core@7.2_a6e7fe7b2107bfd5c9e45031e322c5c3\node_modules\next\dist\trace\trace.js: Invalid source map. Only conformant source maps can be used to find the original code. Cause: Error: sourceMapURL could not be parsed +Error: listen EADDRINUSE: address already in use :::3000 + at (Error: listen EADDRINUSE: address already in use :::3000) + at new Promise () { + code: 'EADDRINUSE', + errno: -4091, + syscall: 'listen', + address: '::', + port: 3000 +} diff --git a/frontend.out b/frontend.out new file mode 100644 index 00000000..0117337c --- /dev/null +++ b/frontend.out @@ -0,0 +1,6 @@ + +> wolai-frontend@0.1.0 dev F:\SOFT\MNOTE\wolai-frontend +> next dev "--port" "3000" + +[?25h + ELIFECYCLE  Command failed with exit code 1. diff --git a/package.json b/package.json index b4a80332..00deb845 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,52 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "eslint" + "lint": "eslint", + "test": "vitest" }, "dependencies": { + "@blocknote/core": "^0.42.0", + "@blocknote/mantine": "0.42.0", + "@blocknote/react": "^0.42.0", + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", + "@hello-pangea/dnd": "^18.0.1", + "@hocuspocus/provider": "^2.15.3", + "@radix-ui/react-avatar": "^1.1.11", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-hover-card": "^1.1.15", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-separator": "^1.1.8", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-toggle": "^1.1.10", + "@supabase/auth-helpers-nextjs": "^0.10.0", + "@supabase/auth-helpers-react": "^0.5.0", + "@supabase/supabase-js": "^2.81.1", + "@tanstack/react-query": "^5.90.10", + "@tanstack/react-query-devtools": "^5.90.2", + "@tanstack/react-virtual": "^3.11.0", + "@xyflow/react": "^12.9.3", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "cmdk": "^1.1.1", + "lucide-react": "^0.554.0", "next": "16.0.3", "react": "19.2.0", - "react-dom": "19.2.0" + "react-dom": "19.2.0", + "react-dropzone": "^14.3.8", + "react-icons": "5.5.0", + "sonner": "^2.0.7", + "tailwind-merge": "^3.4.0", + "uuid": "^13.0.0", + "vaul": "^1.1.2", + "y-protocols": "^1.0.6", + "yjs": "^13.6.27", + "zustand": "^5.0.8" }, "devDependencies": { "@tailwindcss/postcss": "^4", @@ -20,7 +60,10 @@ "@types/react-dom": "^19", "eslint": "^9", "eslint-config-next": "16.0.3", + "jsdom": "^27.2.0", "tailwindcss": "^4", - "typescript": "^5" + "tw-animate-css": "^1.4.0", + "typescript": "^5", + "vitest": "^4.0.13" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2fcaeb93..63f970ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,96 @@ importers: .: dependencies: + '@blocknote/core': + specifier: ^0.42.0 + version: 0.42.0(@hocuspocus/provider@2.15.3(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27))(@tiptap/extensions@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7))(@types/hast@3.0.4) + '@blocknote/mantine': + specifier: 0.42.0 + version: 0.42.0(@floating-ui/dom@1.7.4)(@hocuspocus/provider@2.15.3(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27))(@mantine/core@8.3.8(@mantine/hooks@8.3.8(react@19.2.0))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@mantine/hooks@8.3.8(react@19.2.0))(@mantine/utils@6.0.22(react@19.2.0))(@tiptap/extensions@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7))(@types/hast@3.0.4)(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@blocknote/react': + specifier: ^0.42.0 + version: 0.42.0(@floating-ui/dom@1.7.4)(@hocuspocus/provider@2.15.3(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27))(@tiptap/extensions@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7))(@types/hast@3.0.4)(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@dnd-kit/core': + specifier: ^6.3.1 + version: 6.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@dnd-kit/sortable': + specifier: ^10.0.0 + version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) + '@dnd-kit/utilities': + specifier: ^3.2.2 + version: 3.2.2(react@19.2.0) + '@hello-pangea/dnd': + specifier: ^18.0.1 + version: 18.0.1(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@hocuspocus/provider': + specifier: ^2.15.3 + version: 2.15.3(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27) + '@radix-ui/react-avatar': + specifier: ^1.1.11 + version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-dialog': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-dropdown-menu': + specifier: ^2.1.16 + version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-hover-card': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-label': + specifier: ^2.1.8 + version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-popover': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-scroll-area': + specifier: ^1.2.10 + version: 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-separator': + specifier: ^1.1.8 + version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': + specifier: ^1.2.4 + version: 1.2.4(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-tabs': + specifier: ^1.1.13 + version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-toggle': + specifier: ^1.1.10 + version: 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@supabase/auth-helpers-nextjs': + specifier: ^0.10.0 + version: 0.10.0(@supabase/supabase-js@2.81.1) + '@supabase/auth-helpers-react': + specifier: ^0.5.0 + version: 0.5.0(@supabase/supabase-js@2.81.1) + '@supabase/supabase-js': + specifier: ^2.81.1 + version: 2.81.1 + '@tanstack/react-query': + specifier: ^5.90.10 + version: 5.90.10(react@19.2.0) + '@tanstack/react-query-devtools': + specifier: ^5.90.2 + version: 5.90.2(@tanstack/react-query@5.90.10(react@19.2.0))(react@19.2.0) + '@tanstack/react-virtual': + specifier: ^3.11.0 + version: 3.13.12(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@xyflow/react': + specifier: ^12.9.3 + version: 12.9.3(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + cmdk: + specifier: ^1.1.1 + version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + lucide-react: + specifier: ^0.554.0 + version: 0.554.0(react@19.2.0) next: specifier: 16.0.3 version: 16.0.3(@babel/core@7.28.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -17,6 +107,33 @@ importers: react-dom: specifier: 19.2.0 version: 19.2.0(react@19.2.0) + react-dropzone: + specifier: ^14.3.8 + version: 14.3.8(react@19.2.0) + react-icons: + specifier: 5.5.0 + version: 5.5.0(react@19.2.0) + sonner: + specifier: ^2.0.7 + version: 2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + tailwind-merge: + specifier: ^3.4.0 + version: 3.4.0 + uuid: + specifier: ^13.0.0 + version: 13.0.0 + vaul: + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + y-protocols: + specifier: ^1.0.6 + version: 1.0.6(yjs@13.6.27) + yjs: + specifier: ^13.6.27 + version: 13.6.27 + zustand: + specifier: ^5.0.8 + version: 5.0.8(@types/react@19.2.5)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) devDependencies: '@tailwindcss/postcss': specifier: ^4 @@ -36,19 +153,40 @@ importers: eslint-config-next: specifier: 16.0.3 version: 16.0.3(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + jsdom: + specifier: ^27.2.0 + version: 27.2.0 tailwindcss: specifier: ^4 version: 4.1.17 + tw-animate-css: + specifier: ^1.4.0 + version: 1.4.0 typescript: specifier: ^5 version: 5.9.3 + vitest: + specifier: ^4.0.13 + version: 4.0.13(@types/debug@4.1.12)(@types/node@20.19.25)(jiti@2.6.1)(jsdom@27.2.0)(lightningcss@1.30.2) packages: + '@acemir/cssom@0.9.23': + resolution: {integrity: sha512-2kJ1HxBKzPLbmhZpxBiTZggjtgCwKg1ma5RHShxvd6zgqhDEdEkzpiwe7jLkI2p2BrZvFCXIihdoMkl1H39VnA==} + '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@asamuzakjp/css-color@4.1.0': + resolution: {integrity: sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==} + + '@asamuzakjp/dom-selector@6.7.4': + resolution: {integrity: sha512-buQDjkm+wDPXd6c13534URWZqbz0RP5PAhXZ+LIoa5LgwInT9HVJvGIJivg75vi8I13CxDGdTnz+aY5YUJlIAA==} + + '@asamuzakjp/nwsapi@2.3.9': + resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -104,6 +242,10 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} @@ -116,6 +258,83 @@ packages: resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} + '@blocknote/core@0.42.0': + resolution: {integrity: sha512-V478pyJFTJxdKmVo2ICqKNVzuRNgBOK3Zg3Ut1AKozrOGJ2mB4h1esDncK01P/DSCLDro6TmSobOrVAF55w1uA==} + peerDependencies: + '@hocuspocus/provider': ^2.15.2 + peerDependenciesMeta: + '@hocuspocus/provider': + optional: true + + '@blocknote/mantine@0.42.0': + resolution: {integrity: sha512-N4sbfFm6mJaS9oRBOibyUUDdWDns1350m3CAUJXJzmTCp0ugOlVm+TPzMj2ENnALwkYEDtLWIDXrfen7XQ8r6Q==} + peerDependencies: + '@mantine/core': ^8.3.4 + '@mantine/hooks': ^8.3.4 + '@mantine/utils': ^6.0.22 + react: ^18.0 || ^19.0 || >= 19.0.0-rc + react-dom: ^18.0 || ^19.0 || >= 19.0.0-rc + + '@blocknote/react@0.42.0': + resolution: {integrity: sha512-6o2lUdzQAffe20mkb8q+KnNZLQ5MjAMztnMV14I0eraSpdFfNt11msASbL6uYXTwLL8mLSGaMUojcR8mLv3u1w==} + peerDependencies: + react: ^18.0 || ^19.0 || >= 19.0.0-rc + react-dom: ^18.0 || ^19.0 || >= 19.0.0-rc + + '@csstools/color-helpers@5.1.0': + resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} + engines: {node: '>=18'} + + '@csstools/css-calc@2.1.4': + resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-color-parser@3.1.0': + resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-parser-algorithms@3.0.5': + resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-syntax-patches-for-csstree@1.0.17': + resolution: {integrity: sha512-LCC++2h8pLUSPY+EsZmrrJ1EOUu+5iClpEiDhhdw3zRJpPbABML/N5lmRuBHjxtKm9VnRcsUzioyD0sekFMF0A==} + engines: {node: '>=18'} + + '@csstools/css-tokenizer@3.0.4': + resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} + engines: {node: '>=18'} + + '@dnd-kit/accessibility@3.1.1': + resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} + peerDependencies: + react: '>=16.8.0' + + '@dnd-kit/core@6.3.1': + resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@dnd-kit/sortable@10.0.0': + resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==} + peerDependencies: + '@dnd-kit/core': ^6.3.0 + react: '>=16.8.0' + + '@dnd-kit/utilities@3.2.2': + resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} + peerDependencies: + react: '>=16.8.0' + '@emnapi/core@1.7.1': resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} @@ -125,6 +344,165 @@ packages: '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@emoji-mart/data@1.2.1': + resolution: {integrity: sha512-no2pQMWiBy6gpBEiqGeU77/bFejDqUTRY7KX+0+iur13op3bqUsXdnwoZs6Xb1zbv0gAj5VvS1PWoUUckSr5Dw==} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.0': resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -163,6 +541,42 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/react@0.27.16': + resolution: {integrity: sha512-9O8N4SeG2z++TSM8QA/KTeKFBVCNEz/AGS7gWPJf6KFRzmRWixFRnCnkPHRDwSVZW6QPDO6uT0P2SpWNKCc9/g==} + peerDependencies: + react: '>=17.0.0' + react-dom: '>=17.0.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@hello-pangea/dnd@18.0.1': + resolution: {integrity: sha512-xojVWG8s/TGrKT1fC8K2tIWeejJYTAeJuj36zM//yEm/ZrnZUSFGS15BpO+jGZT1ybWvyXmeDJwPYb4dhWlbZQ==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + + '@hocuspocus/common@2.15.3': + resolution: {integrity: sha512-Rzh1HF0a2o/tf90A3w2XNdXd9Ym3aQzMDfD3lAUONCX9B9QOdqdyiORrj6M25QEaJrEIbXFy8LtAFcL0wRdWzA==} + + '@hocuspocus/provider@2.15.3': + resolution: {integrity: sha512-oadN05m+KL4ylNKVo5YspNG4MXkT2Y+FUFzrgigpQeTjQibkPUwCNmUnkUxMgrGRgxb+O0lJCfirFIJMxedctA==} + peerDependencies: + y-protocols: ^1.0.6 + yjs: ^13.6.8 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -332,6 +746,26 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@lifeomic/attempt@3.1.0': + resolution: {integrity: sha512-QZqem4QuAnAyzfz+Gj5/+SLxqwCAw2qmt7732ZXodr6VDWGeYLG6w1i/vYLa55JQM9wRuBKLmXmiZ2P0LtE5rw==} + + '@mantine/core@8.3.8': + resolution: {integrity: sha512-UM3Za7Yl0FzbZ2zPgHwNyCpLgtSqkAi8ku13+gRS/6JB0FjwSkMwibERUqQIpwqAHdR5KNmIohjuqHu8guJowg==} + peerDependencies: + '@mantine/hooks': 8.3.8 + react: ^18.x || ^19.x + react-dom: ^18.x || ^19.x + + '@mantine/hooks@8.3.8': + resolution: {integrity: sha512-2YCUk5IWz+Ebi7VpbdscUz1MwulyaVPKr236ugMfpK0PFwsun4aBaLCAc8UeMGP0LtoSkuFvnsCPR4U6rhNfeQ==} + peerDependencies: + react: ^18.x || ^19.x + + '@mantine/utils@6.0.22': + resolution: {integrity: sha512-RSKlNZvxhMCkOFZ6slbYvZYbWjHUM+PxDQnupIOxIdsTZQQjx/BFfrfJ7kQFOP+g7MtpOds8weAetEs5obwMOQ==} + peerDependencies: + react: '>=16.8.0' + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -405,9 +839,599 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-avatar@1.1.11': + resolution: {integrity: sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.3': + resolution: {integrity: sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.15': + resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.11': + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dropdown-menu@2.1.16': + resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.3': + resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-hover-card@1.1.15': + resolution: {integrity: sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-label@2.1.8': + resolution: {integrity: sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menu@2.1.16': + resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popover@1.1.15': + resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.8': + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.4': + resolution: {integrity: sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.11': + resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-scroll-area@1.2.10': + resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-separator@1.1.8': + resolution: {integrity: sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-slot@1.2.4': + resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-tabs@1.1.13': + resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toggle@1.1.10': + resolution: {integrity: sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-is-hydrated@0.1.0': + resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + + '@remirror/core-constants@3.0.0': + resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} + + '@rollup/rollup-android-arm-eabi@4.53.3': + resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.53.3': + resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.53.3': + resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.53.3': + resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.53.3': + resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.53.3': + resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.53.3': + resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.53.3': + resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.53.3': + resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.53.3': + resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.53.3': + resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.53.3': + resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.53.3': + resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.53.3': + resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.53.3': + resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.53.3': + resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.53.3': + resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.53.3': + resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} + cpu: [x64] + os: [win32] + '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@shikijs/types@3.13.0': + resolution: {integrity: sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + + '@supabase/auth-helpers-nextjs@0.10.0': + resolution: {integrity: sha512-2dfOGsM4yZt0oS4TPiE7bD4vf7EVz7NRz/IJrV6vLg0GP7sMUx8wndv2euLGq4BjN9lUCpu6DG/uCC8j+ylwPg==} + deprecated: This package is now deprecated - please use the @supabase/ssr package instead. + peerDependencies: + '@supabase/supabase-js': ^2.39.8 + + '@supabase/auth-helpers-react@0.5.0': + resolution: {integrity: sha512-5QSaV2CGuhDhd7RlQCoviVEAYsP7XnrFMReOcBazDvVmqSIyjKcDwhLhWvnrxMOq5qjOaA44MHo7wXqDiF0puQ==} + deprecated: This package is now deprecated - please use the @supabase/ssr package instead. + peerDependencies: + '@supabase/supabase-js': ^2.39.8 + + '@supabase/auth-helpers-shared@0.7.0': + resolution: {integrity: sha512-FBFf2ei2R7QC+B/5wWkthMha8Ca2bWHAndN+syfuEUUfufv4mLcAgBCcgNg5nJR8L0gZfyuaxgubtOc9aW3Cpg==} + deprecated: This package is now deprecated - please use the @supabase/ssr package instead. + peerDependencies: + '@supabase/supabase-js': ^2.39.8 + + '@supabase/auth-js@2.81.1': + resolution: {integrity: sha512-K20GgiSm9XeRLypxYHa5UCnybWc2K0ok0HLbqCej/wRxDpJxToXNOwKt0l7nO8xI1CyQ+GrNfU6bcRzvdbeopQ==} + engines: {node: '>=20.0.0'} + + '@supabase/functions-js@2.81.1': + resolution: {integrity: sha512-sYgSO3mlgL0NvBFS3oRfCK4OgKGQwuOWJLzfPyWg0k8MSxSFSDeN/JtrDJD5GQrxskP6c58+vUzruBJQY78AqQ==} + engines: {node: '>=20.0.0'} + + '@supabase/postgrest-js@2.81.1': + resolution: {integrity: sha512-DePpUTAPXJyBurQ4IH2e42DWoA+/Qmr5mbgY4B6ZcxVc/ZUKfTVK31BYIFBATMApWraFc8Q/Sg+yxtfJ3E0wSg==} + engines: {node: '>=20.0.0'} + + '@supabase/realtime-js@2.81.1': + resolution: {integrity: sha512-ViQ+Kxm8BuUP/TcYmH9tViqYKGSD1LBjdqx2p5J+47RES6c+0QHedM0PPAjthMdAHWyb2LGATE9PD2++2rO/tw==} + engines: {node: '>=20.0.0'} + + '@supabase/storage-js@2.81.1': + resolution: {integrity: sha512-UNmYtjnZnhouqnbEMC1D5YJot7y0rIaZx7FG2Fv8S3hhNjcGVvO+h9We/tggi273BFkiahQPS/uRsapo1cSapw==} + engines: {node: '>=20.0.0'} + + '@supabase/supabase-js@2.81.1': + resolution: {integrity: sha512-KSdY7xb2L0DlLmlYzIOghdw/na4gsMcqJ8u4sD6tOQJr+x3hLujU9s4R8N3ob84/1bkvpvlU5PYKa1ae+OICnw==} + engines: {node: '>=20.0.0'} + '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} @@ -499,21 +1523,189 @@ packages: '@tailwindcss/postcss@4.1.17': resolution: {integrity: sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw==} + '@tanstack/query-core@5.90.10': + resolution: {integrity: sha512-EhZVFu9rl7GfRNuJLJ3Y7wtbTnENsvzp+YpcAV7kCYiXni1v8qZh++lpw4ch4rrwC0u/EZRnBHIehzCGzwXDSQ==} + + '@tanstack/query-devtools@5.90.1': + resolution: {integrity: sha512-GtINOPjPUH0OegJExZ70UahT9ykmAhmtNVcmtdnOZbxLwT7R5OmRztR5Ahe3/Cu7LArEmR6/588tAycuaWb1xQ==} + + '@tanstack/react-query-devtools@5.90.2': + resolution: {integrity: sha512-vAXJzZuBXtCQtrY3F/yUNJCV4obT/A/n81kb3+YqLbro5Z2+phdAbceO+deU3ywPw8B42oyJlp4FhO0SoivDFQ==} + peerDependencies: + '@tanstack/react-query': ^5.90.2 + react: ^18 || ^19 + + '@tanstack/react-query@5.90.10': + resolution: {integrity: sha512-BKLss9Y8PQ9IUjPYQiv3/Zmlx92uxffUOX8ZZNoQlCIZBJPT5M+GOMQj7xislvVQ6l1BstBjcX0XB/aHfFYVNw==} + peerDependencies: + react: ^18 || ^19 + + '@tanstack/react-virtual@3.13.12': + resolution: {integrity: sha512-Gd13QdxPSukP8ZrkbgS2RwoZseTTbQPLnQEn7HY/rqtM+8Zt95f7xKC7N0EsKs7aoz0WzZ+fditZux+F8EzYxA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/virtual-core@3.13.12': + resolution: {integrity: sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA==} + + '@tiptap/core@3.10.7': + resolution: {integrity: sha512-4rD3oHkXNOS6Fxm0mr+ECyq35iMFnnAXheIO+UsQbOexwTxn2yZ5Q1rQiFKcCf+p+rrg1yt8TtxQPM8VLWS+1g==} + peerDependencies: + '@tiptap/pm': ^3.10.7 + + '@tiptap/extension-bold@3.10.7': + resolution: {integrity: sha512-NWjOIIZdxUSkWLQrEY4Tg60MzS6RGt/1aLnwTyFFzFFShzOmd/xzxp0fRS+p79ZKNcQa9OKgnrlS4xuRq8WOdQ==} + peerDependencies: + '@tiptap/core': ^3.10.7 + + '@tiptap/extension-bubble-menu@3.10.7': + resolution: {integrity: sha512-ezsNpClKQ4Bq6R+Y/jGcmxhSBuYYOCGXV72yy3SlX1w6seA/I8h27ktWy9zAD2RPX560NzpZEyBjaASL3961sQ==} + peerDependencies: + '@tiptap/core': ^3.10.7 + '@tiptap/pm': ^3.10.7 + + '@tiptap/extension-code@3.10.7': + resolution: {integrity: sha512-POK3CCy29LoRI6JVvFRVAmH2G90a7pKJT8sbqOaX1WKmLLDt7drUxGgBNnz/cBXJQHPnXZgRq/P8ZQPISklT7Q==} + peerDependencies: + '@tiptap/core': ^3.10.7 + + '@tiptap/extension-floating-menu@3.10.7': + resolution: {integrity: sha512-yuTIGDbx0Q2IWOUrkhVQ/i1fU0Qi+8fCS8jkGB34/+3nbhtqXNYfFajpeaU9rkcCJqXH4aiFJdSGy44kCnYP2g==} + peerDependencies: + '@floating-ui/dom': ^1.0.0 + '@tiptap/core': ^3.10.7 + '@tiptap/pm': ^3.10.7 + + '@tiptap/extension-gapcursor@3.10.7': + resolution: {integrity: sha512-1VDNX+4ZCKxuoj6nRTZDwHjPYhuSdELYYCSfxscojlwexPxCLcgqOt71xdgnQXW5Hv6ACT4OrGGYcGTupudOHg==} + peerDependencies: + '@tiptap/extensions': ^3.10.7 + + '@tiptap/extension-history@3.10.7': + resolution: {integrity: sha512-QP0JZbA3jm3GY/VZNM3KC5bMkraj3GHglw1HAr1jcwIjwkvGS+Q6SmrfBTovTzT7y23QpZAPNKpToxy7X76C7A==} + peerDependencies: + '@tiptap/extensions': ^3.10.7 + + '@tiptap/extension-horizontal-rule@3.10.7': + resolution: {integrity: sha512-V9uWb341QUBDDbR3aoSs3Sx0PQQaKwZ/ESVEE03El9rkIrf8g5K82x8/M0nvSOvGobt6oRyI/rgbj196YQuXiQ==} + peerDependencies: + '@tiptap/core': ^3.10.7 + '@tiptap/pm': ^3.10.7 + + '@tiptap/extension-italic@3.10.7': + resolution: {integrity: sha512-1CQgHNm51xDyZI188f5xKLcUIjRS+2cyZgS9XwKwIU/3QOsiKsNC+cBc4VmN3aR0A01NjK0ch0MjeKkPPWUt5A==} + peerDependencies: + '@tiptap/core': ^3.10.7 + + '@tiptap/extension-link@3.10.7': + resolution: {integrity: sha512-AIgrtveTQ5QyRpcic2MVSuv9aOaN0n+swdZPvi8XREZX/uf1SU4dYU7p0dNChhcn53GGPDNVRTQXX4YdEAZFQQ==} + peerDependencies: + '@tiptap/core': ^3.10.7 + '@tiptap/pm': ^3.10.7 + + '@tiptap/extension-paragraph@3.10.7': + resolution: {integrity: sha512-53+nCxNaKcmeqQ+aWrSauEWywuWPp8qkUTOO2rHlpmM+rk/1bv3IZePKQ2JtHZzYCeRd3xOC33kl60HE7EwakQ==} + peerDependencies: + '@tiptap/core': ^3.10.7 + + '@tiptap/extension-strike@3.10.7': + resolution: {integrity: sha512-pZMdQhChv59jsahvmjiJjSTPM05J6EHAX/GPdA9w8xSKy73899MhIhWJ7yt2CJEPjwn3ixnomIPhMjxBkizv+g==} + peerDependencies: + '@tiptap/core': ^3.10.7 + + '@tiptap/extension-text@3.10.7': + resolution: {integrity: sha512-b7Rjil/uqiabWnRHyd1P84rWD2XRyZZSrmIAO9mDMD/jB2bE+f7rDJcHG76GF03UicDhEEEf2/8mz0dMLa6mUA==} + peerDependencies: + '@tiptap/core': ^3.10.7 + + '@tiptap/extension-underline@3.10.7': + resolution: {integrity: sha512-yBL81xdbjT5Y7acoBqWpnH/SoH3bpgqaLvJBG3NNk+mdLB5HjBWTlPLKjvjQV0HRN5bZ+RJWeiRnQk1ahcfmQA==} + peerDependencies: + '@tiptap/core': ^3.10.7 + + '@tiptap/extensions@3.10.7': + resolution: {integrity: sha512-jYYR7NA7t2hdyJmSLYVAJ3usyIOZ2mfFqPCCHbSn/k3jqmGaPFZuxJSwmYjfmTxisZ9rGn+49/YJF2y/Yej/0Q==} + peerDependencies: + '@tiptap/core': ^3.10.7 + '@tiptap/pm': ^3.10.7 + + '@tiptap/pm@3.10.7': + resolution: {integrity: sha512-/iiurioqSukJk6CrEtfRpdOEafDybyVPToAllgn7i2XcusXSxJSX+K0GUndMUwVR+UqVOCyMYBTRTnE0hdQqgA==} + + '@tiptap/react@3.10.7': + resolution: {integrity: sha512-hhKj62zvs/mSu5HlcmZDRFHVHCjJ6v6/7vB45MTAziP+cZ0+CEbEh2rnGNRNwooumWwm5pWdkVqI1efp7GtnUA==} + peerDependencies: + '@tiptap/core': ^3.10.7 + '@tiptap/pm': ^3.10.7 + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + '@types/react-dom': ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node@20.19.25': resolution: {integrity: sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==} + '@types/phoenix@1.6.6': + resolution: {integrity: sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==} + '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: @@ -522,6 +1714,15 @@ packages: '@types/react@19.2.5': resolution: {integrity: sha512-keKxkZMqnDicuvFoJbzrhbtdLSPhj/rZThDlKWCDbgXmUg0rEUFtRssDXKYmtXluZlIqiC5VqkCgRwzuyLHKHw==} + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/use-sync-external-store@0.0.6': + resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} + + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@typescript-eslint/eslint-plugin@8.47.0': resolution: {integrity: sha512-fe0rz9WJQ5t2iaLfdbDc9T80GJy0AeO453q8C3YCilnGozvOyCG5t+EZtg7j7D88+c3FipfP/x+wzGnh1xp8ZA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -581,6 +1782,9 @@ packages: resolution: {integrity: sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@unrs/resolver-binding-android-arm-eabi@1.11.1': resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} cpu: [arm] @@ -676,6 +1880,44 @@ packages: cpu: [x64] os: [win32] + '@vitest/expect@4.0.13': + resolution: {integrity: sha512-zYtcnNIBm6yS7Gpr7nFTmq8ncowlMdOJkWLqYvhr/zweY6tFbDkDi8BPPOeHxEtK1rSI69H7Fd4+1sqvEGli6w==} + + '@vitest/mocker@4.0.13': + resolution: {integrity: sha512-eNCwzrI5djoauklwP1fuslHBjrbR8rqIVbvNlAnkq1OTa6XT+lX68mrtPirNM9TnR69XUPt4puBCx2Wexseylg==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.0.13': + resolution: {integrity: sha512-ooqfze8URWbI2ozOeLDMh8YZxWDpGXoeY3VOgcDnsUxN0jPyPWSUvjPQWqDGCBks+opWlN1E4oP1UYl3C/2EQA==} + + '@vitest/runner@4.0.13': + resolution: {integrity: sha512-9IKlAru58wcVaWy7hz6qWPb2QzJTKt+IOVKjAx5vb5rzEFPTL6H4/R9BMvjZ2ppkxKgTrFONEJFtzvnyEpiT+A==} + + '@vitest/snapshot@4.0.13': + resolution: {integrity: sha512-hb7Usvyika1huG6G6l191qu1urNPsq1iFc2hmdzQY3F5/rTgqQnwwplyf8zoYHkpt7H6rw5UfIw6i/3qf9oSxQ==} + + '@vitest/spy@4.0.13': + resolution: {integrity: sha512-hSu+m4se0lDV5yVIcNWqjuncrmBgwaXa2utFLIrBkQCQkt+pSwyZTPFQAZiiF/63j8jYa8uAeUZ3RSfcdWaYWw==} + + '@vitest/utils@4.0.13': + resolution: {integrity: sha512-ydozWyQ4LZuu8rLp47xFUWis5VOKMdHjXCWhs1LuJsTNKww+pTHQNK4e0assIB9K80TxFyskENL6vCu3j34EYA==} + + '@xyflow/react@12.9.3': + resolution: {integrity: sha512-PSWoJ8vHiEqSIkLIkge+0eiHWiw4C6dyFDA03VKWJkqbU4A13VlDIVwKqf/Znuysn2GQw/zA61zpHE4rGgax7Q==} + peerDependencies: + react: '>=17' + react-dom: '>=17' + + '@xyflow/system@0.0.73': + resolution: {integrity: sha512-C2ymH2V4mYDkdVSiRx0D7R0s3dvfXiupVBcko6tXP5K4tVdSBMo22/e3V9yRNdn+2HQFv44RFKzwOyCcUUDAVQ==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -686,6 +1928,10 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -696,6 +1942,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + aria-query@5.3.2: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} @@ -732,6 +1982,10 @@ packages: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} @@ -739,6 +1993,10 @@ packages: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} + attr-accept@2.2.5: + resolution: {integrity: sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==} + engines: {node: '>=4'} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -751,6 +2009,9 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -758,6 +2019,9 @@ packages: resolution: {integrity: sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA==} hasBin: true + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -792,13 +2056,45 @@ packages: caniuse-lite@1.0.30001755: resolution: {integrity: sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==} + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chai@6.2.1: + resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} + engines: {node: '>=18'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + classcat@5.0.5: + resolution: {integrity: sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==} + client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + cmdk@1.1.1: + resolution: {integrity: sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==} + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + react-dom: ^18 || ^19 || ^19.0.0-rc + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -806,22 +2102,81 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + css-box-model@1.2.1: + resolution: {integrity: sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==} + + css-tree@3.1.0: + resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + cssstyle@5.3.3: + resolution: {integrity: sha512-OytmFH+13/QXONJcC75QNdMtKpceNk3u8ThBjyyYjkEcy/ekBwR1mMAuNvi3gdBPW3N5TlCzQ0WZw8H0lN/bDw==} + engines: {node: '>=20'} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + data-urls@6.0.0: + resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==} + engines: {node: '>=20'} + data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -851,6 +2206,12 @@ packages: supports-color: optional: true + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + + decode-named-character-reference@1.2.0: + resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -862,10 +2223,20 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -877,6 +2248,9 @@ packages: electron-to-chromium@1.5.255: resolution: {integrity: sha512-Z9oIp4HrFF/cZkDPMpz2XSuVpc1THDpT4dlmATFlJUIBVCy9Vap5/rIXsASP1CscBacBqhabwh8vLctqBwEerQ==} + emoji-mart@5.6.0: + resolution: {integrity: sha512-eJp3QRe79pjwa+duv+n7+5YsNhRcMl812EcFVwrnRvYKoNPoQb5qxU8DG6Bgwji0akHdp6D4Ln6tYLG58MFSow==} + emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} @@ -884,6 +2258,14 @@ packages: resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} engines: {node: '>=10.13.0'} + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + es-abstract@1.24.0: resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} engines: {node: '>= 0.4'} @@ -900,6 +2282,9 @@ packages: resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} engines: {node: '>= 0.4'} + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -916,6 +2301,11 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -924,6 +2314,10 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + eslint-config-next@16.0.3: resolution: {integrity: sha512-5F6qDjcZldf0Y0ZbqvWvap9xzYUxyDf7/of37aeyhvkrQokj/4bT1JYWZdlWUr283aeVa+s52mPq9ogmGg+5dw==} peerDependencies: @@ -1036,10 +2430,20 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + expect-type@1.2.2: + resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} + engines: {node: '>=12.0.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1073,6 +2477,10 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + file-selector@2.1.2: + resolution: {integrity: sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==} + engines: {node: '>= 12'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -1092,6 +2500,11 @@ packages: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} @@ -1114,6 +2527,10 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -1182,12 +2599,82 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hast-util-embedded@3.0.0: + resolution: {integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==} + + hast-util-format@1.1.0: + resolution: {integrity: sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==} + + hast-util-from-dom@5.0.1: + resolution: {integrity: sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-has-property@3.0.0: + resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} + + hast-util-is-body-ok-link@3.0.1: + resolution: {integrity: sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-minify-whitespace@1.0.1: + resolution: {integrity: sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-phrasing@3.0.1: + resolution: {integrity: sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-mdast@10.1.2: + resolution: {integrity: sha512-FiCRI7NmOvM4y+f5w32jPRzcxDIz+PUqDwEqn1A+1q2cdp3B8Gx7aVrXORdOKjMNDQsD1ogOr896+0jJHW1EFQ==} + + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + html-whitespace-sensitive-tag-names@3.0.1: + resolution: {integrity: sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1275,6 +2762,13 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -1317,6 +2811,9 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isomorphic.js@0.2.5: + resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + iterator.prototype@1.1.5: resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} @@ -1325,6 +2822,9 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jose@4.15.9: + resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1332,6 +2832,15 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + jsdom@27.2.0: + resolution: {integrity: sha512-454TI39PeRDW1LgpyLPyURtB4Zx1tklSr6+OFOipsxGUH1WMTvk6C65JQdrj455+DP2uJ1+veBEHTGFKWVLFoA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -1373,6 +2882,11 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lib0@0.2.114: + resolution: {integrity: sha512-gcxmNFzA4hv8UYi8j43uPlQ7CGcyMJ2KQb5kZASw6SnAKAf10hK12i2fjrS3Cl/ugZa5Ui6WwIu1/6MIXiHttQ==} + engines: {node: '>=16'} + hasBin: true + lightningcss-android-arm64@1.30.2: resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} engines: {node: '>= 12.0.0'} @@ -1443,6 +2957,12 @@ packages: resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + + linkifyjs@4.3.2: + resolution: {integrity: sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1450,24 +2970,169 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + lru-cache@11.2.2: + resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lucide-react@0.554.0: + resolution: {integrity: sha512-St+z29uthEJVx0Is7ellNkgTEhaeSoA42I7JjOCBCrc5X6LYMGSv0P/2uS5HDLTExP5tpiqRD2PyUEOS6s9UXA==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.0: + resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + mdn-data@2.12.2: + resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -1558,6 +3223,9 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + orderedmap@2.1.1: + resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} + own-keys@1.0.1: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} @@ -1574,6 +3242,12 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + parse5@8.0.0: + resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -1585,6 +3259,9 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1615,6 +3292,106 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + + prosemirror-changeset@2.3.1: + resolution: {integrity: sha512-j0kORIBm8ayJNl3zQvD1TTPHJX3g042et6y/KQhZhnPrruO8exkTgG8X+NRpj7kIyMMEx74Xb3DyMIBtO0IKkQ==} + + prosemirror-collab@1.3.1: + resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==} + + prosemirror-commands@1.7.1: + resolution: {integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==} + + prosemirror-dropcursor@1.8.2: + resolution: {integrity: sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==} + + prosemirror-gapcursor@1.4.0: + resolution: {integrity: sha512-z00qvurSdCEWUIulij/isHaqu4uLS8r/Fi61IbjdIPJEonQgggbJsLnstW7Lgdk4zQ68/yr6B6bf7sJXowIgdQ==} + + prosemirror-highlight@0.13.0: + resolution: {integrity: sha512-GIC2VCTUnukNdsEGLQWWOVpYPl/7/KrVp4xs7XMB48/4rhUrHK8hp8TEog4Irmv+2kmjx24RLnaisGOCP6U8jw==} + peerDependencies: + '@shikijs/types': ^1.29.2 || ^2.0.0 || ^3.0.0 + '@types/hast': ^3.0.0 + highlight.js: ^11.9.0 + lowlight: ^3.1.0 + prosemirror-model: ^1.19.3 + prosemirror-state: ^1.4.3 + prosemirror-transform: ^1.8.0 + prosemirror-view: ^1.32.4 + refractor: ^5.0.0 + sugar-high: ^0.6.1 || ^0.7.0 || ^0.8.0 || ^0.9.0 + peerDependenciesMeta: + '@shikijs/types': + optional: true + '@types/hast': + optional: true + highlight.js: + optional: true + lowlight: + optional: true + prosemirror-model: + optional: true + prosemirror-state: + optional: true + prosemirror-transform: + optional: true + prosemirror-view: + optional: true + refractor: + optional: true + sugar-high: + optional: true + + prosemirror-history@1.5.0: + resolution: {integrity: sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==} + + prosemirror-inputrules@1.5.1: + resolution: {integrity: sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==} + + prosemirror-keymap@1.2.3: + resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==} + + prosemirror-markdown@1.13.2: + resolution: {integrity: sha512-FPD9rHPdA9fqzNmIIDhhnYQ6WgNoSWX9StUZ8LEKapaXU9i6XgykaHKhp6XMyXlOWetmaFgGDS/nu/w9/vUc5g==} + + prosemirror-menu@1.2.5: + resolution: {integrity: sha512-qwXzynnpBIeg1D7BAtjOusR+81xCp53j7iWu/IargiRZqRjGIlQuu1f3jFi+ehrHhWMLoyOQTSRx/IWZJqOYtQ==} + + prosemirror-model@1.25.4: + resolution: {integrity: sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==} + + prosemirror-schema-basic@1.2.4: + resolution: {integrity: sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==} + + prosemirror-schema-list@1.5.1: + resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==} + + prosemirror-state@1.4.4: + resolution: {integrity: sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==} + + prosemirror-tables@1.8.1: + resolution: {integrity: sha512-DAgDoUYHCcc6tOGpLVPSU1k84kCUWTWnfWX3UDy2Delv4ryH0KqTD6RBI6k4yi9j9I8gl3j8MkPpRD/vWPZbug==} + + prosemirror-trailing-node@3.0.0: + resolution: {integrity: sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==} + peerDependencies: + prosemirror-model: ^1.22.1 + prosemirror-state: ^1.4.2 + prosemirror-view: ^1.33.8 + + prosemirror-transform@1.10.5: + resolution: {integrity: sha512-RPDQCxIDhIBb1o36xxwsaeAvivO8VLJcgBtzmOwQ64bMtsVFh5SSuJ6dWSxO1UsHTiTXPCgQm3PDJt7p6IOLbw==} + + prosemirror-view@1.41.3: + resolution: {integrity: sha512-SqMiYMUQNNBP9kfPhLO8WXEk/fon47vc52FQsUiJzTBuyjKgEcoAwMyF04eQ4WZ2ArMn7+ReypYL60aKngbACQ==} + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1622,18 +3399,89 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + raf-schd@4.0.3: + resolution: {integrity: sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==} + react-dom@19.2.0: resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} peerDependencies: react: ^19.2.0 + react-dropzone@14.3.8: + resolution: {integrity: sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug==} + engines: {node: '>= 10.13'} + peerDependencies: + react: '>= 16.8 || 18.0.0' + + react-icons@5.5.0: + resolution: {integrity: sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==} + peerDependencies: + react: '*' + react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-number-format@5.4.4: + resolution: {integrity: sha512-wOmoNZoOpvMminhifQYiYSTCLUDOiUbBunrMrMjA+dV52sY+vck1S4UhR6PkgnoCquvvMSeJjErXZ4qSaWCliA==} + peerDependencies: + react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-redux@9.2.0: + resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==} + peerDependencies: + '@types/react': ^18.2.25 || ^19 + react: ^18.0 || ^19 + redux: ^5.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + redux: + optional: true + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.1: + resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-textarea-autosize@8.5.9: + resolution: {integrity: sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==} + engines: {node: '>=10'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react@19.2.0: resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} engines: {node: '>=0.10.0'} + redux@5.0.1: + resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -1642,6 +3490,37 @@ packages: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} + rehype-format@5.0.1: + resolution: {integrity: sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==} + + rehype-minify-whitespace@6.0.2: + resolution: {integrity: sha512-Zk0pyQ06A3Lyxhe9vGtOtzz3Z0+qZ5+7icZ/PL/2x1SHPbKao5oB/g/rlc6BCTajqBb33JcOe71Ye1oFsuYbnw==} + + rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} + + rehype-remark@10.0.1: + resolution: {integrity: sha512-EmDndlb5NVwXGfUa4c9GPK+lXeItTilLhE6ADSaQuHr4JUlKw9MidzGzx4HpqZrNCt6vnHmEifXQiiA+CEnjYQ==} + + rehype-stringify@10.0.1: + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1662,6 +3541,14 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rollup@4.53.3: + resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rope-sequence@1.3.4: + resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -1677,6 +3564,13 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -1689,6 +3583,9 @@ packages: engines: {node: '>=10'} hasBin: true + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -1729,13 +3626,31 @@ packages: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + sonner@2.0.7: + resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + stable-hash@0.0.5: resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} @@ -1763,6 +3678,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -1792,6 +3710,15 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + tabbable@6.3.0: + resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} + + tailwind-merge@3.4.0: + resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} + tailwindcss@4.1.17: resolution: {integrity: sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==} @@ -1799,14 +3726,51 @@ packages: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + engines: {node: '>=14.0.0'} + + tldts-core@7.0.18: + resolution: {integrity: sha512-jqJC13oP4FFAahv4JT/0WTDrCF9Okv7lpKtOZUGPLiAnNbACcSg8Y8T+Z9xthOmRBqi/Sob4yi0TE0miRCvF7Q==} + + tldts@7.0.18: + resolution: {integrity: sha512-lCcgTAgMxQ1JKOWrVGo6E69Ukbnx4Gc1wiYLRf6J5NN4HRYJtCby1rPF8rkQ4a6qqoFBK5dvjJ1zJ0F7VfDSvw==} + hasBin: true + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + tough-cookie@6.0.0: + resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} + engines: {node: '>=16'} + + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trim-trailing-lines@2.1.0: + resolution: {integrity: sha512-5UR5Biq4VlVOtzqkm2AZlgvSlDJtME46uV0br0gENbwN4l5+mMKT4b9gJKqWtuL2zAIqajGJGuvbCbcAJUZqBg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-api-utils@2.1.0: resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} engines: {node: '>=18.12'} @@ -1819,10 +3783,17 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tw-animate-css@1.4.0: + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -1851,6 +3822,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -1858,6 +3832,27 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} @@ -1870,6 +3865,184 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-composed-ref@1.4.0: + resolution: {integrity: sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-isomorphic-layout-effect@1.2.1: + resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-latest@1.3.0: + resolution: {integrity: sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + uuid@13.0.0: + resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==} + hasBin: true + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + vaul@1.1.2: + resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite@7.2.4: + resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.0.13: + resolution: {integrity: sha512-QSD4I0fN6uZQfftryIXuqvqgBxTvJ3ZNkF6RWECd82YGAYAfhcppBLFXzXJHQAAhVFyYEuFTrq6h0hQqjB7jIQ==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/debug': ^4.1.12 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.0.13 + '@vitest/browser-preview': 4.0.13 + '@vitest/browser-webdriverio': 4.0.13 + '@vitest/ui': 4.0.13 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + webidl-conversions@8.0.0: + resolution: {integrity: sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==} + engines: {node: '>=20'} + + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-url@15.1.0: + resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} + engines: {node: '>=20'} + which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} @@ -1891,13 +4064,57 @@ packages: engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + 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 + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + + y-prosemirror@1.3.7: + resolution: {integrity: sha512-NpM99WSdD4Fx4if5xOMDpPtU3oAmTSjlzh5U4353ABbRHl1HtAFUx6HlebLZfyFxXN9jzKMDkVbcRjqOZVkYQg==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + peerDependencies: + prosemirror-model: ^1.7.1 + prosemirror-state: ^1.2.3 + prosemirror-view: ^1.9.10 + y-protocols: ^1.0.1 + yjs: ^13.5.38 + + y-protocols@1.0.6: + resolution: {integrity: sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + peerDependencies: + yjs: ^13.0.0 + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yjs@13.6.27: + resolution: {integrity: sha512-OIDwaflOaq4wC6YlPBy2L6ceKeKuF7DeTxx+jPzv1FHn9tCZ0ZwSRnUBxD05E3yed46fv/FWJbvR+Ud7x0L7zw==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -1911,10 +4128,66 @@ packages: zod@4.1.12: resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==} + zustand@4.5.7: + resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} + engines: {node: '>=12.7.0'} + peerDependencies: + '@types/react': '>=16.8' + immer: '>=9.0.6' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + + zustand@5.0.8: + resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + snapshots: + '@acemir/cssom@0.9.23': {} + '@alloc/quick-lru@5.2.0': {} + '@asamuzakjp/css-color@4.1.0': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + lru-cache: 11.2.2 + + '@asamuzakjp/dom-selector@6.7.4': + dependencies: + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.1.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.2.2 + + '@asamuzakjp/nwsapi@2.3.9': {} + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -1992,6 +4265,8 @@ snapshots: dependencies: '@babel/types': 7.28.5 + '@babel/runtime@7.28.4': {} + '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 @@ -2015,6 +4290,154 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@blocknote/core@0.42.0(@hocuspocus/provider@2.15.3(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27))(@tiptap/extensions@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7))(@types/hast@3.0.4)': + dependencies: + '@emoji-mart/data': 1.2.1 + '@shikijs/types': 3.13.0 + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + '@tiptap/extension-bold': 3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7)) + '@tiptap/extension-code': 3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7)) + '@tiptap/extension-gapcursor': 3.10.7(@tiptap/extensions@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7)) + '@tiptap/extension-history': 3.10.7(@tiptap/extensions@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7)) + '@tiptap/extension-horizontal-rule': 3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7) + '@tiptap/extension-italic': 3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7)) + '@tiptap/extension-link': 3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7) + '@tiptap/extension-paragraph': 3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7)) + '@tiptap/extension-strike': 3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7)) + '@tiptap/extension-text': 3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7)) + '@tiptap/extension-underline': 3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7)) + '@tiptap/pm': 3.10.7 + emoji-mart: 5.6.0 + fast-deep-equal: 3.1.3 + hast-util-from-dom: 5.0.1 + prosemirror-dropcursor: 1.8.2 + prosemirror-highlight: 0.13.0(@shikijs/types@3.13.0)(@types/hast@3.0.4)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-transform@1.10.5)(prosemirror-view@1.41.3) + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-tables: 1.8.1 + prosemirror-transform: 1.10.5 + prosemirror-view: 1.41.3 + rehype-format: 5.0.1 + rehype-parse: 9.0.1 + rehype-remark: 10.0.1 + rehype-stringify: 10.0.1 + remark-gfm: 4.0.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + remark-stringify: 11.0.0 + unified: 11.0.5 + unist-util-visit: 5.0.0 + uuid: 8.3.2 + y-prosemirror: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.3)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27) + y-protocols: 1.0.6(yjs@13.6.27) + yjs: 13.6.27 + optionalDependencies: + '@hocuspocus/provider': 2.15.3(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27) + transitivePeerDependencies: + - '@tiptap/extensions' + - '@types/hast' + - highlight.js + - lowlight + - refractor + - sugar-high + - supports-color + + '@blocknote/mantine@0.42.0(@floating-ui/dom@1.7.4)(@hocuspocus/provider@2.15.3(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27))(@mantine/core@8.3.8(@mantine/hooks@8.3.8(react@19.2.0))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@mantine/hooks@8.3.8(react@19.2.0))(@mantine/utils@6.0.22(react@19.2.0))(@tiptap/extensions@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7))(@types/hast@3.0.4)(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@blocknote/core': 0.42.0(@hocuspocus/provider@2.15.3(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27))(@tiptap/extensions@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7))(@types/hast@3.0.4) + '@blocknote/react': 0.42.0(@floating-ui/dom@1.7.4)(@hocuspocus/provider@2.15.3(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27))(@tiptap/extensions@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7))(@types/hast@3.0.4)(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@mantine/core': 8.3.8(@mantine/hooks@8.3.8(react@19.2.0))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@mantine/hooks': 8.3.8(react@19.2.0) + '@mantine/utils': 6.0.22(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-icons: 5.5.0(react@19.2.0) + transitivePeerDependencies: + - '@floating-ui/dom' + - '@hocuspocus/provider' + - '@tiptap/extensions' + - '@types/hast' + - '@types/react' + - '@types/react-dom' + - highlight.js + - lowlight + - refractor + - sugar-high + - supports-color + + '@blocknote/react@0.42.0(@floating-ui/dom@1.7.4)(@hocuspocus/provider@2.15.3(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27))(@tiptap/extensions@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7))(@types/hast@3.0.4)(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@blocknote/core': 0.42.0(@hocuspocus/provider@2.15.3(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27))(@tiptap/extensions@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7))(@types/hast@3.0.4) + '@emoji-mart/data': 1.2.1 + '@floating-ui/react': 0.27.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + '@tiptap/pm': 3.10.7 + '@tiptap/react': 3.10.7(@floating-ui/dom@1.7.4)(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7)(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + emoji-mart: 5.6.0 + lodash.merge: 4.6.2 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-icons: 5.5.0(react@19.2.0) + transitivePeerDependencies: + - '@floating-ui/dom' + - '@hocuspocus/provider' + - '@tiptap/extensions' + - '@types/hast' + - '@types/react' + - '@types/react-dom' + - highlight.js + - lowlight + - refractor + - sugar-high + - supports-color + + '@csstools/color-helpers@5.1.0': {} + + '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/color-helpers': 5.1.0 + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-syntax-patches-for-csstree@1.0.17': {} + + '@csstools/css-tokenizer@3.0.4': {} + + '@dnd-kit/accessibility@3.1.1(react@19.2.0)': + dependencies: + react: 19.2.0 + tslib: 2.8.1 + + '@dnd-kit/core@6.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@dnd-kit/accessibility': 3.1.1(react@19.2.0) + '@dnd-kit/utilities': 3.2.2(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + tslib: 2.8.1 + + '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)': + dependencies: + '@dnd-kit/core': 6.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@dnd-kit/utilities': 3.2.2(react@19.2.0) + react: 19.2.0 + tslib: 2.8.1 + + '@dnd-kit/utilities@3.2.2(react@19.2.0)': + dependencies: + react: 19.2.0 + tslib: 2.8.1 + '@emnapi/core@1.7.1': dependencies: '@emnapi/wasi-threads': 1.1.0 @@ -2031,6 +4454,86 @@ snapshots: tslib: 2.8.1 optional: true + '@emoji-mart/data@1.2.1': {} + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.6.1))': dependencies: eslint: 9.39.1(jiti@2.6.1) @@ -2077,6 +4580,59 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@floating-ui/react@0.27.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@floating-ui/utils': 0.2.10 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + tabbable: 6.3.0 + + '@floating-ui/utils@0.2.10': {} + + '@hello-pangea/dnd@18.0.1(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@babel/runtime': 7.28.4 + css-box-model: 1.2.1 + raf-schd: 4.0.3 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-redux: 9.2.0(@types/react@19.2.5)(react@19.2.0)(redux@5.0.1) + redux: 5.0.1 + transitivePeerDependencies: + - '@types/react' + + '@hocuspocus/common@2.15.3': + dependencies: + lib0: 0.2.114 + + '@hocuspocus/provider@2.15.3(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27)': + dependencies: + '@hocuspocus/common': 2.15.3 + '@lifeomic/attempt': 3.1.0 + lib0: 0.2.114 + ws: 8.18.3 + y-protocols: 1.0.6(yjs@13.6.27) + yjs: 13.6.27 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -2204,6 +4760,30 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@lifeomic/attempt@3.1.0': {} + + '@mantine/core@8.3.8(@mantine/hooks@8.3.8(react@19.2.0))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@floating-ui/react': 0.27.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@mantine/hooks': 8.3.8(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-number-format: 5.4.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.5)(react@19.2.0) + react-textarea-autosize: 8.5.9(@types/react@19.2.5)(react@19.2.0) + type-fest: 4.41.0 + transitivePeerDependencies: + - '@types/react' + + '@mantine/hooks@8.3.8(react@19.2.0)': + dependencies: + react: 19.2.0 + + '@mantine/utils@6.0.22(react@19.2.0)': + dependencies: + react: 19.2.0 + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.7.1 @@ -2255,8 +4835,545 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} + '@radix-ui/number@1.1.1': {} + + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-avatar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-context': 1.1.3(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.5)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-context@1.1.2(@types/react@19.2.5)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-context@1.1.3(@types/react@19.2.5)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.5)(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.5)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-direction@1.1.1(@types/react@19.2.5)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.5)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-hover-card@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-id@1.1.1(@types/react@19.2.5)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.5)(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.5)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.5)(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.5)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/rect': 1.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-separator@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-slot@1.2.3(@types/react@19.2.5)(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-slot@1.2.4(@types/react@19.2.5)(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-toggle@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.5)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.5)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.5)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.5)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.2.5)(react@19.2.0)': + dependencies: + react: 19.2.0 + use-sync-external-store: 1.6.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.5)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.5)(react@19.2.0)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.5)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.5)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + '@radix-ui/rect@1.1.1': {} + + '@remirror/core-constants@3.0.0': {} + + '@rollup/rollup-android-arm-eabi@4.53.3': + optional: true + + '@rollup/rollup-android-arm64@4.53.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.53.3': + optional: true + + '@rollup/rollup-darwin-x64@4.53.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.53.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.53.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.53.3': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.53.3': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-x64-musl@4.53.3': + optional: true + + '@rollup/rollup-openharmony-arm64@4.53.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.53.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.53.3': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.53.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.53.3': + optional: true + '@rtsao/scc@1.1.0': {} + '@shikijs/types@3.13.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@standard-schema/spec@1.0.0': {} + + '@supabase/auth-helpers-nextjs@0.10.0(@supabase/supabase-js@2.81.1)': + dependencies: + '@supabase/auth-helpers-shared': 0.7.0(@supabase/supabase-js@2.81.1) + '@supabase/supabase-js': 2.81.1 + set-cookie-parser: 2.7.2 + + '@supabase/auth-helpers-react@0.5.0(@supabase/supabase-js@2.81.1)': + dependencies: + '@supabase/supabase-js': 2.81.1 + + '@supabase/auth-helpers-shared@0.7.0(@supabase/supabase-js@2.81.1)': + dependencies: + '@supabase/supabase-js': 2.81.1 + jose: 4.15.9 + + '@supabase/auth-js@2.81.1': + dependencies: + tslib: 2.8.1 + + '@supabase/functions-js@2.81.1': + dependencies: + tslib: 2.8.1 + + '@supabase/postgrest-js@2.81.1': + dependencies: + tslib: 2.8.1 + + '@supabase/realtime-js@2.81.1': + dependencies: + '@types/phoenix': 1.6.6 + '@types/ws': 8.18.1 + tslib: 2.8.1 + ws: 8.18.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@supabase/storage-js@2.81.1': + dependencies: + tslib: 2.8.1 + + '@supabase/supabase-js@2.81.1': + dependencies: + '@supabase/auth-js': 2.81.1 + '@supabase/functions-js': 2.81.1 + '@supabase/postgrest-js': 2.81.1 + '@supabase/realtime-js': 2.81.1 + '@supabase/storage-js': 2.81.1 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@swc/helpers@0.5.15': dependencies: tslib: 2.8.1 @@ -2330,21 +5447,205 @@ snapshots: postcss: 8.5.6 tailwindcss: 4.1.17 + '@tanstack/query-core@5.90.10': {} + + '@tanstack/query-devtools@5.90.1': {} + + '@tanstack/react-query-devtools@5.90.2(@tanstack/react-query@5.90.10(react@19.2.0))(react@19.2.0)': + dependencies: + '@tanstack/query-devtools': 5.90.1 + '@tanstack/react-query': 5.90.10(react@19.2.0) + react: 19.2.0 + + '@tanstack/react-query@5.90.10(react@19.2.0)': + dependencies: + '@tanstack/query-core': 5.90.10 + react: 19.2.0 + + '@tanstack/react-virtual@3.13.12(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@tanstack/virtual-core': 3.13.12 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@tanstack/virtual-core@3.13.12': {} + + '@tiptap/core@3.10.7(@tiptap/pm@3.10.7)': + dependencies: + '@tiptap/pm': 3.10.7 + + '@tiptap/extension-bold@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))': + dependencies: + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + + '@tiptap/extension-bubble-menu@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7)': + dependencies: + '@floating-ui/dom': 1.7.4 + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + '@tiptap/pm': 3.10.7 + optional: true + + '@tiptap/extension-code@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))': + dependencies: + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + + '@tiptap/extension-floating-menu@3.10.7(@floating-ui/dom@1.7.4)(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7)': + dependencies: + '@floating-ui/dom': 1.7.4 + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + '@tiptap/pm': 3.10.7 + optional: true + + '@tiptap/extension-gapcursor@3.10.7(@tiptap/extensions@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7))': + dependencies: + '@tiptap/extensions': 3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7) + + '@tiptap/extension-history@3.10.7(@tiptap/extensions@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7))': + dependencies: + '@tiptap/extensions': 3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7) + + '@tiptap/extension-horizontal-rule@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7)': + dependencies: + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + '@tiptap/pm': 3.10.7 + + '@tiptap/extension-italic@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))': + dependencies: + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + + '@tiptap/extension-link@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7)': + dependencies: + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + '@tiptap/pm': 3.10.7 + linkifyjs: 4.3.2 + + '@tiptap/extension-paragraph@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))': + dependencies: + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + + '@tiptap/extension-strike@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))': + dependencies: + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + + '@tiptap/extension-text@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))': + dependencies: + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + + '@tiptap/extension-underline@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))': + dependencies: + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + + '@tiptap/extensions@3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7)': + dependencies: + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + '@tiptap/pm': 3.10.7 + + '@tiptap/pm@3.10.7': + dependencies: + prosemirror-changeset: 2.3.1 + prosemirror-collab: 1.3.1 + prosemirror-commands: 1.7.1 + prosemirror-dropcursor: 1.8.2 + prosemirror-gapcursor: 1.4.0 + prosemirror-history: 1.5.0 + prosemirror-inputrules: 1.5.1 + prosemirror-keymap: 1.2.3 + prosemirror-markdown: 1.13.2 + prosemirror-menu: 1.2.5 + prosemirror-model: 1.25.4 + prosemirror-schema-basic: 1.2.4 + prosemirror-schema-list: 1.5.1 + prosemirror-state: 1.4.4 + prosemirror-tables: 1.8.1 + prosemirror-trailing-node: 3.0.0(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.3) + prosemirror-transform: 1.10.5 + prosemirror-view: 1.41.3 + + '@tiptap/react@3.10.7(@floating-ui/dom@1.7.4)(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7)(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@tiptap/core': 3.10.7(@tiptap/pm@3.10.7) + '@tiptap/pm': 3.10.7 + '@types/react': 19.2.5 + '@types/react-dom': 19.2.3(@types/react@19.2.5) + '@types/use-sync-external-store': 0.0.6 + fast-deep-equal: 3.1.3 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + use-sync-external-store: 1.6.0(react@19.2.0) + optionalDependencies: + '@tiptap/extension-bubble-menu': 3.10.7(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7) + '@tiptap/extension-floating-menu': 3.10.7(@floating-ui/dom@1.7.4)(@tiptap/core@3.10.7(@tiptap/pm@3.10.7))(@tiptap/pm@3.10.7) + transitivePeerDependencies: + - '@floating-ui/dom' + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 optional: true + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/d3-color@3.1.3': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/deep-eql@4.0.2': {} + '@types/estree@1.0.8': {} + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} + '@types/linkify-it@5.0.0': {} + + '@types/markdown-it@14.1.2': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdurl@2.0.0': {} + + '@types/ms@2.1.0': {} + '@types/node@20.19.25': dependencies: undici-types: 6.21.0 + '@types/phoenix@1.6.6': {} + '@types/react-dom@19.2.3(@types/react@19.2.5)': dependencies: '@types/react': 19.2.5 @@ -2353,6 +5654,14 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/unist@3.0.3': {} + + '@types/use-sync-external-store@0.0.6': {} + + '@types/ws@8.18.1': + dependencies: + '@types/node': 20.19.25 + '@typescript-eslint/eslint-plugin@8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -2446,6 +5755,8 @@ snapshots: '@typescript-eslint/types': 8.47.0 eslint-visitor-keys: 4.2.1 + '@ungap/structured-clone@1.3.0': {} + '@unrs/resolver-binding-android-arm-eabi@1.11.1': optional: true @@ -2505,12 +5816,76 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + '@vitest/expect@4.0.13': + dependencies: + '@standard-schema/spec': 1.0.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.0.13 + '@vitest/utils': 4.0.13 + chai: 6.2.1 + tinyrainbow: 3.0.3 + + '@vitest/mocker@4.0.13(vite@7.2.4(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2))': + dependencies: + '@vitest/spy': 4.0.13 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.2.4(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2) + + '@vitest/pretty-format@4.0.13': + dependencies: + tinyrainbow: 3.0.3 + + '@vitest/runner@4.0.13': + dependencies: + '@vitest/utils': 4.0.13 + pathe: 2.0.3 + + '@vitest/snapshot@4.0.13': + dependencies: + '@vitest/pretty-format': 4.0.13 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.0.13': {} + + '@vitest/utils@4.0.13': + dependencies: + '@vitest/pretty-format': 4.0.13 + tinyrainbow: 3.0.3 + + '@xyflow/react@12.9.3(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@xyflow/system': 0.0.73 + classcat: 5.0.5 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + zustand: 4.5.7(@types/react@19.2.5)(react@19.2.0) + transitivePeerDependencies: + - '@types/react' + - immer + + '@xyflow/system@0.0.73': + dependencies: + '@types/d3-drag': 3.0.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-zoom: 3.0.0 + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 acorn@8.15.0: {} + agent-base@7.1.4: {} + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -2524,6 +5899,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + aria-query@5.3.2: {} array-buffer-byte-length@1.0.2: @@ -2593,10 +5972,14 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 + assertion-error@2.0.1: {} + ast-types-flow@0.0.8: {} async-function@1.0.0: {} + attr-accept@2.2.5: {} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 @@ -2605,10 +5988,16 @@ snapshots: axobject-query@4.1.0: {} + bail@2.0.2: {} + balanced-match@1.0.2: {} baseline-browser-mapping@2.8.29: {} + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -2651,33 +6040,123 @@ snapshots: caniuse-lite@1.0.30001755: {} + ccount@2.0.1: {} + + chai@6.2.1: {} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + classcat@5.0.5: {} + client-only@0.0.1: {} + clsx@2.1.1: {} + + cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.5)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} + comma-separated-tokens@2.0.3: {} + concat-map@0.0.1: {} convert-source-map@2.0.0: {} + crelt@1.0.6: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + css-box-model@1.2.1: + dependencies: + tiny-invariant: 1.3.3 + + css-tree@3.1.0: + dependencies: + mdn-data: 2.12.2 + source-map-js: 1.2.1 + + cssstyle@5.3.3: + dependencies: + '@asamuzakjp/css-color': 4.1.0 + '@csstools/css-syntax-patches-for-csstree': 1.0.17 + css-tree: 3.1.0 + csstype@3.2.3: {} + d3-color@3.1.0: {} + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-ease@3.0.1: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-selection@3.0.0: {} + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + damerau-levenshtein@1.0.8: {} + data-urls@6.0.0: + dependencies: + whatwg-mimetype: 4.0.0 + whatwg-url: 15.1.0 + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -2704,6 +6183,12 @@ snapshots: dependencies: ms: 2.1.3 + decimal.js@10.6.0: {} + + decode-named-character-reference@1.2.0: + dependencies: + character-entities: 2.0.2 + deep-is@0.1.4: {} define-data-property@1.1.4: @@ -2718,8 +6203,16 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + dequal@2.0.3: {} + detect-libc@2.1.2: {} + detect-node-es@1.1.0: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -2732,6 +6225,8 @@ snapshots: electron-to-chromium@1.5.255: {} + emoji-mart@5.6.0: {} + emoji-regex@9.2.2: {} enhanced-resolve@5.18.3: @@ -2739,6 +6234,10 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.0 + entities@4.5.0: {} + + entities@6.0.1: {} + es-abstract@1.24.0: dependencies: array-buffer-byte-length: 1.0.2 @@ -2819,6 +6318,8 @@ snapshots: iterator.prototype: 1.1.5 safe-array-concat: 1.1.3 + es-module-lexer@1.7.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -2840,10 +6341,41 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + escalade@3.2.0: {} escape-string-regexp@4.0.0: {} + escape-string-regexp@5.0.0: {} + eslint-config-next@16.0.3(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): dependencies: '@next/eslint-plugin-next': 16.0.3 @@ -3045,8 +6577,16 @@ snapshots: estraverse@5.3.0: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + esutils@2.0.3: {} + expect-type@1.2.2: {} + + extend@3.0.2: {} + fast-deep-equal@3.1.3: {} fast-glob@3.3.1: @@ -3081,6 +6621,10 @@ snapshots: dependencies: flat-cache: 4.0.1 + file-selector@2.1.2: + dependencies: + tslib: 2.8.1 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -3101,6 +6645,9 @@ snapshots: dependencies: is-callable: 1.2.7 + fsevents@2.3.3: + optional: true + function-bind@1.1.2: {} function.prototype.name@1.1.8: @@ -3131,6 +6678,8 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 + get-nonce@1.0.1: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -3191,12 +6740,161 @@ snapshots: dependencies: function-bind: 1.1.2 + hast-util-embedded@3.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-is-element: 3.0.0 + + hast-util-format@1.1.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-minify-whitespace: 1.0.1 + hast-util-phrasing: 3.0.1 + hast-util-whitespace: 3.0.0 + html-whitespace-sensitive-tag-names: 3.0.1 + unist-util-visit-parents: 6.0.2 + + hast-util-from-dom@5.0.1: + dependencies: + '@types/hast': 3.0.4 + hastscript: 9.0.1 + web-namespaces: 2.0.1 + + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-has-property@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-is-body-ok-link@3.0.1: + dependencies: + '@types/hast': 3.0.4 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-minify-whitespace@1.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-is-element: 3.0.0 + hast-util-whitespace: 3.0.0 + unist-util-is: 6.0.1 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-phrasing@3.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-has-property: 3.0.0 + hast-util-is-body-ok-link: 3.0.1 + hast-util-is-element: 3.0.0 + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-mdast@10.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + hast-util-phrasing: 3.0.1 + hast-util-to-html: 9.0.5 + hast-util-to-text: 4.0.2 + hast-util-whitespace: 3.0.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-hast: 13.2.0 + mdast-util-to-string: 4.0.0 + rehype-minify-whitespace: 6.0.2 + trim-trailing-lines: 2.1.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + hermes-estree@0.25.1: {} hermes-parser@0.25.1: dependencies: hermes-estree: 0.25.1 + html-encoding-sniffer@4.0.0: + dependencies: + whatwg-encoding: 3.1.1 + + html-void-elements@3.0.0: {} + + html-whitespace-sensitive-tag-names@3.0.1: {} + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + ignore@5.3.2: {} ignore@7.0.5: {} @@ -3287,6 +6985,10 @@ snapshots: is-number@7.0.0: {} + is-plain-obj@4.1.0: {} + + is-potential-custom-element-name@1.0.1: {} + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -3330,6 +7032,8 @@ snapshots: isexe@2.0.0: {} + isomorphic.js@0.2.5: {} + iterator.prototype@1.1.5: dependencies: define-data-property: 1.1.4 @@ -3341,12 +7045,41 @@ snapshots: jiti@2.6.1: {} + jose@4.15.9: {} + js-tokens@4.0.0: {} js-yaml@4.1.1: dependencies: argparse: 2.0.1 + jsdom@27.2.0: + dependencies: + '@acemir/cssom': 0.9.23 + '@asamuzakjp/dom-selector': 6.7.4 + cssstyle: 5.3.3 + data-urls: 6.0.0 + decimal.js: 10.6.0 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-potential-custom-element-name: 1.0.1 + parse5: 8.0.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.0 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 15.1.0 + ws: 8.18.3 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -3383,6 +7116,10 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lib0@0.2.114: + dependencies: + isomorphic.js: 0.2.5 + lightningcss-android-arm64@1.30.2: optional: true @@ -3432,28 +7169,362 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.2 lightningcss-win32-x64-msvc: 1.30.2 + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + + linkifyjs@4.3.2: {} + locate-path@6.0.0: dependencies: p-locate: 5.0.0 lodash.merge@4.6.2: {} + longest-streak@3.1.0: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 + lru-cache@11.2.2: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 + lucide-react@0.554.0(react@19.2.0): + dependencies: + react: 19.2.0 + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + markdown-it@14.1.0: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + + markdown-table@3.0.4: {} + math-intrinsics@1.1.0: {} + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.0: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + mdn-data@2.12.2: {} + + mdurl@2.0.0: {} + merge2@1.4.1: {} + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.2.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -3553,6 +7624,8 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + orderedmap@2.1.1: {} + own-keys@1.0.1: dependencies: get-intrinsic: 1.3.0 @@ -3571,12 +7644,22 @@ snapshots: dependencies: callsites: 3.1.0 + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + parse5@8.0.0: + dependencies: + entities: 6.0.1 + path-exists@4.0.0: {} path-key@3.1.1: {} path-parse@1.0.7: {} + pathe@2.0.3: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -3605,19 +7688,200 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + property-information@7.1.0: {} + + prosemirror-changeset@2.3.1: + dependencies: + prosemirror-transform: 1.10.5 + + prosemirror-collab@1.3.1: + dependencies: + prosemirror-state: 1.4.4 + + prosemirror-commands@1.7.1: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.10.5 + + prosemirror-dropcursor@1.8.2: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.10.5 + prosemirror-view: 1.41.3 + + prosemirror-gapcursor@1.4.0: + dependencies: + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-view: 1.41.3 + + prosemirror-highlight@0.13.0(@shikijs/types@3.13.0)(@types/hast@3.0.4)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-transform@1.10.5)(prosemirror-view@1.41.3): + optionalDependencies: + '@shikijs/types': 3.13.0 + '@types/hast': 3.0.4 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.10.5 + prosemirror-view: 1.41.3 + + prosemirror-history@1.5.0: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.10.5 + prosemirror-view: 1.41.3 + rope-sequence: 1.3.4 + + prosemirror-inputrules@1.5.1: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.10.5 + + prosemirror-keymap@1.2.3: + dependencies: + prosemirror-state: 1.4.4 + w3c-keyname: 2.2.8 + + prosemirror-markdown@1.13.2: + dependencies: + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.0 + prosemirror-model: 1.25.4 + + prosemirror-menu@1.2.5: + dependencies: + crelt: 1.0.6 + prosemirror-commands: 1.7.1 + prosemirror-history: 1.5.0 + prosemirror-state: 1.4.4 + + prosemirror-model@1.25.4: + dependencies: + orderedmap: 2.1.1 + + prosemirror-schema-basic@1.2.4: + dependencies: + prosemirror-model: 1.25.4 + + prosemirror-schema-list@1.5.1: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.10.5 + + prosemirror-state@1.4.4: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-transform: 1.10.5 + prosemirror-view: 1.41.3 + + prosemirror-tables@1.8.1: + dependencies: + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.10.5 + prosemirror-view: 1.41.3 + + prosemirror-trailing-node@3.0.0(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.3): + dependencies: + '@remirror/core-constants': 3.0.0 + escape-string-regexp: 4.0.0 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-view: 1.41.3 + + prosemirror-transform@1.10.5: + dependencies: + prosemirror-model: 1.25.4 + + prosemirror-view@1.41.3: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.10.5 + + punycode.js@2.3.1: {} + punycode@2.3.1: {} queue-microtask@1.2.3: {} + raf-schd@4.0.3: {} + react-dom@19.2.0(react@19.2.0): dependencies: react: 19.2.0 scheduler: 0.27.0 + react-dropzone@14.3.8(react@19.2.0): + dependencies: + attr-accept: 2.2.5 + file-selector: 2.1.2 + prop-types: 15.8.1 + react: 19.2.0 + + react-icons@5.5.0(react@19.2.0): + dependencies: + react: 19.2.0 + react-is@16.13.1: {} + react-number-format@5.4.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + react-redux@9.2.0(@types/react@19.2.5)(react@19.2.0)(redux@5.0.1): + dependencies: + '@types/use-sync-external-store': 0.0.6 + react: 19.2.0 + use-sync-external-store: 1.6.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + redux: 5.0.1 + + react-remove-scroll-bar@2.3.8(@types/react@19.2.5)(react@19.2.0): + dependencies: + react: 19.2.0 + react-style-singleton: 2.2.3(@types/react@19.2.5)(react@19.2.0) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.5 + + react-remove-scroll@2.7.1(@types/react@19.2.5)(react@19.2.0): + dependencies: + react: 19.2.0 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.5)(react@19.2.0) + react-style-singleton: 2.2.3(@types/react@19.2.5)(react@19.2.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.5)(react@19.2.0) + use-sidecar: 1.1.3(@types/react@19.2.5)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + + react-style-singleton@2.2.3(@types/react@19.2.5)(react@19.2.0): + dependencies: + get-nonce: 1.0.1 + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.5 + + react-textarea-autosize@8.5.9(@types/react@19.2.5)(react@19.2.0): + dependencies: + '@babel/runtime': 7.28.4 + react: 19.2.0 + use-composed-ref: 1.4.0(@types/react@19.2.5)(react@19.2.0) + use-latest: 1.3.0(@types/react@19.2.5)(react@19.2.0) + transitivePeerDependencies: + - '@types/react' + react@19.2.0: {} + redux@5.0.1: {} + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -3638,6 +7902,72 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 + rehype-format@5.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-format: 1.1.0 + + rehype-minify-whitespace@6.0.2: + dependencies: + '@types/hast': 3.0.4 + hast-util-minify-whitespace: 1.0.1 + + rehype-parse@9.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-html: 2.0.3 + unified: 11.0.5 + + rehype-remark@10.0.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + hast-util-to-mdast: 10.1.2 + unified: 11.0.5 + vfile: 6.0.3 + + rehype-stringify@10.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + unified: 11.0.5 + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.0 + unified: 11.0.5 + vfile: 6.0.3 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + require-from-string@2.0.2: {} + resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} @@ -3656,6 +7986,36 @@ snapshots: reusify@1.1.0: {} + rollup@4.53.3: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.53.3 + '@rollup/rollup-android-arm64': 4.53.3 + '@rollup/rollup-darwin-arm64': 4.53.3 + '@rollup/rollup-darwin-x64': 4.53.3 + '@rollup/rollup-freebsd-arm64': 4.53.3 + '@rollup/rollup-freebsd-x64': 4.53.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 + '@rollup/rollup-linux-arm-musleabihf': 4.53.3 + '@rollup/rollup-linux-arm64-gnu': 4.53.3 + '@rollup/rollup-linux-arm64-musl': 4.53.3 + '@rollup/rollup-linux-loong64-gnu': 4.53.3 + '@rollup/rollup-linux-ppc64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-musl': 4.53.3 + '@rollup/rollup-linux-s390x-gnu': 4.53.3 + '@rollup/rollup-linux-x64-gnu': 4.53.3 + '@rollup/rollup-linux-x64-musl': 4.53.3 + '@rollup/rollup-openharmony-arm64': 4.53.3 + '@rollup/rollup-win32-arm64-msvc': 4.53.3 + '@rollup/rollup-win32-ia32-msvc': 4.53.3 + '@rollup/rollup-win32-x64-gnu': 4.53.3 + '@rollup/rollup-win32-x64-msvc': 4.53.3 + fsevents: 2.3.3 + + rope-sequence@1.3.4: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -3679,12 +8039,20 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 + safer-buffer@2.1.2: {} + + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + scheduler@0.27.0: {} semver@6.3.1: {} semver@7.7.3: {} + set-cookie-parser@2.7.2: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -3773,10 +8141,23 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} + + sonner@2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + source-map-js@1.2.1: {} + space-separated-tokens@2.0.2: {} + stable-hash@0.0.5: {} + stackback@0.0.2: {} + + std-env@3.10.0: {} + stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -3832,6 +8213,11 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + strip-bom@3.0.0: {} strip-json-comments@3.1.1: {} @@ -3849,19 +8235,53 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + symbol-tree@3.2.4: {} + + tabbable@6.3.0: {} + + tailwind-merge@3.4.0: {} + tailwindcss@4.1.17: {} tapable@2.3.0: {} + tiny-invariant@1.3.3: {} + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + tinyrainbow@3.0.3: {} + + tldts-core@7.0.18: {} + + tldts@7.0.18: + dependencies: + tldts-core: 7.0.18 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + tough-cookie@6.0.0: + dependencies: + tldts: 7.0.18 + + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + + trim-lines@3.0.1: {} + + trim-trailing-lines@2.1.0: {} + + trough@2.2.0: {} + ts-api-utils@2.1.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -3875,10 +8295,14 @@ snapshots: tslib@2.8.1: {} + tw-animate-css@1.4.0: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 + type-fest@4.41.0: {} + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -3925,6 +8349,8 @@ snapshots: typescript@5.9.3: {} + uc.micro@2.1.0: {} + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -3934,6 +8360,44 @@ snapshots: undici-types@6.21.0: {} + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + unrs-resolver@1.11.1: dependencies: napi-postinstall: 0.3.4 @@ -3968,6 +8432,147 @@ snapshots: dependencies: punycode: 2.3.1 + use-callback-ref@1.3.3(@types/react@19.2.5)(react@19.2.0): + dependencies: + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.5 + + use-composed-ref@1.4.0(@types/react@19.2.5)(react@19.2.0): + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + use-isomorphic-layout-effect@1.2.1(@types/react@19.2.5)(react@19.2.0): + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.5 + + use-latest@1.3.0(@types/react@19.2.5)(react@19.2.0): + dependencies: + react: 19.2.0 + use-isomorphic-layout-effect: 1.2.1(@types/react@19.2.5)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + + use-sidecar@1.1.3(@types/react@19.2.5)(react@19.2.0): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.5 + + use-sync-external-store@1.6.0(react@19.2.0): + dependencies: + react: 19.2.0 + + uuid@13.0.0: {} + + uuid@8.3.2: {} + + vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.5))(@types/react@19.2.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite@7.2.4(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.53.3 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 20.19.25 + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + + vitest@4.0.13(@types/debug@4.1.12)(@types/node@20.19.25)(jiti@2.6.1)(jsdom@27.2.0)(lightningcss@1.30.2): + dependencies: + '@vitest/expect': 4.0.13 + '@vitest/mocker': 4.0.13(vite@7.2.4(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)) + '@vitest/pretty-format': 4.0.13 + '@vitest/runner': 4.0.13 + '@vitest/snapshot': 4.0.13 + '@vitest/spy': 4.0.13 + '@vitest/utils': 4.0.13 + debug: 4.4.3 + es-module-lexer: 1.7.0 + expect-type: 1.2.2 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tinyrainbow: 3.0.3 + vite: 7.2.4(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/debug': 4.1.12 + '@types/node': 20.19.25 + jsdom: 27.2.0 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + w3c-keyname@2.2.8: {} + + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + + web-namespaces@2.0.1: {} + + webidl-conversions@8.0.0: {} + + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + + whatwg-url@15.1.0: + dependencies: + tr46: 6.0.0 + webidl-conversions: 8.0.0 + which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 @@ -4013,10 +8618,39 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + word-wrap@1.2.5: {} + ws@8.18.3: {} + + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + + y-prosemirror@1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.3)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27): + dependencies: + lib0: 0.2.114 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-view: 1.41.3 + y-protocols: 1.0.6(yjs@13.6.27) + yjs: 13.6.27 + + y-protocols@1.0.6(yjs@13.6.27): + dependencies: + lib0: 0.2.114 + yjs: 13.6.27 + yallist@3.1.1: {} + yjs@13.6.27: + dependencies: + lib0: 0.2.114 + yocto-queue@0.1.0: {} zod-validation-error@4.0.2(zod@4.1.12): @@ -4024,3 +8658,18 @@ snapshots: zod: 4.1.12 zod@4.1.12: {} + + zustand@4.5.7(@types/react@19.2.5)(react@19.2.0): + dependencies: + use-sync-external-store: 1.6.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.5 + react: 19.2.0 + + zustand@5.0.8(@types/react@19.2.5)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)): + optionalDependencies: + '@types/react': 19.2.5 + react: 19.2.0 + use-sync-external-store: 1.6.0(react@19.2.0) + + zwitch@2.0.4: {} diff --git a/src/app/(app)/documents/[id]/loading.tsx b/src/app/(app)/documents/[id]/loading.tsx new file mode 100644 index 00000000..c1020817 --- /dev/null +++ b/src/app/(app)/documents/[id]/loading.tsx @@ -0,0 +1,11 @@ +import { Skeleton } from "@/components/ui/skeleton"; + +export default function LoadingDocument() { + return ( +
+ + + +
+ ); +} diff --git a/src/app/(app)/documents/[id]/page.tsx b/src/app/(app)/documents/[id]/page.tsx new file mode 100644 index 00000000..df8137c0 --- /dev/null +++ b/src/app/(app)/documents/[id]/page.tsx @@ -0,0 +1,61 @@ +import { notFound, redirect } from "next/navigation"; +import { createSupabaseServerClient } from "@/lib/supabase/server"; +import { DocumentShell } from "@/components/editor/document-shell"; +import type { PageOptionsState, DocumentStats } from "@/types/page-options"; + +interface DocumentPageProps { + params: Promise<{ id: string }>; +} + +export default async function DocumentPage({ params }: DocumentPageProps) { + const { id } = await params; + const supabase = await createSupabaseServerClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + redirect("/login"); + } + + const { data: document } = await supabase + .from("documents") + .select( + "id,title,content,updated_at,workspace_id,wide_layout,use_small_text,show_heading_numbers,show_toc,show_structure,protect_editing,show_word_count,word_count,character_count,block_count", + ) + .eq("user_id", session.user.id) + .eq("id", id) + .single(); + + if (!document) { + notFound(); + } + + const initialOptions: PageOptionsState = { + wideLayout: document.wide_layout ?? false, + smallText: document.use_small_text ?? false, + showHeadingNumbers: document.show_heading_numbers ?? true, + showToc: document.show_toc ?? false, + showStructure: document.show_structure ?? false, + protectEditing: document.protect_editing ?? false, + showWordCount: document.show_word_count ?? true, + }; + + const initialStats: DocumentStats = { + wordCount: document.word_count ?? 0, + characterCount: document.character_count ?? 0, + blockCount: document.block_count ?? 0, + }; + + return ( + + ); +} diff --git a/src/app/(app)/layout.tsx b/src/app/(app)/layout.tsx new file mode 100644 index 00000000..0dd793e7 --- /dev/null +++ b/src/app/(app)/layout.tsx @@ -0,0 +1,55 @@ +import { redirect } from "next/navigation"; +import type { ReactNode } from "react"; +import { Sidebar } from "@/components/sidebar/sidebar"; +import { Breadcrumb } from "@/components/breadcrumb"; +import { BottomToolbar } from "@/components/bottom-toolbar"; +import { MobileSidebarTrigger } from "@/components/mobile-sidebar-trigger"; +import type { DocumentRecord } from "@/lib/documents"; +import { createSupabaseServerClient } from "@/lib/supabase/server"; +import { ensureDefaultWorkspace, fetchWorkspaceSummaries } from "@/lib/workspaces"; +import { fetchSidebarDataset } from "@/lib/sidebar-tree"; +import type { SidebarInitialData } from "@/components/sidebar/types"; +import { SearchPalette } from "@/components/search/search-palette"; + +export default async function AppLayout({ children }: { children: ReactNode }) { + const supabase = await createSupabaseServerClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + redirect("/login"); + } + + await ensureDefaultWorkspace(supabase, session.user.id, session.user.email ?? "我的空间"); + const { workspaces, activeWorkspaceId } = await fetchWorkspaceSummaries(supabase, session.user.id); + + let documents: DocumentRecord[] = []; + let sidebarInitialData: SidebarInitialData | null = null; + + if (activeWorkspaceId) { + const dataset = await fetchSidebarDataset(supabase, activeWorkspaceId); + documents = dataset.documents; + sidebarInitialData = { + activeWorkspaceId, + workspaces, + documents: dataset.documents, + trashedDocuments: dataset.trashedDocuments, + }; + } + + return ( +
+ {sidebarInitialData && } +
+
+ + +
+
{children}
+ + +
+
+ ); +} diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx new file mode 100644 index 00000000..971513e3 --- /dev/null +++ b/src/app/(auth)/login/page.tsx @@ -0,0 +1,91 @@ +"use client"; + +import { useCallback, useState } from "react"; +import { useRouter } from "next/navigation"; +import { supabaseBrowser } from "@/lib/supabase/client"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Separator } from "@/components/ui/separator"; + +export default function LoginPage() { + const router = useRouter(); + const [email, setEmail] = useState("test@163.com"); + const [password, setPassword] = useState("123456"); + const [loading, setLoading] = useState(false); + const [message, setMessage] = useState(""); + const [sessionInfo, setSessionInfo] = useState(""); + + const handleLogin = useCallback(async () => { + setLoading(true); + setMessage(""); + const { data, error } = await supabaseBrowser.auth.signInWithPassword({ + email, + password, + }); + setLoading(false); + if (error) { + setMessage(`登录失败:${error.message}`); + return; + } + setMessage("登录成功,准备跳转..."); + setSessionInfo(JSON.stringify(data.session, null, 2)); + router.replace("/"); + }, [email, password, router]); + + const handleGetSession = useCallback(async () => { + setLoading(true); + const { + data: { session }, + error, + } = await supabaseBrowser.auth.getSession(); + setLoading(false); + if (error) { + setMessage(`获取会话失败:${error.message}`); + return; + } + if (!session) { + setMessage("当前未登录"); + setSessionInfo(""); + return; + } + setMessage("发现有效 Session"); + setSessionInfo(JSON.stringify(session, null, 2)); + }, []); + + return ( +
+ + + Supabase 登录 +

测试账号:test@163.com / 123456

+
+ +
+ + setEmail(e.target.value)} /> +
+
+ + setPassword(e.target.value)} /> +
+
+ + +
+ {message &&

{message}

} + + {sessionInfo && ( +
+              {sessionInfo}
+            
+ )} +
+
+
+ ); +} diff --git a/src/app/api/.gitkeep b/src/app/api/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/app/api/documents/create-child/route.ts b/src/app/api/documents/create-child/route.ts new file mode 100644 index 00000000..cd72c30a --- /dev/null +++ b/src/app/api/documents/create-child/route.ts @@ -0,0 +1,99 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; +import { ensureDefaultWorkspace, resolveActiveWorkspaceId } from "@/lib/workspaces"; + +type CreateChildPayload = { + parentId: string | null; + title?: string; + blocks?: unknown; +}; + +export const dynamic = "force-dynamic"; + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录无法创建页面" }, { status: 401 }); + } + + const { parentId, title, blocks }: CreateChildPayload = await request.json(); + + if (typeof parentId === "undefined") { + return NextResponse.json({ error: "缺少 parentId" }, { status: 400 }); + } + + let workspaceId: string; + let accessScope: "private" | "shared" | "public" = "private"; + + if (parentId) { + const { data: parentDoc, error: parentError } = await supabase + .from("documents") + .select("workspace_id,access_scope") + .eq("id", parentId) + .single(); + + if (parentError || !parentDoc) { + return NextResponse.json({ error: "父页面不存在" }, { status: 404 }); + } + workspaceId = parentDoc.workspace_id; + accessScope = (parentDoc.access_scope ?? "private") as typeof accessScope; + } else { + await ensureDefaultWorkspace(supabase, session.user.id, session.user.email ?? "我的空间"); + workspaceId = await resolveActiveWorkspaceId(supabase, session.user.id); + if (!workspaceId) { + return NextResponse.json({ error: "缺少目标工作空间" }, { status: 400 }); + } + } + + const siblingQuery = supabase + .from("documents") + .select("id", { head: true, count: "exact" }) + .eq("workspace_id", workspaceId); + + if (parentId) { + siblingQuery.eq("parent_id", parentId); + } else { + siblingQuery.is("parent_id", null); + } + + const { count: siblingCount = 0, error: countError } = await siblingQuery; + + if (countError) { + return NextResponse.json({ error: countError.message }, { status: 500 }); + } + + const resolvedTitle = + title && title.trim().length > 0 ? title.trim() : "未命名页面"; + + const contentPayload = Array.isArray(blocks) ? blocks : []; + + const { data, error } = await supabase + .from("documents") + .insert({ + user_id: session.user.id, + parent_id: parentId, + workspace_id: workspaceId, + access_scope: accessScope, + title: resolvedTitle, + content: contentPayload, + sort_order: siblingCount, + }) + .select("id,title") + .single(); + + if (error || !data) { + return NextResponse.json( + { error: error?.message ?? "创建子页面失败" }, + { status: 500 }, + ); + } + + return NextResponse.json({ + pageId: data.id, + title: data.title ?? resolvedTitle, + }); +} diff --git a/src/app/api/documents/create/route.ts b/src/app/api/documents/create/route.ts new file mode 100644 index 00000000..9672e21c --- /dev/null +++ b/src/app/api/documents/create/route.ts @@ -0,0 +1,123 @@ +import { randomUUID } from "crypto"; +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; +import { ensureDefaultWorkspace, resolveActiveWorkspaceId } from "@/lib/workspaces"; +import type { Json } from "@/types/supabase"; +import { composeContentWithBlocks, extractBlocksFromContent } from "@/lib/document-content"; + +export async function POST(request: Request) { + try { + return await handleCreateRequest(request); + } catch (error) { + console.error("创建页面失败", error); + const message = error instanceof Error ? error.message : "创建页面失败,请稍后再试"; + return NextResponse.json({ error: message }, { status: 500 }); + } +} + +async function handleCreateRequest(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { parentId }: { parentId?: string | null } = await request.json(); + + await ensureDefaultWorkspace(supabase, session.user.id, session.user.email ?? "我的空间"); + + let workspaceId: string | null = null; + let parentContent: Json | null = null; + let accessScope: "private" | "shared" | "public" = "private"; + + if (parentId) { + const { data: parentDoc, error: parentError } = await supabase + .from("documents") + .select("workspace_id,access_scope,content,user_id") + .eq("id", parentId) + .eq("user_id", session.user.id) + .single(); + + if (parentError || !parentDoc) { + return NextResponse.json({ error: "父页面不存在或无权限" }, { status: 404 }); + } + workspaceId = parentDoc.workspace_id; + accessScope = (parentDoc.access_scope ?? "private") as typeof accessScope; + parentContent = parentDoc.content; + } else { + workspaceId = await resolveActiveWorkspaceId(supabase, session.user.id); + if (!workspaceId) { + return NextResponse.json({ error: "缺少目标工作空间" }, { status: 400 }); + } + } + + if (!workspaceId) { + return NextResponse.json({ error: "缺少目标工作空间" }, { status: 400 }); + } + + const siblingQuery = supabase + .from("documents") + .select("id", { head: true, count: "exact" }) + .eq("workspace_id", workspaceId); + + if (parentId) { + siblingQuery.eq("parent_id", parentId); + } else { + siblingQuery.is("parent_id", null); + } + + const { count: siblingCount = 0, error: countError } = await siblingQuery; + + if (countError) { + return NextResponse.json({ error: countError.message }, { status: 500 }); + } + + const { data, error } = await supabase + .from("documents") + .insert({ + user_id: session.user.id, + parent_id: parentId ?? null, + workspace_id: workspaceId, + title: "无标题", + content: { blocks: [] }, + access_scope: accessScope, + sort_order: siblingCount, + }) + .select( + "id,title,parent_id,sort_order,is_starred,created_at,updated_at,workspace_id,access_scope,is_template", + ) + .single(); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 400 }); + } + + if (parentId && data) { + const existingBlocks = extractBlocksFromContent(parentContent); + const pageReferenceBlock = { + id: randomUUID(), + type: "pageReference", + props: { + pageId: data.id, + title: data.title ?? "无标题", + }, + }; + const nextBlocks = [...existingBlocks, pageReferenceBlock as Json]; + const payload = composeContentWithBlocks(parentContent, nextBlocks); + const timestamp = new Date().toISOString(); + const { error: parentUpdateError } = await supabase + .from("documents") + .update({ content: payload, updated_at: timestamp }) + .eq("id", parentId) + .eq("user_id", session.user.id); + + if (parentUpdateError) { + return NextResponse.json({ error: parentUpdateError.message }, { status: 500 }); + } + } + + return NextResponse.json(data); +} diff --git a/src/app/api/documents/delete/route.ts b/src/app/api/documents/delete/route.ts new file mode 100644 index 00000000..8e75acfa --- /dev/null +++ b/src/app/api/documents/delete/route.ts @@ -0,0 +1,36 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; + +export const dynamic = "force-dynamic"; + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { documentId } = await request.json(); + + if (!documentId) { + return NextResponse.json({ error: "缺少 documentId" }, { status: 400 }); + } + + const { error } = await supabase + .from("documents") + .update({ + deleted_at: new Date().toISOString(), + deleted_by: session.user.id, + }) + .eq("id", documentId) + .eq("user_id", session.user.id); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ success: true }); +} diff --git a/src/app/api/documents/duplicate/route.ts b/src/app/api/documents/duplicate/route.ts new file mode 100644 index 00000000..6dc2a403 --- /dev/null +++ b/src/app/api/documents/duplicate/route.ts @@ -0,0 +1,74 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; + +interface DuplicatePayload { + documentId: string; +} + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { documentId }: DuplicatePayload = await request.json(); + + if (!documentId) { + return NextResponse.json({ error: "缺少 documentId" }, { status: 400 }); + } + + const { data: sourceDoc, error: sourceError } = await supabase + .from("documents") + .select("id,title,content,parent_id,workspace_id,access_scope") + .eq("id", documentId) + .eq("user_id", session.user.id) + .single(); + + if (sourceError || !sourceDoc) { + return NextResponse.json({ error: "页面不存在或无权访问" }, { status: 404 }); + } + + const siblingQuery = supabase + .from("documents") + .select("id", { head: true, count: "exact" }) + .eq("workspace_id", sourceDoc.workspace_id); + + if (sourceDoc.parent_id) { + siblingQuery.eq("parent_id", sourceDoc.parent_id); + } else { + siblingQuery.is("parent_id", null); + } + + const { count: siblingCount = 0, error: countError } = await siblingQuery; + + if (countError) { + return NextResponse.json({ error: countError.message }, { status: 500 }); + } + + const fallbackTitle = sourceDoc.title?.trim() && sourceDoc.title.trim().length > 0 ? sourceDoc.title.trim() : "无标题"; + const duplicatedTitle = `${fallbackTitle} 副本`; + + const { data: duplicated, error: duplicateError } = await supabase + .from("documents") + .insert({ + user_id: session.user.id, + workspace_id: sourceDoc.workspace_id, + parent_id: sourceDoc.parent_id, + access_scope: sourceDoc.access_scope ?? "private", + title: duplicatedTitle, + content: sourceDoc.content, + sort_order: siblingCount, + }) + .select("id,title,parent_id,sort_order") + .single(); + + if (duplicateError || !duplicated) { + return NextResponse.json({ error: duplicateError?.message ?? "复制失败" }, { status: 500 }); + } + + return NextResponse.json(duplicated); +} diff --git a/src/app/api/documents/embed/route.ts b/src/app/api/documents/embed/route.ts new file mode 100644 index 00000000..6387d993 --- /dev/null +++ b/src/app/api/documents/embed/route.ts @@ -0,0 +1,76 @@ +import { randomUUID } from "crypto"; +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; +import type { Json } from "@/types/supabase"; +import { composeContentWithBlocks, extractBlocksFromContent } from "@/lib/document-content"; + +interface EmbedPayload { + sourceId: string; + targetId: string; +} + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { sourceId, targetId }: EmbedPayload = await request.json(); + + if (!sourceId || !targetId) { + return NextResponse.json({ error: "缺少参数" }, { status: 400 }); + } + + const { data: sourceDoc, error: sourceError } = await supabase + .from("documents") + .select("id,title,user_id") + .eq("id", sourceId) + .eq("user_id", session.user.id) + .single(); + + if (sourceError || !sourceDoc) { + return NextResponse.json({ error: "原始页面不存在或无权限" }, { status: 404 }); + } + + const { data: targetDoc, error: targetError } = await supabase + .from("documents") + .select("id,content,user_id") + .eq("id", targetId) + .eq("user_id", session.user.id) + .single(); + + if (targetError || !targetDoc) { + return NextResponse.json({ error: "目标页面不存在或无权限" }, { status: 404 }); + } + + const currentBlocks = extractBlocksFromContent(targetDoc.content); + const nextBlocks: Json[] = [ + ...currentBlocks, + { + id: randomUUID(), + type: "pageReference", + props: { + pageId: sourceDoc.id, + title: sourceDoc.title ?? "无标题", + }, + }, + ]; + + const payload: Json = composeContentWithBlocks(targetDoc.content, nextBlocks); + + const { error: updateError } = await supabase + .from("documents") + .update({ content: payload }) + .eq("id", targetDoc.id) + .eq("user_id", session.user.id); + + if (updateError) { + return NextResponse.json({ error: updateError.message }, { status: 500 }); + } + + return NextResponse.json({ ok: true }); +} diff --git a/src/app/api/documents/empty-trash/route.ts b/src/app/api/documents/empty-trash/route.ts new file mode 100644 index 00000000..d6cd5578 --- /dev/null +++ b/src/app/api/documents/empty-trash/route.ts @@ -0,0 +1,53 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; + +export const dynamic = "force-dynamic"; + +interface EmptyTrashPayload { + workspaceId?: string; +} + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { workspaceId }: EmptyTrashPayload = await request.json(); + + if (!workspaceId) { + return NextResponse.json({ error: "缺少 workspaceId" }, { status: 400 }); + } + + const { data: membership, error: membershipError } = await supabase + .from("workspace_members") + .select("workspace_id") + .eq("workspace_id", workspaceId) + .eq("user_id", session.user.id) + .limit(1); + + if (membershipError) { + return NextResponse.json({ error: membershipError.message }, { status: 500 }); + } + + if (!membership || membership.length === 0) { + return NextResponse.json({ error: "无权操作该工作空间" }, { status: 403 }); + } + + const { error } = await supabase + .from("documents") + .delete() + .eq("workspace_id", workspaceId) + .eq("user_id", session.user.id) + .not("deleted_at", "is", null); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ success: true }); +} diff --git a/src/app/api/documents/move/route.ts b/src/app/api/documents/move/route.ts new file mode 100644 index 00000000..90b6158b --- /dev/null +++ b/src/app/api/documents/move/route.ts @@ -0,0 +1,37 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; + +interface MovePayload { + documentId: string; + parentId?: string | null; + position: number; +} + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { documentId, parentId = null, position }: MovePayload = await request.json(); + const sortOrder = Number.isFinite(position) ? Math.floor(position) : 0; + + const { error } = await supabase + .from("documents") + .update({ + parent_id: parentId, + sort_order: sortOrder, + }) + .eq("id", documentId) + .eq("user_id", session.user.id); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 400 }); + } + + return NextResponse.json({ ok: true }); +} diff --git a/src/app/api/documents/options/route.ts b/src/app/api/documents/options/route.ts new file mode 100644 index 00000000..63a6e9c2 --- /dev/null +++ b/src/app/api/documents/options/route.ts @@ -0,0 +1,61 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; +import type { PageOptionsState } from "@/types/page-options"; +import type { Database } from "@/types/supabase"; + +type OptionsPayload = { + documentId: string; + options: Partial; +}; + +const COLUMN_MAP: Record = { + wideLayout: "wide_layout", + smallText: "use_small_text", + showHeadingNumbers: "show_heading_numbers", + showToc: "show_toc", + showStructure: "show_structure", + protectEditing: "protect_editing", + showWordCount: "show_word_count", +}; + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { documentId, options }: OptionsPayload = await request.json(); + if (!documentId || !options) { + return NextResponse.json({ error: "缺少参数" }, { status: 400 }); + } + + const updatePayload: Record = {}; + (Object.keys(options) as (keyof PageOptionsState)[]).forEach((key) => { + const column = COLUMN_MAP[key]; + if (!column) return; + const value = options[key]; + if (typeof value === "boolean") { + updatePayload[column as string] = value; + } + }); + + if (Object.keys(updatePayload).length === 0) { + return NextResponse.json({ error: "缺少可更新的选项" }, { status: 400 }); + } + + const { error } = await supabase + .from("documents") + .update(updatePayload) + .eq("id", documentId) + .eq("user_id", session.user.id); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ ok: true }); +} diff --git a/src/app/api/documents/purge/route.ts b/src/app/api/documents/purge/route.ts new file mode 100644 index 00000000..ac1a7569 --- /dev/null +++ b/src/app/api/documents/purge/route.ts @@ -0,0 +1,33 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; + +export const dynamic = "force-dynamic"; + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { documentId } = await request.json(); + + if (!documentId) { + return NextResponse.json({ error: "缺少 documentId" }, { status: 400 }); + } + + const { error } = await supabase + .from("documents") + .delete() + .eq("id", documentId) + .eq("user_id", session.user.id); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ success: true }); +} diff --git a/src/app/api/documents/restore/route.ts b/src/app/api/documents/restore/route.ts new file mode 100644 index 00000000..f66c2894 --- /dev/null +++ b/src/app/api/documents/restore/route.ts @@ -0,0 +1,38 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; + +export const dynamic = "force-dynamic"; + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { documentId } = await request.json(); + + if (!documentId) { + return NextResponse.json({ error: "缺少 documentId" }, { status: 400 }); + } + + const { error } = await supabase + .from("documents") + .update({ + deleted_at: null, + deleted_by: null, + parent_id: null, + access_scope: "private", + }) + .eq("id", documentId) + .eq("user_id", session.user.id); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ success: true }); +} diff --git a/src/app/api/documents/save/route.ts b/src/app/api/documents/save/route.ts new file mode 100644 index 00000000..70e917c8 --- /dev/null +++ b/src/app/api/documents/save/route.ts @@ -0,0 +1,32 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; + +interface SavePayload { + documentId: string; + content: unknown; +} + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { documentId, content }: SavePayload = await request.json(); + + const { error } = await supabase + .from("documents") + .update({ content }) + .eq("id", documentId) + .eq("user_id", session.user.id); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 400 }); + } + + return NextResponse.json({ ok: true }); +} diff --git a/src/app/api/documents/stats/route.ts b/src/app/api/documents/stats/route.ts new file mode 100644 index 00000000..a69e6127 --- /dev/null +++ b/src/app/api/documents/stats/route.ts @@ -0,0 +1,40 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; +import type { DocumentStats } from "@/types/page-options"; + +interface StatsPayload { + documentId: string; + stats: DocumentStats; +} + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { documentId, stats }: StatsPayload = await request.json(); + if (!documentId || !stats) { + return NextResponse.json({ error: "缺少参数" }, { status: 400 }); + } + + const { error } = await supabase + .from("documents") + .update({ + word_count: stats.wordCount, + character_count: stats.characterCount, + block_count: stats.blockCount, + }) + .eq("id", documentId) + .eq("user_id", session.user.id); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ ok: true }); +} diff --git a/src/app/api/documents/title/route.ts b/src/app/api/documents/title/route.ts new file mode 100644 index 00000000..f3888bb1 --- /dev/null +++ b/src/app/api/documents/title/route.ts @@ -0,0 +1,32 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; + +interface RenamePayload { + documentId: string; + title: string; +} + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { documentId, title }: RenamePayload = await request.json(); + + const { error } = await supabase + .from("documents") + .update({ title }) + .eq("id", documentId) + .eq("user_id", session.user.id); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 400 }); + } + + return NextResponse.json({ ok: true }); +} diff --git a/src/app/api/media/assets/route.ts b/src/app/api/media/assets/route.ts new file mode 100644 index 00000000..6c717a05 --- /dev/null +++ b/src/app/api/media/assets/route.ts @@ -0,0 +1,92 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; +import type { MediaAsset } from "@/types/media"; + +export const dynamic = "force-dynamic"; + +export async function GET(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { searchParams } = new URL(request.url); + const workspaceId = searchParams.get("workspaceId"); + const limit = Number.parseInt(searchParams.get("limit") ?? "12", 10); + + if (!workspaceId) { + return NextResponse.json({ error: "缺少 workspaceId" }, { status: 400 }); + } + + let query = supabase + .from("media_assets") + .select("*") + .eq("workspace_id", workspaceId) + .order("created_at", { ascending: false }) + .limit(Number.isNaN(limit) ? 12 : limit); + + const assetType = searchParams.get("assetType"); + if (assetType) { + query = query.eq("asset_type", assetType); + } + + const { data, error } = await query; + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ items: (data ?? []) as MediaAsset[] }); +} + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const payload = (await request.json()) as { + workspaceId: string; + documentId: string; + fileUrl: string; + thumbnailUrl?: string; + assetType?: string; + fileName?: string; + fileSize?: number; + mimeType?: string; + }; + + if (!payload.workspaceId || !payload.documentId || !payload.fileUrl) { + return NextResponse.json({ error: "参数不完整" }, { status: 400 }); + } + + const { data, error } = await supabase + .from("media_assets") + .insert({ + workspace_id: payload.workspaceId, + document_id: payload.documentId, + file_url: payload.fileUrl, + thumbnail_url: payload.thumbnailUrl ?? payload.fileUrl, + asset_type: payload.assetType ?? "image", + file_name: payload.fileName, + file_size: payload.fileSize ?? null, + mime_type: payload.mimeType ?? null, + created_by: session.user.id, + }) + .select("*") + .single(); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ asset: data as MediaAsset }); +} diff --git a/src/app/api/media/ocr/route.ts b/src/app/api/media/ocr/route.ts new file mode 100644 index 00000000..7a172cc2 --- /dev/null +++ b/src/app/api/media/ocr/route.ts @@ -0,0 +1,43 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { assetId } = (await request.json()) as { assetId?: string }; + if (!assetId) { + return NextResponse.json({ error: "缺少 assetId" }, { status: 400 }); + } + + const { error } = await supabase + .from("media_assets") + .update({ ocr_status: "processing" }) + .eq("id", assetId) + .limit(1); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL; + if (backendUrl) { + void fetch(`${backendUrl}/api/v1/tasks/media-ocr`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ asset_id: assetId }), + }).catch((err) => { + console.warn("触发后端 OCR 失败", err); + }); + } + + return NextResponse.json({ ok: true }); +} diff --git a/src/app/api/media/upload/route.ts b/src/app/api/media/upload/route.ts new file mode 100644 index 00000000..ddb79e0c --- /dev/null +++ b/src/app/api/media/upload/route.ts @@ -0,0 +1,82 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; +import type { MediaAsset } from "@/types/media"; +import { extname } from "path"; + +export const dynamic = "force-dynamic"; + +const MEDIA_BUCKET = process.env.NEXT_PUBLIC_SUPABASE_MEDIA_BUCKET ?? "media"; + +const resolveAssetType = (mime: string): "image" | "video" | "audio" | "file" => { + if (mime.startsWith("image/")) return "image"; + if (mime.startsWith("video/")) return "video"; + if (mime.startsWith("audio/")) return "audio"; + return "file"; +}; + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const formData = await request.formData(); + const file = formData.get("file"); + const workspaceId = String(formData.get("workspaceId") ?? ""); + const documentId = String(formData.get("documentId") ?? ""); + + if (!(file instanceof File) || !workspaceId || !documentId) { + return NextResponse.json({ error: "缺少必要参数" }, { status: 400 }); + } + + try { + const arrayBuffer = await file.arrayBuffer(); + const buffer = Buffer.from(arrayBuffer); + const extension = extname(file.name || "").replace(/\s+/g, ""); + const uniqueId = typeof crypto.randomUUID === "function" ? crypto.randomUUID() : Math.random().toString(36).slice(2); + const path = `${workspaceId}/${Date.now()}-${uniqueId}${extension}`; + const assetType = resolveAssetType(file.type || ""); + + const { error: uploadError } = await supabase.storage.from(MEDIA_BUCKET).upload(path, buffer, { + contentType: file.type, + upsert: false, + }); + + if (uploadError) { + return NextResponse.json({ error: uploadError.message }, { status: 500 }); + } + + const { + data: { publicUrl }, + } = supabase.storage.from(MEDIA_BUCKET).getPublicUrl(path); + + const { data: asset, error } = await supabase + .from("media_assets") + .insert({ + workspace_id: workspaceId, + document_id: documentId, + file_url: publicUrl, + thumbnail_url: publicUrl, + asset_type: assetType, + file_name: file.name, + file_size: file.size, + mime_type: file.type, + created_by: session.user.id, + }) + .select("*") + .single(); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ asset: asset as MediaAsset }); + } catch (error) { + console.error(error); + return NextResponse.json({ error: "上传失败" }, { status: 500 }); + } +} diff --git a/src/app/api/references/backlinks/route.ts b/src/app/api/references/backlinks/route.ts new file mode 100644 index 00000000..2686f3de --- /dev/null +++ b/src/app/api/references/backlinks/route.ts @@ -0,0 +1,50 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; + +export async function GET(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { searchParams } = new URL(request.url); + const workspaceId = searchParams.get("workspaceId"); + const pageId = searchParams.get("pageId"); + const limit = Number(searchParams.get("limit") ?? "50"); + const offset = Number(searchParams.get("offset") ?? "0"); + + if (!workspaceId || !pageId) { + return NextResponse.json({ error: "缺少 workspaceId 或 pageId" }, { status: 400 }); + } + + const { data: membership, error: membershipError } = await supabase + .from("workspace_members") + .select("workspace_id") + .eq("workspace_id", workspaceId) + .eq("user_id", session.user.id) + .maybeSingle(); + + if (membershipError) { + return NextResponse.json({ error: membershipError.message }, { status: 500 }); + } + if (!membership) { + return NextResponse.json({ error: "无权访问该工作空间" }, { status: 403 }); + } + + const { data, error } = await supabase.rpc("list_backlinks", { + p_workspace_id: workspaceId, + p_target_page_id: pageId, + p_limit: Number.isFinite(limit) ? limit : 50, + p_offset: Number.isFinite(offset) ? offset : 0, + }); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ backlinks: data ?? [] }); +} diff --git a/src/app/api/references/record/route.ts b/src/app/api/references/record/route.ts new file mode 100644 index 00000000..48a0ce95 --- /dev/null +++ b/src/app/api/references/record/route.ts @@ -0,0 +1,68 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; + +type DisplayMode = "inline" | "embed"; + +interface RecordReferencePayload { + workspaceId: string; + sourcePageId: string; + targetPageId: string; + sourceBlockId?: string | null; + alias?: string | null; + displayMode: DisplayMode; + isPreviewable?: boolean; +} + +const isValidDisplayMode = (mode: string): mode is DisplayMode => mode === "inline" || mode === "embed"; + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const body = (await request.json()) as RecordReferencePayload; + const { workspaceId, sourcePageId, targetPageId, sourceBlockId, alias, displayMode, isPreviewable = true } = body; + + if (!workspaceId || !sourcePageId || !targetPageId) { + return NextResponse.json({ error: "缺少必要参数" }, { status: 400 }); + } + if (!isValidDisplayMode(displayMode)) { + return NextResponse.json({ error: "非法的引用模式" }, { status: 400 }); + } + + const { data: membership, error: membershipError } = await supabase + .from("workspace_members") + .select("workspace_id") + .eq("workspace_id", workspaceId) + .eq("user_id", session.user.id) + .maybeSingle(); + + if (membershipError) { + return NextResponse.json({ error: membershipError.message }, { status: 500 }); + } + if (!membership) { + return NextResponse.json({ error: "无权访问该工作空间" }, { status: 403 }); + } + + const { data, error } = await supabase.rpc("record_page_ref", { + p_workspace_id: workspaceId, + p_source_page_id: sourcePageId, + p_source_block_id: sourceBlockId ?? null, + p_target_page_id: targetPageId, + p_alias: alias ?? null, + p_display_mode: displayMode, + p_is_previewable: isPreviewable, + p_created_by: session.user.id, + }); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ reference: data }); +} diff --git a/src/app/api/search/documents/route.ts b/src/app/api/search/documents/route.ts new file mode 100644 index 00000000..027cb181 --- /dev/null +++ b/src/app/api/search/documents/route.ts @@ -0,0 +1,303 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; +import type { + DocumentSearchFilters, + DocumentSearchRequest, + DocumentSearchResponse, + DocumentSearchResult, + DocumentSearchTimeRange, +} from "@/types/search"; +import { buildSnippet } from "@/lib/search/snippet"; + +const MAX_LIMIT = 50; + +const DEFAULT_FILTERS: DocumentSearchFilters = { + titleOnly: false, + exact: false, + onlyCurrentPage: false, + includeOcr: false, + timeRange: "any", + timeField: "updated", +}; + +const TIME_RANGE_TO_MS: Record = { + any: null, + "7d": 1000 * 60 * 60 * 24 * 7, + "30d": 1000 * 60 * 60 * 24 * 30, +}; + +const TIME_FIELD_COLUMN = { + updated: "updated_at", + created: "created_at", +} as const; + +const escapeLike = (value: string): string => value.replace(/[%_\\]/g, (match) => `\\${match}`); +interface DocumentRow { + id: string; + title: string | null; + raw_text: string | null; + updated_at: string | null; + created_at: string | null; +} + +const buildIsoBoundary = (value: string, isEnd = false): string | null => { + if (!value) { + return null; + } + const normalized = value.trim(); + if (!normalized) { + return null; + } + const suffix = isEnd ? "T23:59:59.999Z" : "T00:00:00.000Z"; + const date = new Date(`${normalized}${suffix}`); + if (Number.isNaN(date.getTime())) { + return null; + } + return date.toISOString(); +}; + +const mapDocumentToResult = ( + row: DocumentRow, + keyword: string | null, + forcedMatch?: DocumentSearchResult["matchField"], +): DocumentSearchResult => { + const normalizedKeyword = keyword?.trim() ?? ""; + const normalizedTitle = row.title ?? "无标题"; + let matchField: DocumentSearchResult["matchField"] = "recent"; + if (forcedMatch) { + matchField = forcedMatch; + } else if (normalizedKeyword) { + const matchesTitle = normalizedTitle.toLowerCase().includes(normalizedKeyword.toLowerCase()); + matchField = matchesTitle ? "title" : "content"; + } + + return { + id: row.id, + title: normalizedTitle, + snippet: buildSnippet(row.raw_text, normalizedKeyword || null), + updatedAt: row.updated_at, + createdAt: row.created_at, + matchField, + hasOcr: Boolean(row.raw_text), + publicPath: `/documents/${row.id}`, + score: matchField === "title" ? 2 : 1, + }; +}; + +type RouteSupabaseClient = Awaited>; + +const fetchRecentResults = async ( + supabase: RouteSupabaseClient, + userId: string, + workspaceId: string, +): Promise => { + const { data: recentRows, error: recentError } = await supabase + .from("user_recent_pages") + .select("document_id,last_accessed_at") + .eq("user_id", userId) + .eq("workspace_id", workspaceId) + .order("last_accessed_at", { ascending: false }) + .limit(10); + + if (recentError || !recentRows || recentRows.length === 0) { + return []; + } + + const documentIds = recentRows.map((row) => row.document_id); + + const { data: docRows, error: docsError } = await supabase + .from("documents") + .select("id,title,updated_at,created_at,raw_text") + .in("id", documentIds) + .is("deleted_at", null); + + if (docsError || !docRows) { + return []; + } + + const docMap = new Map(docRows.map((row) => [row.id, row])); + return recentRows + .map((row) => docMap.get(row.document_id)) + .filter((row): row is DocumentRow => Boolean(row)) + .map((row) => mapDocumentToResult(row, null, "recent")); +}; + +const fetchOcrMatches = async ( + supabase: RouteSupabaseClient, + workspaceId: string, + likePattern: string, + limit: number, +) => { + const { data, error } = await supabase + .from("media_assets") + .select("document_id,ocr_text") + .eq("workspace_id", workspaceId) + .not("ocr_text", "is", null) + .ilike("ocr_text", likePattern) + .limit(limit); + + if (error || !data) { + return []; + } + return data; +}; + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const payload = (await request.json()) as DocumentSearchRequest; + const workspaceId = payload.workspaceId; + + if (!workspaceId) { + return NextResponse.json({ error: "缺少 workspaceId" }, { status: 400 }); + } + + const filters: DocumentSearchFilters = { + ...DEFAULT_FILTERS, + ...payload.filters, + }; + + const { data: membership, error: membershipError } = await supabase + .from("workspace_members") + .select("workspace_id") + .eq("workspace_id", workspaceId) + .eq("user_id", session.user.id) + .limit(1); + + if (membershipError) { + return NextResponse.json({ error: membershipError.message }, { status: 500 }); + } + + if (!membership || membership.length === 0) { + return NextResponse.json({ error: "无权访问该工作空间" }, { status: 403 }); + } + + if (filters.onlyCurrentPage && !payload.documentId) { + filters.onlyCurrentPage = false; + } + + const limit = Math.min(payload.limit ?? 30, MAX_LIMIT); + const normalizedQuery = payload.query?.trim() ?? ""; + const likePattern = filters.exact ? normalizedQuery : `%${escapeLike(normalizedQuery)}%`; + const timeColumn = TIME_FIELD_COLUMN[filters.timeField ?? "updated"]; + + let builder = supabase + .from("documents") + .select("id,title,updated_at,created_at,raw_text,is_starred,access_scope") + .eq("workspace_id", workspaceId) + .is("deleted_at", null) + .order(timeColumn, { ascending: false }) + .limit(limit); + + if (filters.onlyCurrentPage && payload.documentId) { + builder = builder.eq("id", payload.documentId); + } + + const customFrom = filters.customRange?.from ? buildIsoBoundary(filters.customRange.from, false) : null; + const customTo = filters.customRange?.to ? buildIsoBoundary(filters.customRange.to, true) : null; + + if (customFrom) { + builder = builder.gte(timeColumn, customFrom); + } + if (customTo) { + builder = builder.lte(timeColumn, customTo); + } + + if (!customFrom && !customTo) { + const now = Date.now(); + const offset = TIME_RANGE_TO_MS[filters.timeRange]; + if (offset) { + const from = new Date(now - offset).toISOString(); + builder = builder.gte(timeColumn, from); + } + } + + if (normalizedQuery) { + if (filters.titleOnly) { + builder = filters.exact ? builder.eq("title", normalizedQuery) : builder.ilike("title", likePattern); + } else { + const clauses = [ + `title.${filters.exact ? `eq.${normalizedQuery}` : `ilike.${likePattern}`}`, + ]; + if (filters.includeOcr) { + clauses.push(`raw_text.ilike.${likePattern}`); + } + builder = builder.or(clauses.join(",")); + } + } + + const shouldSearchOcr = Boolean(filters.includeOcr && normalizedQuery); + const [{ data, error }, recentResults, ocrMatches] = await Promise.all([ + builder, + fetchRecentResults(supabase, session.user.id, workspaceId), + shouldSearchOcr ? fetchOcrMatches(supabase, workspaceId, likePattern, limit) : Promise.resolve([]), + ]); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + let results: DocumentSearchResult[] = (data ?? []).map((row) => + mapDocumentToResult(row, normalizedQuery || null), + ); + + if (ocrMatches.length > 0 && normalizedQuery) { + const snippetMap = new Map(); + ocrMatches.forEach((row: { document_id: string; ocr_text: string | null }) => { + if (!row.ocr_text) return; + if (!snippetMap.has(row.document_id)) { + snippetMap.set(row.document_id, row.ocr_text); + } + }); + if (snippetMap.size > 0) { + const resultMap = new Map(results.map((item) => [item.id, item])); + const missingDocIds: string[] = []; + snippetMap.forEach((text, docId) => { + const snippet = buildSnippet(text, normalizedQuery || null); + if (resultMap.has(docId)) { + const existing = resultMap.get(docId)!; + resultMap.set(docId, { + ...existing, + snippet: snippet || existing.snippet, + hasOcr: true, + matchField: "content", + }); + } else { + missingDocIds.push(docId); + } + }); + let extraResults: DocumentSearchResult[] = []; + if (missingDocIds.length > 0) { + const { data: extraDocs } = await supabase + .from("documents") + .select("id,title,updated_at,created_at,raw_text") + .in("id", missingDocIds) + .is("deleted_at", null); + extraResults = + extraDocs?.map((row) => { + const snippetText = snippetMap.get(row.id) ?? row.raw_text ?? ""; + return { + ...mapDocumentToResult(row, normalizedQuery || null, "content"), + snippet: buildSnippet(snippetText, normalizedQuery || null), + hasOcr: true, + }; + }) ?? []; + } + results = [...resultMap.values(), ...extraResults]; + } + } + + const response: DocumentSearchResponse = { + results, + recent: recentResults, + }; + + return NextResponse.json(response); +} diff --git a/src/app/api/search/recent/route.ts b/src/app/api/search/recent/route.ts new file mode 100644 index 00000000..71d4a10e --- /dev/null +++ b/src/app/api/search/recent/route.ts @@ -0,0 +1,54 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; + +interface RecentPayload { + workspaceId: string; + documentId: string; +} + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const { workspaceId, documentId }: RecentPayload = await request.json(); + + if (!workspaceId || !documentId) { + return NextResponse.json({ error: "缺少参数" }, { status: 400 }); + } + + const { data: membership, error: membershipError } = await supabase + .from("workspace_members") + .select("workspace_id") + .eq("workspace_id", workspaceId) + .eq("user_id", session.user.id) + .maybeSingle(); + + if (membershipError) { + return NextResponse.json({ error: membershipError.message }, { status: 500 }); + } + if (!membership) { + return NextResponse.json({ error: "无权访问该工作空间" }, { status: 403 }); + } + + const { error } = await supabase.from("user_recent_pages").upsert( + { + user_id: session.user.id, + workspace_id: workspaceId, + document_id: documentId, + last_accessed_at: new Date().toISOString(), + }, + { onConflict: "user_id,document_id" }, + ); + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ ok: true }); +} diff --git a/src/app/api/sidebar/route.ts b/src/app/api/sidebar/route.ts new file mode 100644 index 00000000..29911e98 --- /dev/null +++ b/src/app/api/sidebar/route.ts @@ -0,0 +1,47 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; +import { ensureDefaultWorkspace, fetchWorkspaceSummaries } from "@/lib/workspaces"; +import { fetchSidebarDataset } from "@/lib/sidebar-tree"; +import type { SidebarInitialData } from "@/components/sidebar/types"; + +export const dynamic = "force-dynamic"; + +export async function GET(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const url = new URL(request.url); + const workspaceIdParam = url.searchParams.get("workspaceId"); + + await ensureDefaultWorkspace(supabase, session.user.id, session.user.email ?? "我的空间"); + const { workspaces, activeWorkspaceId } = await fetchWorkspaceSummaries(supabase, session.user.id); + const targetWorkspaceId = workspaceIdParam || activeWorkspaceId; + + if (!targetWorkspaceId) { + return NextResponse.json({ error: "暂无可用工作空间" }, { status: 404 }); + } + + try { + const dataset = await fetchSidebarDataset(supabase, targetWorkspaceId); + + const payload: SidebarInitialData = { + activeWorkspaceId: targetWorkspaceId, + workspaces, + documents: dataset.documents, + trashedDocuments: dataset.trashedDocuments, + }; + + return NextResponse.json(payload); + } catch (error) { + return NextResponse.json( + { error: error instanceof Error ? error.message : "拉取侧边栏数据失败" }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/workspaces/switch/route.ts b/src/app/api/workspaces/switch/route.ts new file mode 100644 index 00000000..d921118b --- /dev/null +++ b/src/app/api/workspaces/switch/route.ts @@ -0,0 +1,54 @@ +import { NextResponse } from "next/server"; +import { createSupabaseRouteClient } from "@/lib/supabase/server"; + +export const dynamic = "force-dynamic"; + +export async function POST(request: Request) { + const supabase = await createSupabaseRouteClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + return NextResponse.json({ error: "未登录" }, { status: 401 }); + } + + const payload = await request.json().catch(() => ({})); + const workspaceId = payload.workspaceId as string | undefined; + + if (!workspaceId) { + return NextResponse.json({ error: "缺少 workspaceId" }, { status: 400 }); + } + + const { data: membership, error: membershipError } = await supabase + .from("workspace_members") + .select("id") + .eq("workspace_id", workspaceId) + .eq("user_id", session.user.id) + .single(); + + if (membershipError || !membership) { + return NextResponse.json({ error: "无权切换至该工作空间" }, { status: 403 }); + } + + const { error: resetError } = await supabase + .from("workspace_members") + .update({ is_default: false }) + .eq("user_id", session.user.id); + + if (resetError) { + return NextResponse.json({ error: resetError.message }, { status: 500 }); + } + + const { error: switchError } = await supabase + .from("workspace_members") + .update({ is_default: true }) + .eq("user_id", session.user.id) + .eq("workspace_id", workspaceId); + + if (switchError) { + return NextResponse.json({ error: switchError.message }, { status: 500 }); + } + + return NextResponse.json({ success: true }); +} diff --git a/src/app/globals.css b/src/app/globals.css index a2dc41ec..21318910 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,26 +1,410 @@ +@import url("https://rsms.me/inter/inter.css"); @import "tailwindcss"; +@import "tw-animate-css"; -:root { - --background: #ffffff; - --foreground: #171717; -} +@custom-variant dark (&:is(.dark *)); @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); --font-sans: var(--font-geist-sans); --font-mono: var(--font-geist-mono); + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); } -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + html { + font-family: "Inter", system-ui, sans-serif; + } + body { + @apply bg-background text-foreground; } } -body { - background: var(--background); - color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; +@layer components { + .wolai-hover { + @apply transition-colors duration-150 hover:bg-gray-50; + } + .wolai-selected { + @apply border-l-2 border-blue-500 bg-blue-50; + } + .wolai-blue { + @apply cursor-pointer text-[#2563eb] hover:underline; + } + .wolai-editor .bn-block-outer { + padding: 2px 0; + } + .wolai-editor .bn-inline-content a { + color: #2563eb; + text-decoration: underline; + } + .wolai-editor .bn-drag-handle { + opacity: 0; + transition: opacity 0.2s ease; + } + .wolai-editor .bn-block-group:hover .bn-drag-handle { + opacity: 1; + } + .wolai-editor[data-heading-numbering="true"] { + counter-reset: wolai-h1 wolai-h2 wolai-h3 wolai-h4 wolai-h5; + } + .wolai-editor[data-heading-numbering="true"] h1 { + counter-increment: wolai-h1; + counter-reset: wolai-h2; + } + .wolai-editor[data-heading-numbering="true"] h1::before { + content: counter(wolai-h1) ". "; + color: #94a3b8; + margin-right: 8px; + } + .wolai-editor[data-heading-numbering="true"] h2 { + counter-increment: wolai-h2; + counter-reset: wolai-h3; + } + .wolai-editor[data-heading-numbering="true"] h2::before { + content: counter(wolai-h1) "." counter(wolai-h2) ". "; + color: #94a3b8; + margin-right: 6px; + } + .wolai-editor[data-heading-numbering="true"] h3 { + counter-increment: wolai-h3; + counter-reset: wolai-h4; + } + .wolai-editor[data-heading-numbering="true"] h3::before { + content: counter(wolai-h1) "." counter(wolai-h2) "." counter(wolai-h3) ". "; + color: #cbd5f5; + margin-right: 4px; + } + .wolai-editor[data-heading-numbering="true"] h4 { + counter-increment: wolai-h4; + counter-reset: wolai-h5; + } + .wolai-editor[data-heading-numbering="true"] h4::before { + content: counter(wolai-h1) "." counter(wolai-h2) "." counter(wolai-h3) "." counter(wolai-h4) ". "; + color: #d0d7e7; + margin-right: 4px; + } + .wolai-editor[data-heading-numbering="true"] h5 { + counter-increment: wolai-h5; + } + .wolai-editor[data-heading-numbering="true"] h5::before { + content: counter(wolai-h1) "." counter(wolai-h2) "." counter(wolai-h3) "." counter(wolai-h4) "." counter(wolai-h5) ". "; + color: #d4d4d8; + margin-right: 4px; + } + .wolai-editor-show-structure .bn-block-outer { + outline: 1px dashed #d4d4d8; + border-radius: 8px; + padding: 4px 8px; + } + .wolai-advanced-todo { + display: flex; + align-items: center; + gap: 10px; + } + .wolai-advanced-todo__status { + border-radius: 999px; + border: 1px solid #c7d2fe; + padding: 2px 10px; + font-size: 12px; + cursor: pointer; + background-color: #eef2ff; + color: #312e81; + } + .wolai-advanced-todo__status.status-doing { + border-color: #fcd34d; + background-color: #fff7ed; + color: #92400e; + } + .wolai-advanced-todo__status.status-done { + border-color: #4ade80; + background-color: #ecfdf5; + color: #047857; + } + .wolai-advanced-todo__status.status-cancelled { + border-color: #fecdd3; + background-color: #fff1f2; + color: #9f1239; + } + .wolai-progress { + border-radius: 12px; + padding: 12px; + border: 1px solid #e5e7eb; + background-color: #f8fafc; + margin: 8px 0; + } + .wolai-progress__header { + display: flex; + align-items: center; + justify-content: space-between; + font-size: 12px; + color: #475569; + margin-bottom: 8px; + } + .wolai-progress__mode { + font-size: 11px; + border-radius: 12px; + background-color: #e0edff; + color: #1d4ed8; + padding: 2px 8px; + } + .wolai-progress__bar { + position: relative; + width: 100%; + height: 10px; + border-radius: 999px; + background-color: #e4e4e7; + overflow: hidden; + cursor: pointer; + } + .wolai-progress__fill { + position: absolute; + top: 0; + left: 0; + bottom: 0; + border-radius: inherit; + background-image: linear-gradient(90deg, #60a5fa, #2563eb); + } + .wolai-progress__percent { + display: block; + margin-top: 6px; + font-size: 12px; + color: #1d4ed8; + font-weight: 600; + } + .wolai-progress__description { + font-size: 13px; + color: #6b7280; + margin-top: 6px; + } + .wolai-media { + position: relative; + margin: 24px 0; + border-radius: 18px; + } + .wolai-media::after { + content: ""; + position: absolute; + inset: -8px; + border: 1px solid transparent; + border-radius: 24px; + transition: border-color 0.2s ease; + pointer-events: none; + } + .wolai-media:hover::after, + .wolai-media:focus-within::after { + border-color: rgba(37, 99, 235, 0.15); + } + .wolai-media--empty { + border: 1px dashed #bed5ff; + background-color: #fff; + padding: 20px; + border-radius: 16px; + } + .wolai-media__canvas { + position: relative; + border-radius: 18px; + overflow: hidden; + background-color: #fff; + box-shadow: 0 10px 40px rgba(15, 23, 42, 0.05); + margin: 0 auto; + } + .wolai-media__figure { + border-radius: inherit; + overflow: hidden; + background-color: #fff; + } + .wolai-media__figure img { + width: 100%; + border-radius: inherit; + object-fit: cover; + } + .wolai-media__figure--border img { + border: 1px solid #e2e8f0; + } + .wolai-media__figure figcaption { + padding: 8px 12px; + } + .wolai-media__figure--center figcaption { + text-align: center; + } + .wolai-media__figure--right figcaption { + text-align: right; + } + .wolai-media__quickbar { + position: absolute; + top: 12px; + right: 12px; + display: flex; + gap: 6px; + padding: 4px; + border-radius: 9999px; + background-color: rgba(15, 23, 42, 0.85); + box-shadow: 0 12px 32px rgba(15, 23, 42, 0.35); + opacity: 0; + transform: translateY(-4px); + transition: opacity 0.15s ease, transform 0.15s ease; + pointer-events: none; + } + .wolai-media:hover .wolai-media__quickbar, + .wolai-media:focus-within .wolai-media__quickbar { + opacity: 1; + transform: translateY(0); + pointer-events: auto; + } + .wolai-media__quickbutton { + display: inline-flex; + align-items: center; + justify-content: center; + width: 34px; + height: 34px; + border-radius: 9999px; + background-color: transparent; + color: #e2e8f0; + border: none; + cursor: pointer; + transition: background-color 0.15s ease, color 0.15s ease; + } + .wolai-media__quickbutton:hover, + .wolai-media__quickbutton:focus-visible { + background-color: rgba(255, 255, 255, 0.15); + color: #fff; + outline: none; + } + .wolai-media__hint { + margin-top: 6px; + font-size: 12px; + color: #94a3b8; + text-align: left; + } + .wolai-media__resize-handle { + position: absolute; + top: 50%; + width: 12px; + height: 44px; + border-radius: 2px; + background: rgba(15, 23, 42, 0.5); + transform: translateY(-50%); + opacity: 0; + transition: opacity 0.15s ease; + cursor: ew-resize; + z-index: 20; + } + .wolai-media__resize-handle--left { + left: -6px; + } + .wolai-media__resize-handle--right { + right: -6px; + } + .wolai-media:hover .wolai-media__resize-handle, + .wolai-media:focus-within .wolai-media__resize-handle { + opacity: 1; + } + .wolai-media__resize-handle.is-dragging { + background: rgba(37, 99, 235, 0.85); + } } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index f7fa87eb..f422648c 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,33 +1,36 @@ import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; +import { Inter } from "next/font/google"; import "./globals.css"; +import { SupabaseProvider } from "@/components/providers/supabase-provider"; +import { QueryProvider } from "@/components/providers/query-provider"; +import { createSupabaseServerClient } from "@/lib/supabase/server"; -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", +const inter = Inter({ subsets: ["latin"], + variable: "--font-inter", }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Wolai Clone", + description: "Stage0 + Stage1 implementation powered by Supabase", }; -export default function RootLayout({ +export default async function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { + const supabase = await createSupabaseServerClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + return ( - - - {children} + + + + {children} + ); diff --git a/src/app/page.tsx b/src/app/page.tsx index 295f8fdf..f591e488 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,65 +1,41 @@ -import Image from "next/image"; +import { redirect } from "next/navigation"; +import { createSupabaseServerClient } from "@/lib/supabase/server"; -export default function Home() { - return ( -
-
- Next.js logo -
-

- To get started, edit the page.tsx file. -

-

- Looking for a starting point or more instructions? Head over to{" "} - - Templates - {" "} - or the{" "} - - Learning - {" "} - center. -

-
- -
-
- ); +export default async function Home() { + const supabase = await createSupabaseServerClient(); + const { + data: { session }, + } = await supabase.auth.getSession(); + + if (!session) { + redirect("/login"); + } + + const { data: firstDoc } = await supabase + .from("documents") + .select("id") + .eq("user_id", session.user.id) + .order("created_at", { ascending: true }) + .limit(1) + .maybeSingle(); + + if (firstDoc?.id) { + redirect(`/documents/${firstDoc.id}`); + } + + const { data: createdDoc, error } = await supabase + .from("documents") + .insert({ + user_id: session.user.id, + title: "新页面", + content: {}, + }) + .select("id") + .single(); + + if (error || !createdDoc) { + redirect("/login"); + } + + redirect(`/documents/${createdDoc.id}`); } diff --git a/src/components/bottom-toolbar.tsx b/src/components/bottom-toolbar.tsx new file mode 100644 index 00000000..b458b6fc --- /dev/null +++ b/src/components/bottom-toolbar.tsx @@ -0,0 +1,36 @@ +"use client"; + +import { MessageCircle, Sparkles, Wand2 } from "lucide-react"; +import { useBackendHealth } from "@/hooks/use-backend-health"; +import { cn } from "@/lib/utils"; + +export function BottomToolbar() { + const status = useBackendHealth(); + const indicatorColor = + status === "ok" ? "bg-green-500" : status === "error" ? "bg-red-500" : "bg-gray-300"; + + return ( +
+
+ + 后端连接:{status === "ok" ? "正常" : status === "error" ? "异常" : "检测中"} +
+
+ + + +
+
+ ); +} diff --git a/src/components/breadcrumb.tsx b/src/components/breadcrumb.tsx new file mode 100644 index 00000000..1090faf8 --- /dev/null +++ b/src/components/breadcrumb.tsx @@ -0,0 +1,63 @@ +"use client"; + +import Link from "next/link"; +import { useParams, useSelectedLayoutSegments } from "next/navigation"; +import { ChevronRight, MoreHorizontal, Star } from "lucide-react"; +import type { DocumentRecord } from "@/lib/documents"; +import { findBreadcrumb } from "@/lib/documents"; +import { usePageLayoutStore } from "@/store/page-layout"; + +interface BreadcrumbProps { + documents: DocumentRecord[]; +} + +export function Breadcrumb({ documents }: BreadcrumbProps) { + const segments = useSelectedLayoutSegments(); + const params = useParams<{ id?: string }>(); + const paramId = typeof params?.id === "string" ? params.id : ""; + const activeId = paramId || segments?.[1] || ""; + const path = findBreadcrumb(documents, activeId); + const showInspector = usePageLayoutStore((state) => state.showInspector); + const toggleInspector = usePageLayoutStore((state) => state.toggleInspector); + + if (!path.length) { + return
请选择一个页面
; + } + + return ( +
+ +
+ + +
+
+ ); +} diff --git a/src/components/common/.gitkeep b/src/components/common/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/components/document-task-panel.tsx b/src/components/document-task-panel.tsx new file mode 100644 index 00000000..6dc437b3 --- /dev/null +++ b/src/components/document-task-panel.tsx @@ -0,0 +1,87 @@ +"use client"; + +import { useEffect, useMemo, useState } from "react"; +import { useSessionContext } from "@supabase/auth-helpers-react"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; + +interface TaskResponse { + task_id: string; + status: string; + progress: number; + message?: string | null; +} + +interface Props { + documentId: string; +} + +export function DocumentTaskPanel({ documentId }: Props) { + const { session } = useSessionContext(); + const [task, setTask] = useState(null); + const [pending, setPending] = useState(false); + const backendUrl = useMemo(() => process.env.NEXT_PUBLIC_BACKEND_URL, []); + + const triggerTask = async () => { + if (!backendUrl || !session?.access_token) return; + setPending(true); + try { + const response = await fetch(`${backendUrl}/api/v1/tasks/ocr`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${session.access_token}`, + }, + body: JSON.stringify({ + document_id: documentId, + file_url: "https://example.com/sample.pdf", + }), + }); + const data = await response.json(); + if (response.ok) { + setTask(data); + } + } finally { + setPending(false); + } + }; + + useEffect(() => { + if (!backendUrl || !session?.access_token || !task?.task_id) { + return; + } + const timer = setInterval(async () => { + const response = await fetch(`${backendUrl}/api/v1/tasks/${task.task_id}`, { + headers: { + Authorization: `Bearer ${session.access_token}`, + }, + }); + if (!response.ok) { + return; + } + const data = (await response.json()) as TaskResponse; + setTask(data); + if (data.status === "completed") { + clearInterval(timer); + } + }, 2000); + return () => clearInterval(timer); + }, [backendUrl, session?.access_token, task?.task_id]); + + return ( + + +
+
后端 OCR 流程
+
+ 状态:{task ? task.status : "未开始"} · 进度:{task ? `${task.progress}%` : "0%"} +
+ {task?.message &&
提示:{task.message}
} +
+ +
+
+ ); +} diff --git a/src/components/editor/.gitkeep b/src/components/editor/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/components/editor/blocknote-editor.tsx b/src/components/editor/blocknote-editor.tsx new file mode 100644 index 00000000..cc7b8f07 --- /dev/null +++ b/src/components/editor/blocknote-editor.tsx @@ -0,0 +1,585 @@ +"use client"; + +import "@blocknote/core/style.css"; +import "@blocknote/react/style.css"; +import "@blocknote/mantine/style.css"; + +import { useCallback, useEffect, useMemo, useState } from "react"; +import { BlockNoteView } from "@blocknote/mantine"; +import { + SideMenuController, + useCreateBlockNote, + type SideMenuProps, +} from "@blocknote/react"; +import { HocuspocusProvider } from "@hocuspocus/provider"; +import * as Y from "yjs"; +import type { Block } from "@blocknote/core"; +import { cn } from "@/lib/utils"; +import type { Json } from "@/types/supabase"; +import type { DocumentStats, PageOptionsState } from "@/types/page-options"; +import type { MediaAsset } from "@/types/media"; +import { customBlockSchema, type CustomBlockSchema } from "./schema"; +import { CustomSideMenu } from "./menus/CustomSideMenu"; +import { CustomSlashMenu } from "./menus/CustomSlashMenu"; +import { useDebouncedCallback } from "@/hooks/use-debounced-callback"; +import { DocumentToc, type TocEntry } from "@/components/editor/document-toc"; +import { useSearchPaletteStore } from "@/store/search-palette"; +import { useEditorBridgeStore } from "@/store/editor-bridge"; +import type { ReferenceTarget } from "@/types/search"; + +interface BlockNoteEditorProps { + documentId: string; + workspaceId: string; + initialContent: unknown; + pageOptions: PageOptionsState; + onStatsChange?: (stats: DocumentStats) => void; + onSnapshot?: (payload: { blocks: Json; stats: DocumentStats }) => void; +} + +const extractInitialBlocks = (content: unknown): Json | undefined => { + if (Array.isArray(content) && content.length > 0) { + return content as Json; + } + if (content && typeof content === "object") { + const maybeBlocks = (content as Record).blocks; + if (Array.isArray(maybeBlocks) && maybeBlocks.length > 0) { + return maybeBlocks as Json; + } + } + return undefined; +}; + +const extractInlineText = (block: Block): string => { + const inlineNodes = (block.content ?? []) as Array<{ text?: string }>; + return inlineNodes.map((node) => (typeof node.text === "string" ? node.text : "")).join("").trim(); +}; + +const buildHeadingToc = (blocks: Block[]): TocEntry[] => { + const counters = [0, 0, 0, 0, 0]; + const entries: TocEntry[] = []; + + const walk = (targetBlocks: Block[]) => { + targetBlocks.forEach((block) => { + if (block.type === "heading") { + const level = Math.min(5, Math.max(1, Number(block.props.level) || 1)); + counters[level - 1] += 1; + for (let i = level; i < counters.length; i += 1) { + counters[i] = 0; + } + const numbering = counters.slice(0, level).filter((value) => value > 0).join("."); + entries.push({ + id: block.id, + level, + numbering, + title: extractInlineText(block), + }); + } + if (block.children && block.children.length > 0) { + walk(block.children as Block[]); + } + }); + }; + + walk(blocks); + return entries; +}; + +const findBlockById = ( + blocks: Block[], + id: string, +): Block | undefined => { + for (const block of blocks) { + if (block.id === id) return block; + if (block.children && block.children.length > 0) { + const child = findBlockById(block.children as Block[], id); + if (child) return child; + } + } + return undefined; +}; + +const syncProgressMeters = (editorInstance: ReturnType) => { + if (!editorInstance) { + return; + } + const blocks = editorInstance.topLevelBlocks as Block[]; + const progressStats = new Map< + string, + { done: number; doing: number; total: number } + >(); + let activeProgressId: string | null = null; + + const traverse = (targetBlocks: Block[]) => { + targetBlocks.forEach((block) => { + if (block.type === "progressMeter" && block.props.auto) { + activeProgressId = block.id; + progressStats.set(block.id, { done: 0, doing: 0, total: 0 }); + } else if (block.type === "progressMeter" && !block.props.auto) { + activeProgressId = null; + } else if (block.type === "heading") { + activeProgressId = null; + } else if (block.type === "advancedTodo" && activeProgressId) { + const currentStat = progressStats.get(activeProgressId); + if (!currentStat) return; + if (block.props.status === "cancelled") { + return; + } + currentStat.total += 1; + if (block.props.status === "done") { + currentStat.done += 1; + } else if (block.props.status === "doing") { + currentStat.doing += 1; + } + } + + if (block.children && block.children.length > 0) { + traverse(block.children as Block[]); + } + }); + }; + + traverse(blocks); + + progressStats.forEach((stat, progressId) => { + const block = findBlockById(blocks, progressId); + if (!block) return; + const weightedDone = stat.done + stat.doing * 0.5; + const percent = stat.total === 0 ? 0 : Math.min(100, Math.round((weightedDone / stat.total) * 100)); + const summary = stat.total === 0 ? "暂无条目" : `${stat.done}/${stat.total} 完成`; + + if (block.props.percent !== percent || block.props.summary !== summary) { + editorInstance.updateBlock(block, { + props: { + percent, + summary, + }, + }); + } + }); +}; + +export function BlockNoteEditor({ + documentId, + workspaceId, + initialContent, + pageOptions, + onStatsChange, + onSnapshot, +}: BlockNoteEditorProps) { + const [isSaving, setIsSaving] = useState(false); + const [tocEntries, setTocEntries] = useState([]); + const openReferencePalette = useSearchPaletteStore((state) => state.openReference); + const registerEditorBridge = useEditorBridgeStore((state) => state.registerBridge); + + const normalizedInitialContent = useMemo( + () => extractInitialBlocks(initialContent), + [initialContent], + ); + + const collaboration = useMemo(() => { + const url = process.env.NEXT_PUBLIC_HOCUSPOCUS_URL; + if (!url) return null; + const doc = new Y.Doc(); + const provider = new HocuspocusProvider({ + url, + name: `document.${documentId}`, + document: doc, + }); + return { doc, provider }; + }, [documentId]); + + const editor = useCreateBlockNote( + { + initialContent: normalizedInitialContent as never, + schema: customBlockSchema, + collaboration: collaboration + ? { + provider: collaboration.provider, + fragment: collaboration.doc.getXmlFragment("wolai"), + user: { + name: "访客", + color: "#2563eb", + }, + } + : undefined, + }, + [documentId], + ); + + useEffect( + () => () => { + collaboration?.provider.destroy(); + collaboration?.doc.destroy(); + }, + [collaboration], + ); + + const saveContent = useCallback( + async (content: Json) => { + setIsSaving(true); + try { + await fetch("/api/documents/save", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ documentId, content }), + }); + } finally { + setIsSaving(false); + } + }, + [documentId], + ); + + const debouncedSave = useDebouncedCallback(saveContent, 800); + + useEffect(() => { + if (!editor) { + return undefined; + } + + let disposed = false; + const runSync = () => { + if (disposed) { + return; + } + const blocks = editor.topLevelBlocks; + debouncedSave(blocks as Json); + const typedBlocks = blocks as Block[]; + setTocEntries(buildHeadingToc(typedBlocks)); + syncProgressMeters(editor); + const stats = computeDocumentStats(typedBlocks); + onStatsChange?.(stats); + onSnapshot?.({ blocks: blocks as Json, stats }); + }; + + runSync(); + const unsubscribe = editor.onEditorContentChange(runSync); + return () => { + disposed = true; + if (typeof unsubscribe === "function") { + unsubscribe(); + } + }; + }, [editor, debouncedSave, onSnapshot, onStatsChange]); + + const jumpToHeading = useCallback((headingId: string) => { + const target = document.querySelector(`[data-id="${headingId}"]`); + if (target) { + target.scrollIntoView({ behavior: "smooth", block: "center" }); + } + }, []); + + const editorWrapperClass = cn( + "relative min-h-[60vh] rounded-2xl border border-transparent bg-white p-4 shadow-sm", + pageOptions.smallText ? "text-[15px]" : "text-[16px]", + ); + +const blocknoteClass = cn( + "wolai-editor min-h-full", + pageOptions.showStructure && "wolai-editor-show-structure", +); + +const buildDocumentPath = (documentId: string): string => { + if (typeof window === "undefined" || !window.location) { + return `/documents/${documentId}`; + } + return `${window.location.origin}/documents/${documentId}`; +}; + +const trimTrailingCharacter = ( + editorInstance: ReturnType | null, + block: Block, + char: string, +) => { + if (!editorInstance) { + return; + } + const content = Array.isArray(block.content) ? [...block.content] : []; + for (let index = content.length - 1; index >= 0; index -= 1) { + const node = content[index] as { text?: string }; + if (typeof node?.text === "string" && node.text.endsWith(char)) { + const nextText = node.text.slice(0, -1); + if (nextText.length === 0) { + content.splice(index, 1); + } else { + content[index] = { ...node, text: nextText }; + } + editorInstance.updateBlock(block, { content }); + break; + } + } +}; + +const generateBlockId = () => { + if (typeof crypto !== "undefined" && "randomUUID" in crypto) { + return crypto.randomUUID(); + } + return `ref_${Math.random().toString(36).slice(2, 10)}`; +}; + +const computeDocumentStats = (blocks: Block[]): DocumentStats => { + let characterCount = 0; + let wordCount = 0; + const accumulate = (targetBlocks: Block[]) => { + targetBlocks.forEach((block) => { + if (Array.isArray(block.content)) { + block.content.forEach((node: { text?: string }) => { + if (typeof node.text === "string") { + const text = node.text; + characterCount += text.length; + const trimmed = text.trim(); + if (trimmed.length === 0) { + return; + } + const tokens = trimmed.split(/\s+/).filter(Boolean); + if (tokens.length > 1) { + wordCount += tokens.length; + } else { + wordCount += trimmed.replace(/\s+/g, "").length; + } + } + }); + } + if (block.children && block.children.length > 0) { + accumulate(block.children as Block[]); + } + }); + }; + accumulate(blocks); + return { + wordCount, + characterCount, + blockCount: blocks.length, + }; +}; + + const insertMediaAssetBlock = useCallback( + (asset: MediaAsset) => { + if (!editor) { + return; + } + const fileUrl = asset.file_url ?? ""; + if (!fileUrl) { + return; + } + const cursor = editor.getTextCursorPosition(); + const referenceBlock = + cursor?.block ?? (editor.topLevelBlocks[editor.topLevelBlocks.length - 1] as Block | undefined); + if (!referenceBlock) { + return; + } + editor.insertBlocks( + [ + { + type: "media", + props: { + fileUrl, + thumbnailUrl: asset.thumbnail_url ?? fileUrl, + assetId: asset.id, + assetType: asset.asset_type ?? "image", + fileName: asset.file_name ?? "", + fileSize: asset.file_size ?? null, + mimeType: asset.mime_type ?? "", + ocrStatus: asset.ocr_status ?? "idle", + }, + }, + ], + referenceBlock, + "after", + ); + }, + [editor], + ); + + const uploadClipboardMedia = useCallback( + async (file: File) => { + if (!workspaceId) { + throw new Error("缺少空间信息,无法上传文件"); + } + const form = new FormData(); + form.append("file", file); + form.append("workspaceId", workspaceId); + form.append("documentId", documentId); + const response = await fetch("/api/media/upload", { + method: "POST", + body: form, + }); + if (!response.ok) { + const payload = await response.json().catch(() => null); + throw new Error(payload?.error ?? "上传失败"); + } + const payload = (await response.json()) as { asset: MediaAsset }; + if (!payload.asset) { + throw new Error("上传返回数据缺失"); + } + return payload.asset; + }, + [documentId, workspaceId], + ); + + useEffect(() => { + if (!editor) { + registerEditorBridge(null); + return; + } + const bridge = { + insertInlineReference: (target: ReferenceTarget, aliasText?: string) => { + editor.focus(); + const cursor = editor.getTextCursorPosition(); + const blockId = cursor?.block?.id ?? null; + const text = aliasText || target.title || "无标题"; + editor.insertInlineContent([ + { + type: "link", + href: buildDocumentPath(target.id), + content: text, + }, + { type: "text", text: " " }, + ]); + return { blockId }; + }, + insertEmbedReference: (target: ReferenceTarget) => { + editor.focus(); + const cursor = editor.getTextCursorPosition(); + const referenceBlock = + cursor?.block ?? editor.topLevelBlocks[editor.topLevelBlocks.length - 1]; + const blockId = generateBlockId(); + editor.insertBlocks( + [ + { + id: blockId, + type: "pageReference", + props: { + pageId: target.id, + title: target.title ?? "无标题", + }, + }, + ], + referenceBlock, + "after", + ); + return { blockId }; + }, + replaceWithSnapshot: (payload: Json) => { + editor.focus(); + const nextBlocks = Array.isArray(payload) + ? payload + : Array.isArray((payload as { blocks?: Json }).blocks) + ? ((payload as { blocks?: Json }).blocks as Json) + : []; + if (!Array.isArray(nextBlocks)) { + return; + } + editor.replaceBlocks(editor.topLevelBlocks, nextBlocks as never); + }, + }; + registerEditorBridge(bridge); + return () => registerEditorBridge(null); + }, [editor, registerEditorBridge]); + + useEffect(() => { + if (!editor) { + return undefined; + } + const handlePaste = (event: ClipboardEvent) => { + const activeElement = event.target; + if (!(activeElement instanceof HTMLElement) || !activeElement.closest(".wolai-editor")) { + return; + } + const items = Array.from(event.clipboardData?.files ?? []); + if (items.length === 0) { + return; + } + const imageFile = items.find((candidate) => candidate.type?.startsWith("image/")); + if (!imageFile) { + return; + } + event.preventDefault(); + void (async () => { + try { + const asset = await uploadClipboardMedia(imageFile); + insertMediaAssetBlock(asset); + } catch (error) { + console.error(error); + window.alert((error as Error).message ?? "粘贴图片失败,请稍后重试"); + } + })(); + }; + window.addEventListener("paste", handlePaste); + return () => window.removeEventListener("paste", handlePaste); + }, [editor, insertMediaAssetBlock, uploadClipboardMedia]); + + useEffect(() => { + if (!editor) { + return; + } + const buffer = { char: "", blockId: "", timestamp: 0 }; + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key !== "[" && event.key !== "#") { + buffer.char = ""; + buffer.blockId = ""; + buffer.timestamp = 0; + return; + } + const activeElement = document.activeElement; + if (!(activeElement instanceof HTMLElement) || !activeElement.closest(".wolai-editor")) { + return; + } + const { block } = editor.getTextCursorPosition(); + if (!block) { + return; + } + const now = Date.now(); + if ( + buffer.char === event.key && + buffer.blockId === block.id && + now - buffer.timestamp < 450 + ) { + event.preventDefault(); + trimTrailingCharacter(editor, block, event.key); + openReferencePalette({ + referenceMode: event.key === "[" ? "inline" : "embed", + }); + buffer.char = ""; + buffer.blockId = ""; + buffer.timestamp = 0; + } else { + buffer.char = event.key; + buffer.blockId = block.id; + buffer.timestamp = now; + } + }; + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [editor, openReferencePalette]); + + const layoutClass = cn( + "relative mx-auto w-full", + pageOptions.wideLayout ? "max-w-none" : "max-w-[980px]", + ); + + return ( +
+
+ + ) => ( + + )} + /> + + +
+ {isSaving ? "保存中..." : "已保存"} +
+
+ +
+ ); +} diff --git a/src/components/editor/blocks/AdvancedTodoBlock.tsx b/src/components/editor/blocks/AdvancedTodoBlock.tsx new file mode 100644 index 00000000..b501a572 --- /dev/null +++ b/src/components/editor/blocks/AdvancedTodoBlock.tsx @@ -0,0 +1,56 @@ +"use client"; + +import { createReactBlockSpec } from "@blocknote/react"; + +const TODO_STATES = ["todo", "doing", "done", "cancelled"] as const; + +const STATUS_LABELS: Record<(typeof TODO_STATES)[number], string> = { + todo: "未开始", + doing: "进行中", + done: "已完成", + cancelled: "已取消", +}; + +export const advancedTodoBlock = createReactBlockSpec( + { + type: "advancedTodo", + propSchema: { + status: { + default: "todo", + values: TODO_STATES, + }, + }, + content: "inline", + }, + { + render: ({ block, editor }) => { + const updateStatus = (next: (typeof TODO_STATES)[number]) => { + editor.updateBlock(block, { props: { status: next } }); + }; + + const handleClick = (event: React.MouseEvent) => { + const current = block.props.status as (typeof TODO_STATES)[number]; + if (event.altKey) { + updateStatus("cancelled"); + return; + } + const index = TODO_STATES.indexOf(current); + const nextState = TODO_STATES[(index + 1) % TODO_STATES.length]; + updateStatus(nextState); + }; + + return ( +
+ +
+
+ ); + }, + }, +)(); diff --git a/src/components/editor/blocks/MediaBlock.tsx b/src/components/editor/blocks/MediaBlock.tsx new file mode 100644 index 00000000..fe6ac7d7 --- /dev/null +++ b/src/components/editor/blocks/MediaBlock.tsx @@ -0,0 +1,498 @@ +"use client"; + +import { + useEffect, + useRef, + useState, + useMemo, + type JSX, + type MouseEvent as ReactMouseEvent, +} from "react"; +import { createReactBlockSpec } from "@blocknote/react"; +import type { Block, BlockNoteEditor } from "@blocknote/core"; +import { Download, Image as ImageIcon, Link as LinkIcon, MoreHorizontal, Paperclip, RefreshCcw, Type } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; +import { useImagePicker } from "@/components/media/image-picker-context"; +import type { MediaKind } from "@/types/media"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import type { CustomBlockSchema } from "../schema"; + +type MediaAlign = "left" | "center" | "right"; + +type MediaBlockRenderProps = { + block: Block; + editor: BlockNoteEditor; +}; + +const TYPE_LABEL_MAP: Record = { + image: "图片", + video: "视频", + audio: "音频", + file: "文件", +}; + +const deriveFileName = (value?: string) => { + if (!value) { + return "未命名资源"; + } + try { + const url = new URL(value); + const last = url.pathname.split("/").filter(Boolean).pop(); + if (last) { + return decodeURIComponent(last); + } + } catch { + const segments = value.split("?")[0]?.split("/") ?? []; + const last = segments.pop(); + if (last) { + return decodeURIComponent(last); + } + } + return "未命名资源"; +}; + +const formatFileSize = (size?: number | null) => { + if (!size || size <= 0) { + return "未知大小"; + } + const units = ["B", "KB", "MB", "GB", "TB"]; + let idx = 0; + let current = size; + while (current >= 1024 && idx < units.length - 1) { + current /= 1024; + idx += 1; + } + return `${current.toFixed(current >= 10 ? 0 : 1)} ${units[idx]}`; +}; + +const MediaBlockContent = ({ block, editor }: MediaBlockRenderProps) => { + const { openPicker } = useImagePicker(); + const [busy, setBusy] = useState(false); + const fileUrl = block.props.fileUrl as string; + const rawAssetType = (block.props.assetType as string) || "image"; + const assetType: MediaKind = + rawAssetType === "video" || rawAssetType === "audio" || rawAssetType === "file" + ? (rawAssetType as MediaKind) + : "image"; + const typeLabel = TYPE_LABEL_MAP[assetType] ?? TYPE_LABEL_MAP.image; + const canAlign = assetType === "image" || assetType === "video"; + const canToggleBorder = assetType === "image"; + const canTriggerOcr = assetType === "image"; + const canResize = assetType === "image" || assetType === "video"; + const [dragging, setDragging] = useState(null); + const [localWidth, setLocalWidth] = useState(() => (block.props.width ? Number(block.props.width) : 0)); + const mediaRef = useRef(null); + const latestWidthRef = useRef(localWidth); + const displayFileName = block.props.fileName ?? deriveFileName(fileUrl); + const captionRef = useRef(null); + const [captionEditing, setCaptionEditing] = useState(false); + const shouldShowCaption = captionEditing || Boolean(block.props.caption); + + const handleChoose = () => { + openPicker({ + defaultTab: fileUrl ? "recent" : "upload", + mediaType: assetType, + onSelect: (selection) => { + editor.updateBlock(block, { + props: { + fileUrl: selection.fileUrl, + thumbnailUrl: selection.thumbnailUrl ?? selection.fileUrl, + assetId: selection.assetId, + assetType: selection.assetType ?? rawAssetType, + fileName: selection.fileName ?? block.props.fileName ?? "", + fileSize: selection.fileSize ?? block.props.fileSize ?? null, + mimeType: selection.mimeType ?? block.props.mimeType ?? "", + ocrStatus: "idle", + }, + }); + }, + }); + }; + + const toggleBorder = () => { + editor.updateBlock(block, { props: { hasBorder: !block.props.hasBorder } }); + }; + + const setAlign = (align: MediaAlign) => { + editor.updateBlock(block, { props: { captionAlign: align } }); + }; + + const handleCaptionChange = (value: string) => { + editor.updateBlock(block, { props: { caption: value } }); + }; + + const enableCaptionEdit = () => { + setCaptionEditing(true); + setTimeout(() => captionRef.current?.focus(), 0); + }; + + useEffect(() => { + if (!shouldShowCaption && captionEditing) { + setCaptionEditing(false); + } + }, [captionEditing, shouldShowCaption]); + useEffect(() => { + if (!dragging) { + setLocalWidth(block.props.width ? Number(block.props.width) : 0); + } + }, [block.props.width, dragging]); + useEffect(() => { + latestWidthRef.current = localWidth; + }, [localWidth]); + + const resolvedWidth = useMemo(() => { + if (!canResize) return 0; + if (localWidth > 0) return clampWidth(localWidth); + if (block.props.width && Number(block.props.width) > 0) { + return clampWidth(Number(block.props.width)); + } + return 0; + }, [block.props.width, canResize, localWidth]); + + const handleResizeStart = (event: ReactMouseEvent, side: "left" | "right") => { + if (!canResize) return; + event.preventDefault(); + event.stopPropagation(); + const canvasWidth = resolvedWidth || mediaRef.current?.offsetWidth || 0; + if (!canvasWidth) { + return; + } + setDragging({ + side, + startX: event.clientX, + startWidth: canvasWidth, + }); + }; + + useEffect(() => { + if (!dragging) { + return undefined; + } + const handleMove = (event: MouseEvent) => { + event.preventDefault(); + const delta = event.clientX - dragging.startX; + const adjusted = dragging.side === "left" ? -delta : delta; + const next = clampWidth(dragging.startWidth + adjusted); + setLocalWidth(next); + }; + const handleUp = () => { + const finalWidth = latestWidthRef.current > 0 ? latestWidthRef.current : dragging.startWidth; + editor.updateBlock(block, { props: { width: clampWidth(finalWidth) } }); + setDragging(null); + }; + window.addEventListener("mousemove", handleMove); + window.addEventListener("mouseup", handleUp); + return () => { + window.removeEventListener("mousemove", handleMove); + window.removeEventListener("mouseup", handleUp); + }; + }, [dragging, editor, block]); + + const handleLink = () => { + const next = window.prompt(`输入${typeLabel}跳转链接`, block.props.linkUrl ?? ""); + if (next === null) return; + editor.updateBlock(block, { props: { linkUrl: next.trim() } }); + }; + + const viewOriginal = () => { + if (!fileUrl) return; + window.open(fileUrl, "_blank", "noopener,noreferrer"); + }; + + const downloadAsset = () => { + if (!fileUrl) return; + const anchor = document.createElement("a"); + anchor.href = fileUrl; + anchor.download = block.props.fileName || block.props.caption || typeLabel; + anchor.click(); + }; + + const triggerOcr = async () => { + if (!block.props.assetId) { + window.alert("请先上传图片后再执行 OCR"); + return; + } + setBusy(true); + try { + const response = await fetch("/api/media/ocr", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ assetId: block.props.assetId }), + }); + if (!response.ok) { + const payload = await response.json().catch(() => null); + throw new Error(payload?.error ?? "触发 OCR 失败"); + } + editor.updateBlock(block, { props: { ocrStatus: "processing" } }); + window.alert("已提交 OCR 任务,稍后可在搜索面板中通过 OCR 结果搜索。"); + } catch (error) { + window.alert((error as Error).message); + } finally { + setBusy(false); + } + }; + + if (!fileUrl) { + return ( +
+ +

支持上传、最近及外链插入

+
+ ); + } + + const renderPreviewContent = () => { + if (assetType === "video") { + return ( + + ); + } + if (assetType === "audio") { + return ( +
+ +

{displayFileName}

+
+ ); + } + if (assetType === "file") { + return ( +
+ + + +
+

{displayFileName}

+ {block.props.fileSize ? ( +

{formatFileSize(block.props.fileSize)}

+ ) : null} +
+
+ ); + } + const inlineStyle = resolvedWidth ? { width: `${resolvedWidth}px` } : undefined; + return {block.props.caption; + }; + + const figure = ( +
+
{renderPreviewContent()}
+ {shouldShowCaption && ( +
+ handleCaptionChange(event.target.value)} + onBlur={() => setCaptionEditing(false)} + placeholder={assetType === "file" ? "添加文件说明..." : "添加说明..."} + className="w-full border-none bg-transparent text-sm text-[#475569] outline-none" + /> +
+ )} +
+ ); + + type QuickAction = { key: string; label: string; icon: JSX.Element; onClick: () => void }; + const quickActions: QuickAction[] = [ + { + key: "replace", + label: `替换${typeLabel}`, + icon: , + onClick: handleChoose, + }, + canToggleBorder + ? { + key: "border", + label: block.props.hasBorder ? "取消边框" : "显示边框", + icon: , + onClick: toggleBorder, + } + : null, + !shouldShowCaption + ? { + key: "caption", + label: "添加说明", + icon: , + onClick: enableCaptionEdit, + } + : null, + { + key: "link", + label: block.props.linkUrl ? "编辑链接" : "添加链接", + icon: , + onClick: handleLink, + }, + { + key: "download", + label: `下载${typeLabel}`, + icon: , + onClick: downloadAsset, + }, + ].filter((action): action is QuickAction => Boolean(action)); + + const dropdownLinkLabel = block.props.linkUrl ? "编辑链接" : "添加链接"; + + return ( +
+
+ {block.props.linkUrl ? ( + + {figure} + + ) : ( + figure + )} +
+ {quickActions.map((action) => ( + + ))} + + + + + + 替换资源 + {!shouldShowCaption && ( + 添加说明 + )} + {canToggleBorder && ( + + {block.props.hasBorder ? "取消边框" : "显示边框"} + + )} + {canAlign && ( + <> + 说明对齐 + setAlign("left")}>左对齐 + setAlign("center")}>居中 + setAlign("right")}>右对齐 + + + )} + {dropdownLinkLabel} + handleCopyLink(fileUrl)}>复制链接 + 查看原文件 + 下载到本地 + {canTriggerOcr && ( + <> + + + {busy ? "OCR 进行中..." : "触发 OCR 识别"} + + + )} + + +
+ {canResize && ( + <> + handleResizeStart(event, "left")} /> + handleResizeStart(event, "right")} /> + + )} +
+
{block.props.ocrStatus === "processing" ? "OCR 处理中..." : ""}
+
+ ); +}; + +export const mediaBlock = createReactBlockSpec( + { + type: "media", + propSchema: { + fileUrl: { default: "", type: "string" }, + thumbnailUrl: { default: "", type: "string" }, + caption: { default: "", type: "string" }, + captionAlign: { default: "left", values: ["left", "center", "right"] as MediaAlign[] }, + hasBorder: { default: true, type: "boolean" }, + linkUrl: { default: "", type: "string" }, + assetId: { default: "", type: "string" }, + assetType: { default: "image", type: "string" }, + fileName: { default: "", type: "string" }, + fileSize: { default: 0, type: "number" }, + mimeType: { default: "", type: "string" }, + width: { default: 0, type: "number" }, + ocrStatus: { default: "idle", type: "string" }, + }, + content: "none", + }, + { + render: (props) => , + }, +)(); +const handleCopyLink = async (targetUrl: string | null) => { + if (!targetUrl) return; + try { + if (navigator?.clipboard?.writeText) { + await navigator.clipboard.writeText(targetUrl); + window.alert("链接已复制"); + } else { + throw new Error("no clipboard"); + } + } catch { + window.prompt("请复制以下链接", targetUrl); + } +}; + +const ResizeHandle = ({ + side, + onMouseDown, + dragging, +}: { + side: "left" | "right"; + dragging: boolean; + onMouseDown: (event: ReactMouseEvent) => void; +}) => ( + +); + +const clampWidth = (value: number) => { + const min = 240; + const max = 960; + if (Number.isNaN(value)) return min; + return Math.max(min, Math.min(max, value)); +}; diff --git a/src/components/editor/blocks/PageReferenceBlock.tsx b/src/components/editor/blocks/PageReferenceBlock.tsx new file mode 100644 index 00000000..a8905fe5 --- /dev/null +++ b/src/components/editor/blocks/PageReferenceBlock.tsx @@ -0,0 +1,114 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { createReactBlockSpec } from "@blocknote/react"; +import { RiFileTextFill } from "react-icons/ri"; +import { useRouter } from "next/navigation"; +import { supabaseBrowser } from "@/lib/supabase/client"; + +const normalizeTitle = (value?: string | null) => { + if (!value || !value.trim()) { + return "未命名页面"; + } + return value; +}; + +const PageReferenceContent = ({ pageId, title }: { pageId: string; title: string }) => { + const router = useRouter(); + const fallbackTitle = normalizeTitle(title); + const [resolvedTitle, setResolvedTitle] = useState(fallbackTitle); + + useEffect(() => { + setResolvedTitle(fallbackTitle); + }, [fallbackTitle]); + + useEffect(() => { + if (!pageId) { + return; + } + let cancelled = false; + const applyTitle = (nextTitle?: string | null) => { + if (!cancelled) { + setResolvedTitle(normalizeTitle(nextTitle)); + } + }; + + const fetchTitle = async () => { + try { + const { data } = await supabaseBrowser + .from("documents") + .select("title") + .eq("id", pageId) + .single(); + if (data) { + applyTitle(data.title); + } + } catch { + // ignore fetch errors,等待后续订阅同步 + } + }; + + void fetchTitle(); + + const channel = supabaseBrowser + .channel(`page-ref-${pageId}`) + .on( + "postgres_changes", + { event: "UPDATE", schema: "public", table: "documents", filter: `id=eq.${pageId}` }, + (payload) => { + const nextTitle = (payload.new as { title?: string } | null)?.title ?? null; + applyTitle(nextTitle); + }, + ) + .subscribe(); + + return () => { + cancelled = true; + supabaseBrowser.removeChannel(channel); + }; + }, [pageId]); + + const navigate = () => { + if (pageId) { + router.push(`/documents/${pageId}`); + } + }; + + return ( +
{ + if ((event.key === "Enter" || event.key === " ") && pageId) { + event.preventDefault(); + navigate(); + } + }} + className="group mt-2 flex items-center gap-3 rounded-[4px] px-4 py-3 text-[#2563eb] hover:bg-[#f5f5f5]" + style={{ fontFamily: "Inter, system-ui, sans-serif" }} + > + + {resolvedTitle} + + 点击进入 → + +
+ ); +}; + +export const pageReferenceBlock = createReactBlockSpec( + { + type: "pageReference", + propSchema: { + pageId: { default: "" }, + title: { default: "未命名页面" }, + }, + content: "none", + }, + () => ({ + render: ({ block }) => ( + + ), + }), +)(); diff --git a/src/components/editor/blocks/ProgressBlock.tsx b/src/components/editor/blocks/ProgressBlock.tsx new file mode 100644 index 00000000..347401b7 --- /dev/null +++ b/src/components/editor/blocks/ProgressBlock.tsx @@ -0,0 +1,50 @@ +"use client"; + +import { createReactBlockSpec } from "@blocknote/react"; + +export const progressBlock = createReactBlockSpec( + { + type: "progressMeter", + propSchema: { + percent: { default: 0, type: "number" }, + auto: { default: true, type: "boolean" }, + summary: { default: "", type: "string" }, + }, + content: "inline", + }, + { + render: ({ block, editor }) => { + const percent = block.props.percent ?? 0; + const handleToggle = () => { + editor.updateBlock(block, { props: { auto: !block.props.auto } }); + }; + + const handleBarClick = () => { + if (block.props.auto) return; + const input = window.prompt("设置进度(0-100)", percent.toString()); + if (!input) return; + const value = Number.parseInt(input, 10); + if (Number.isNaN(value)) return; + editor.updateBlock(block, { + props: { percent: Math.min(100, Math.max(0, value)) }, + }); + }; + + return ( +
+
+ {block.props.summary || "暂无条目"} + +
+
+
+
+ {percent}% +
+
+ ); + }, + }, +)(); diff --git a/src/components/editor/document-content.tsx b/src/components/editor/document-content.tsx new file mode 100644 index 00000000..a4284a29 --- /dev/null +++ b/src/components/editor/document-content.tsx @@ -0,0 +1,259 @@ +"use client"; + +import dynamic from "next/dynamic"; +import { useCallback, useEffect, useMemo, useState, type ChangeEvent, type KeyboardEvent } from "react"; +import type { DocumentStats, PageOptionsState } from "@/types/page-options"; +import { PageOptionsSidebar } from "@/components/editor/page-options-sidebar"; +import { PageBacklinksPanel } from "@/components/editor/page-backlinks-panel"; +import { useEditorBridgeStore } from "@/store/editor-bridge"; +import { usePageLayoutStore } from "@/store/page-layout"; +import type { Json } from "@/types/supabase"; +import { DocumentHistoryDrawer } from "@/components/editor/document-history-drawer"; +import type { DocumentSnapshot } from "@/types/document"; +import { useDebouncedCallback } from "@/hooks/use-debounced-callback"; +import { ImagePickerProvider } from "@/components/media/image-picker-context"; + +const BlockNoteEditor = dynamic( + () => import("@/components/editor/blocknote-editor").then((mod) => mod.BlockNoteEditor), + { + ssr: false, + loading: () => ( +
编辑器加载中...
+ ), + }, +); + +export interface DocumentContentProps { + documentId: string; + workspaceId: string; + title: string | null; + updatedAt: string | null; + initialContent: unknown; + initialOptions: PageOptionsState; + initialStats: DocumentStats | null; +} + +const defaultOptions: PageOptionsState = { + wideLayout: false, + smallText: false, + showHeadingNumbers: true, + showToc: false, + showStructure: false, + protectEditing: false, + showWordCount: true, +}; +const defaultStats: DocumentStats = { wordCount: 0, characterCount: 0, blockCount: 0 }; + +export function DocumentContent({ + documentId, + workspaceId, + title, + updatedAt, + initialContent, + initialOptions, + initialStats, +}: DocumentContentProps) { + const [options, setOptions] = useState(initialOptions ?? defaultOptions); + const [stats, setStats] = useState(initialStats ?? defaultStats); + const [history, setHistory] = useState([]); + const [historyOpen, setHistoryOpen] = useState(false); + const editorBridge = useEditorBridgeStore((state) => state.bridge); + const showInspector = usePageLayoutStore((state) => state.showInspector); + const [pageTitle, setPageTitle] = useState(title ?? "无标题"); + + /* eslint-disable react-hooks/set-state-in-effect */ + useEffect(() => { + setPageTitle(title ?? "无标题"); + }, [title]); + + useEffect(() => { + setOptions(initialOptions ?? defaultOptions); + }, [initialOptions]); + + useEffect(() => { + setStats(initialStats ?? defaultStats); + }, [initialStats]); + /* eslint-enable react-hooks/set-state-in-effect */ + + const persistTitle = useCallback( + async (nextTitle: string) => { + const payload = nextTitle.trim() || "无标题"; + await fetch("/api/documents/title", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ documentId, title: payload }), + }); + }, + [documentId], + ); + + const debouncedPersistTitle = useDebouncedCallback((value: string) => { + void persistTitle(value); + }, 600); + + const handleTitleChange = (event: ChangeEvent) => { + const value = event.target.value; + setPageTitle(value); + debouncedPersistTitle(value); + }; + + const handleTitleBlur = () => { + void persistTitle(pageTitle); + }; + + const handleTitleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Enter") { + event.preventDefault(); + event.currentTarget.blur(); + } + }; + + const persistOptions = useCallback( + async (patch: Partial) => { + try { + const response = await fetch("/api/documents/options", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ documentId, options: patch }), + }); + if (!response.ok) { + const payload = await response.json().catch(() => null); + console.error(payload?.error ?? "更新页面选项失败"); + } + } catch (error) { + console.error(error); + } + }, + [documentId], + ); + + const toggleOption = (key: keyof PageOptionsState) => { + setOptions((prev) => { + const nextValue = !prev[key]; + const next = { ...prev, [key]: nextValue }; + void persistOptions({ [key]: nextValue } as Partial); + return next; + }); + }; + + const formattedUpdatedAt = useMemo(() => { + if (!updatedAt) return ""; + return new Date(updatedAt).toLocaleString(); + }, [updatedAt]); + + const handleExport = useCallback(() => { + const latest = history[0]; + if (!latest) { + window.alert("暂无可导出的内容"); + return; + } + const payload = JSON.stringify(latest.blocks, null, 2); + const blob = new Blob([payload], { type: "application/json" }); + const url = URL.createObjectURL(blob); + const anchor = document.createElement("a"); + anchor.href = url; + anchor.download = `${title ?? "未命名页面"}-${new Date(latest.timestamp).toISOString()}.json`; + anchor.click(); + URL.revokeObjectURL(url); + }, [history, title]); + + const handleSnapshot = useCallback((payload: { blocks: Json; stats: DocumentStats }) => { + setHistory((prev) => { + const now = Date.now(); + if (prev.length > 0 && now - prev[0].timestamp < 4000) { + return prev; + } + const snapshot: DocumentSnapshot = { + id: `${now}-${Math.random().toString(36).slice(2, 8)}`, + timestamp: now, + blocks: payload.blocks, + stats: payload.stats, + }; + return [snapshot, ...prev].slice(0, 15); + }); + }, []); + + const persistStatsRequest = useCallback((next: DocumentStats) => { + void fetch("/api/documents/stats", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ documentId, stats: next }), + }).catch((error) => console.error(error)); + }, [documentId]); + + const persistStats = useDebouncedCallback(persistStatsRequest, 1500); + + const handleStatsChange = useCallback( + (nextStats: DocumentStats) => { + setStats(nextStats); + persistStats(nextStats); + }, + [persistStats], + ); + + const handleRestoreSnapshot = useCallback( + (snapshot: DocumentSnapshot) => { + if (!editorBridge) { + window.alert("编辑器尚未准备好,无法恢复历史版本"); + return; + } + editorBridge.replaceWithSnapshot(snapshot.blocks); + setHistoryOpen(false); + }, + [editorBridge], + ); + + return ( + +
+
+
+
+ +
+ {options.protectEditing && ( +

当前页面已开启编辑保护,关闭后方可修改内容。

+ )} +

最近更新:{formattedUpdatedAt}

+
+
+ + +
+
+ {showInspector && ( + setHistoryOpen(true)} + /> + )} +
+ +
+ ); +} diff --git a/src/components/editor/document-history-drawer.tsx b/src/components/editor/document-history-drawer.tsx new file mode 100644 index 00000000..0c593614 --- /dev/null +++ b/src/components/editor/document-history-drawer.tsx @@ -0,0 +1,51 @@ +"use client"; + +import { Drawer, DrawerContent, DrawerDescription, DrawerHeader, DrawerTitle } from "@/components/ui/drawer"; +import { Button } from "@/components/ui/button"; +import type { DocumentSnapshot } from "@/types/document"; + +interface DocumentHistoryDrawerProps { + open: boolean; + onOpenChange: (open: boolean) => void; + history: DocumentSnapshot[]; + onRestore: (snapshot: DocumentSnapshot) => void; +} + +export function DocumentHistoryDrawer({ open, onOpenChange, history, onRestore }: DocumentHistoryDrawerProps) { + return ( + + + + 页面历史 + 最近保存的 15 个版本,可以一键恢复。 + +
+ {history.length === 0 ? ( +
+ 尚未产生历史快照,编辑后会自动生成。 +
+ ) : ( + history.map((snapshot) => ( +
+
+
+ {new Date(snapshot.timestamp).toLocaleString()} +
+
+ 字数 {snapshot.stats.wordCount} · 字符 {snapshot.stats.characterCount} +
+
+ +
+ )) + )} +
+
+
+ ); +} diff --git a/src/components/editor/document-shell.tsx b/src/components/editor/document-shell.tsx new file mode 100644 index 00000000..fb2021e7 --- /dev/null +++ b/src/components/editor/document-shell.tsx @@ -0,0 +1,37 @@ +"use client"; + +import dynamic from "next/dynamic"; +import { useEffect, useState } from "react"; +import type { DocumentContentProps } from "@/components/editor/document-content"; + +const DocumentContent = dynamic( + () => import("@/components/editor/document-content").then((mod) => mod.DocumentContent), + { + ssr: false, + loading: () => ( +
+ 正在载入编辑器... +
+ ), + }, +); + +export function DocumentShell(props: DocumentContentProps) { + const [mounted, setMounted] = useState(false); + + /* eslint-disable react-hooks/set-state-in-effect */ + useEffect(() => { + setMounted(true); + }, []); + /* eslint-enable react-hooks/set-state-in-effect */ + + if (!mounted) { + return ( +
+ 正在载入编辑器... +
+ ); + } + + return ; +} diff --git a/src/components/editor/document-toc.tsx b/src/components/editor/document-toc.tsx new file mode 100644 index 00000000..cdb96bf7 --- /dev/null +++ b/src/components/editor/document-toc.tsx @@ -0,0 +1,48 @@ +"use client"; + +import { cn } from "@/lib/utils"; + +export interface TocEntry { + id: string; + title: string; + level: number; + numbering: string; +} + +interface DocumentTocProps { + entries: TocEntry[]; + visible: boolean; + onJump: (id: string) => void; +} + +export function DocumentToc({ entries, visible, onJump }: DocumentTocProps) { + if (!visible || entries.length === 0) { + return null; + } + + return ( +
+
+
标题目录
+
    + {entries.map((entry) => ( +
  • + +
  • + ))} +
+
+
+ ); +} diff --git a/src/components/editor/menus/CustomSideMenu.tsx b/src/components/editor/menus/CustomSideMenu.tsx new file mode 100644 index 00000000..45a56b09 --- /dev/null +++ b/src/components/editor/menus/CustomSideMenu.tsx @@ -0,0 +1,335 @@ +'use client'; + +import { useCallback, useMemo } from "react"; +import type { Block, PartialBlock } from "@blocknote/core"; +import { + BlockColorsItem, + SideMenu, + TableColumnHeaderItem, + TableRowHeaderItem, + useBlockNoteEditor, + useComponentsContext, + type DragHandleMenuProps, + type SideMenuProps, +} from "@blocknote/react"; +import { useRouter } from "next/navigation"; +import type { CustomBlockSchema } from "../schema"; + +type InlineNode = { text?: unknown }; +type TableMenuBlock = Parameters< + typeof TableRowHeaderItem +>[0]["block"]; +type DraftBlock = PartialBlock & { id?: string }; +type ConvertOption = { + label: string; + type?: Block["type"]; + props?: Record; + shortcut?: string; + action?: () => void; +}; + +type CustomDragProps = DragHandleMenuProps & { + currentDocumentId: string; +}; + +const extractText = (block: Block) => { + const inlineNodes = block.content as InlineNode[] | undefined; + const maybeText = inlineNodes?.[0]?.text; + if (typeof maybeText === "string" && maybeText.trim().length > 0) { + return maybeText.trim(); + } + return "未命名页面"; +}; + +const CustomDragHandleMenu = ({ block, currentDocumentId }: CustomDragProps) => { + const Components = useComponentsContext()!; + const editor = useBlockNoteEditor(); + const router = useRouter(); + + const duplicateBlock = useCallback(() => { + const blockWithoutId: DraftBlock = { ...block }; + delete blockWithoutId.id; + editor.insertBlocks([blockWithoutId], block, "after"); + }, [block, editor]); + + const removePageReference = useCallback(async () => { + if (block.type === "pageReference") { + const pageId = block.props.pageId; + if (pageId) { + await fetch("/api/documents/delete", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ documentId: pageId }), + }); + } + } + editor.removeBlocks([block.id]); + router.refresh(); + }, [block, editor, router]); + + const handleDeleteBlock = useCallback(() => { + if (block.type === "pageReference") { + void removePageReference(); + return; + } + editor.removeBlocks([block.id]); + }, [block, editor, removePageReference]); + + const turnToPage = useCallback(async () => { + const response = await fetch("/api/documents/create-child", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + parentId: currentDocumentId, + title: extractText(block), + blocks: [block], + }), + }); + + if (!response.ok) { + return; + } + + const { pageId, title } = await response.json(); + + editor.replaceBlocks( + [block.id], + [ + { + type: "pageReference", + props: { pageId, title }, + } as PartialBlock, + ], + ); + router.refresh(); + }, [block, currentDocumentId, editor, router]); + + const moveOrEmbedBlock = useCallback(async () => { + if (typeof window === "undefined") { + return; + } + const targetParent = window.prompt("输入目标页面 ID(将在该页面末尾插入新子页面)", currentDocumentId); + if (!targetParent) { + return; + } + const response = await fetch("/api/documents/create-child", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + parentId: targetParent.trim(), + title: extractText(block), + blocks: [block], + }), + }); + if (!response.ok) { + window.alert("移动失败,请确认页面 ID"); + return; + } + const { pageId, title } = await response.json(); + editor.replaceBlocks( + [block.id], + [ + { + type: "pageReference", + props: { pageId, title }, + } as PartialBlock, + ], + ); + router.refresh(); + }, [block, currentDocumentId, editor, router]); + + const convertOptions = useMemo( + () => [ + { label: "文本", type: "paragraph", shortcut: "Ctrl+Alt+0" }, + { label: "待办列表", type: "checkListItem", shortcut: "Ctrl+Shift+5" }, + { label: "高级待办列表", type: "advancedTodo" }, + { label: "主标题", type: "heading", props: { level: 1 }, shortcut: "Ctrl+Shift+1" }, + { label: "大标题", type: "heading", props: { level: 2 }, shortcut: "Ctrl+Shift+2" }, + { label: "中标题", type: "heading", props: { level: 3 }, shortcut: "Ctrl+Shift+3" }, + { label: "小标题", type: "heading", props: { level: 4 }, shortcut: "Ctrl+Shift+4" }, + { label: "页面", action: turnToPage }, + { label: "列表", type: "bulletListItem", shortcut: "Ctrl+Shift+6" }, + { label: "数字列表", type: "numberedListItem", shortcut: "Ctrl+Shift+7" }, + { label: "折叠列表", type: "toggleListItem", shortcut: "Ctrl+Shift+8" }, + { label: "折叠标题", type: "heading", props: { level: 2, isToggleable: true } }, + { label: "引述文字", type: "blockquote" }, + { label: "代码片段", type: "codeBlock" }, + ], + [turnToPage], + ); + + const convertBlock = useCallback( + (option: ConvertOption) => { + if (option.action) { + option.action(); + return; + } + if (!option.type) return; + editor.updateBlock(block, { + type: option.type, + props: option.props ?? {}, + }); + }, + [block, editor], + ); + + const copyBlockLink = useCallback(async () => { + if (typeof window === "undefined") { + return; + } + const url = `${window.location.origin}/documents/${currentDocumentId}#block-${block.id}`; + try { + await navigator.clipboard.writeText(url); + window.alert("块链接已复制"); + } catch { + window.prompt("复制失败,请手动复制", url); + } + }, [block.id, currentDocumentId]); + + const openOnRight = useCallback(() => { + if (typeof window === "undefined") { + return; + } + const url = `${window.location.origin}/documents/${currentDocumentId}?preview=sidebar&focus=${block.id}`; + window.open(url, "_blank", "noopener,noreferrer"); + }, [block.id, currentDocumentId]); + + const setAdvancedTodoStatus = useCallback( + (status: "todo" | "doing" | "done" | "cancelled") => { + if (block.type !== "advancedTodo") return; + editor.updateBlock(block, { + props: { status }, + }); + }, + [block, editor], + ); + + const toggleProgressMode = useCallback(() => { + if (block.type !== "progressMeter") return; + editor.updateBlock(block, { + props: { auto: !block.props.auto }, + }); + }, [block, editor]); + + const setManualProgress = useCallback(() => { + if (block.type !== "progressMeter") return; + const value = Number.parseInt(window.prompt("手动设置进度(0-100)", String(block.props.percent ?? 0)) ?? "", 10); + if (Number.isNaN(value)) return; + const clamped = Math.min(100, Math.max(0, value)); + editor.updateBlock(block, { + props: { percent: clamped }, + }); + }, [block, editor]); + + return ( + + + 在右侧边栏打开 + + + + + + 转换为 + + + + {convertOptions.map((option) => ( + convertBlock(option)} + > + {option.label} + {option.shortcut && {option.shortcut}} + + ))} + + + + + 拷贝副本 + + + + 复制链接 + + + + 移动/嵌入到... + + + window.alert("块历史功能开发中,敬请期待")} + > + 块历史... + + + window.alert("评论功能暂未开放")} + > + 评论 + + + + 删除 + + + 颜色 + 表头(行) + 表头(列) + + {block.type === "advancedTodo" && ( + <> + + {[ + { label: "设为未开始", status: "todo" as const }, + { label: "设为进行中", status: "doing" as const }, + { label: "设为已完成", status: "done" as const }, + { label: "设为取消", status: "cancelled" as const }, + ].map((item) => ( + setAdvancedTodoStatus(item.status)} + > + {item.label} + + ))} + + )} + + {block.type === "progressMeter" && ( + <> + + + {block.props.auto ? "切换为手动进度" : "切换为自动进度"} + + {!block.props.auto && ( + + 手动设置百分比 + + )} + + )} + + ); +}; + +type CustomSideMenuProps = SideMenuProps & { + currentDocumentId: string; +}; + +export const CustomSideMenu = (props: CustomSideMenuProps) => ( + ( + )} + currentDocumentId={props.currentDocumentId} + /> + )} + /> +); diff --git a/src/components/editor/menus/CustomSlashMenu.tsx b/src/components/editor/menus/CustomSlashMenu.tsx new file mode 100644 index 00000000..7450686d --- /dev/null +++ b/src/components/editor/menus/CustomSlashMenu.tsx @@ -0,0 +1,343 @@ +"use client"; + +import { useCallback, useMemo } from "react"; +import type { JSX } from "react"; +import { + SuggestionMenuController, + getDefaultReactSlashMenuItems, + type DefaultReactSuggestionItem, +} from "@blocknote/react"; +import { filterSuggestionItems, type BlockNoteEditor } from "@blocknote/core"; +import { useRouter } from "next/navigation"; +import { + FileImage, + FilePlus2, + FileVideo, + ListTree, + Music, + Paperclip, + PilcrowSquare, + Play, + Sparkles, + SquareCheckBig, +} from "lucide-react"; +import type { CustomBlockSchema } from "../schema"; +import { useImagePicker } from "@/components/media/image-picker-context"; +import type { MediaKind, MediaSelection } from "@/types/media"; + +type Props = { + editor: BlockNoteEditor; + currentDocumentId: string; +}; + +const matchKeywords = (query: string, aliases: string[]) => { + const lower = query.trim().toLowerCase(); + if (!lower) return true; + return aliases.some((alias) => alias.toLowerCase().includes(lower)); +}; + +const GROUP_TRANSLATIONS: Record = { + "Headings": "标题", + "Subheadings": "副标题", + "Basic blocks": "基础块", + "Advanced": "高级", + "Media": "媒体", + "Others": "其他", +}; + +const DEFAULT_ITEM_TRANSLATIONS: Record< + string, + { title?: string; subtext?: string; group?: string; aliases?: string[] } +> = { + "Paragraph": { title: "正文", group: "基础块", aliases: ["zw", "paragraph", "body"] }, + "Heading 1": { title: "主标题", group: "标题", aliases: ["biaoti", "bt1"] }, + "Heading 2": { title: "大标题", group: "标题", aliases: ["biaoti", "bt2"] }, + "Heading 3": { title: "中标题", group: "标题", aliases: ["biaoti", "bt3"] }, + "Heading 4": { title: "小标题", group: "标题", aliases: ["biaoti", "bt4"] }, + "Heading 5": { title: "极小标题", group: "标题", aliases: ["biaoti", "bt5"] }, + "Heading 6": { title: "最小标题", group: "标题", aliases: ["biaoti", "bt6"] }, + "Toggle Heading 1": { title: "可折叠主标题", group: "标题", aliases: ["toggle", "zd1"] }, + "Toggle Heading 2": { title: "可折叠大标题", group: "标题", aliases: ["toggle", "zd2"] }, + "Toggle Heading 3": { title: "可折叠中标题", group: "标题", aliases: ["toggle", "zd3"] }, + "Quote": { title: "引用", group: "基础块", aliases: ["quote", "引用"] }, + "Toggle List": { title: "折叠列表", group: "基础块", aliases: ["toggle list", "zd"] }, + "Numbered List": { title: "数字列表", group: "基础块", aliases: ["ordered", "ol"] }, + "Bullet List": { title: "符号列表", group: "基础块", aliases: ["ul", "list"] }, + "Check List": { title: "任务列表", group: "基础块", aliases: ["todo", "checkbox"] }, + "Code Block": { title: "代码块", group: "基础块", aliases: ["code", "pre"] }, + "Table": { title: "表格", group: "高级", aliases: ["table", "biaoge"] }, + "Image": { title: "插入图片", group: "媒体", subtext: "上传或引用图片资源", aliases: ["tupian", "image", "tp"] }, + "Video": { title: "插入视频", group: "媒体", subtext: "上传或引用视频", aliases: ["shipin", "video", "sp"] }, + "Audio": { title: "插入音频", group: "媒体", subtext: "上传或引用音频", aliases: ["yinpin", "audio", "yp"] }, + "File": { title: "插入文件", group: "媒体", subtext: "上传附件并生成卡片", aliases: ["wenjian", "file", "wj"] }, + "Emoji": { title: "插入表情", group: "其他", aliases: ["emoji", "biaoqing"] }, + "Divider": { title: "分割线", group: "基础块", aliases: ["divider", "hr"] }, + "Page Break": { title: "分页符", group: "基础块", aliases: ["page", "break"] }, +}; + +const MEDIA_ICONS: Record = { + image: , + video: , + audio: , + file: , +}; + +const HEADING_PRESETS = [ + { + level: 1, + title: "主标题", + subtext: "适合页面名称/顶层章节", + aliases: ["biaoti1", "h1", "level1"], + }, + { + level: 2, + title: "大标题", + subtext: "用于章节逻辑层", + aliases: ["biaoti2", "h2", "level2"], + }, + { + level: 3, + title: "中标题", + subtext: "用于小节和段落", + aliases: ["biaoti3", "h3", "level3"], + }, + { + level: 4, + title: "小标题", + subtext: "更细的结构说明", + aliases: ["biaoti4", "h4", "level4"], + }, + { + level: 5, + title: "极小标题", + subtext: "适合脚注/补充说明", + aliases: ["biaoti5", "h5", "level5"], + }, +]; + +const isHeadingDefaultItem = (item: DefaultReactSuggestionItem) => { + const maybeKey = (item as { key?: string }).key ?? ""; + if (maybeKey && (maybeKey === "heading" || maybeKey.startsWith("heading_") || maybeKey.startsWith("toggle_heading"))) { + return true; + } + const title = item.title ?? ""; + return title.includes("标题"); +}; + +export const CustomSlashMenu = ({ editor, currentDocumentId }: Props) => { + const defaultItems = useMemo(() => getDefaultReactSlashMenuItems(editor), [editor]); + const router = useRouter(); + const { openPicker } = useImagePicker(); + + const getItems = useCallback( + async (query: string) => { + const cursor = editor.getTextCursorPosition(); + const referenceBlock = cursor?.block ?? editor.topLevelBlocks[0]; + + const createPageItem: DefaultReactSuggestionItem = { + title: "嵌入页面", + group: "嵌入", + aliases: ["page", "ym", "子页面", "嵌入页面块"], + icon: , + onItemClick: async () => { + const response = await fetch("/api/documents/create-child", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + parentId: currentDocumentId, + title: cursor?.block?.content?.[0]?.text ?? "未命名页面", + blocks: cursor ? [cursor.block] : [], + }), + }); + + if (!response.ok) return; + const { pageId, title } = await response.json(); + editor.insertBlocks( + [ + { + type: "pageReference", + props: { pageId, title }, + }, + ], + referenceBlock, + "after", + ); + router.refresh(); + }, + }; + + const headingItems: DefaultReactSuggestionItem[] = HEADING_PRESETS.map((preset) => ({ + title: preset.title, + group: "标题", + subtext: preset.subtext, + aliases: preset.aliases, + icon: , + onItemClick: () => { + editor.insertBlocks( + [ + { + type: "heading", + props: { level: preset.level }, + }, + ], + referenceBlock, + "after", + ); + }, + })); + + const foldHeading: DefaultReactSuggestionItem = { + title: "折叠标题", + group: "标题", + aliases: ["toggle", "zd", "fold"], + icon: , + onItemClick: () => { + editor.insertBlocks( + [ + { + type: "heading", + props: { level: 2, isToggleable: true }, + }, + ], + referenceBlock, + "after", + ); + }, + }; + + const advancedTodo: DefaultReactSuggestionItem = { + title: "高级待办", + group: "待办", + subtext: "四态状态 · Alt 直接取消", + aliases: ["gjdblb", "todopro", "gaoji", "todo+"], + icon: , + onItemClick: () => { + editor.insertBlocks( + [ + { + type: "advancedTodo", + props: { status: "todo" }, + }, + ], + referenceBlock, + "after", + ); + }, + }; + + const progressMeter: DefaultReactSuggestionItem = { + title: "进度条", + group: "进度", + subtext: "自动读取下方待办完成度", + aliases: ["jdt", "progress", "jindu"], + icon: , + onItemClick: () => { + editor.insertBlocks( + [ + { + type: "progressMeter", + props: { percent: 0, auto: true }, + }, + ], + referenceBlock, + "after", + ); + }, + }; + + const foldAdvancedTodo: DefaultReactSuggestionItem = { + title: "折叠高级待办", + group: "待办", + aliases: ["zdgjdb", "foldtodo"], + icon: , + onItemClick: () => { + editor.insertBlocks( + [ + { + type: "advancedTodo", + props: { status: "todo" }, + }, + ], + referenceBlock, + "after", + ); + }, + }; + + const customItems = [ + ...headingItems, + foldHeading, + createPageItem, + advancedTodo, + foldAdvancedTodo, + progressMeter, + ].filter((item) => matchKeywords(query, item.aliases ?? [])); + + const insertMediaSelection = (selection: MediaSelection) => { + editor.insertBlocks( + [ + { + type: "media", + props: { + fileUrl: selection.fileUrl, + thumbnailUrl: selection.thumbnailUrl ?? selection.fileUrl, + assetId: selection.assetId, + assetType: selection.assetType ?? "image", + fileName: selection.fileName ?? "", + fileSize: selection.fileSize ?? null, + mimeType: selection.mimeType ?? "", + ocrStatus: "idle", + }, + }, + ], + referenceBlock, + "after", + ); + }; + + const handleMediaPick = (mediaType: MediaKind) => { + openPicker({ + mediaType, + onSelect: (selection) => { + insertMediaSelection({ + ...selection, + assetType: selection.assetType ?? mediaType, + }); + }, + }); + }; + + const localizedDefaults = defaultItems.map((item) => { + const translation = DEFAULT_ITEM_TRANSLATIONS[item.title]; + const next: DefaultReactSuggestionItem = { ...item }; + if (translation?.title) next.title = translation.title; + if (translation?.subtext) next.subtext = translation.subtext; + if (translation?.aliases) next.aliases = translation.aliases; + if (translation?.group) { + next.group = translation.group; + } else if (item.group && GROUP_TRANSLATIONS[item.group]) { + next.group = GROUP_TRANSLATIONS[item.group]; + } + + if (["Image", "Video", "Audio", "File"].includes(item.title)) { + const mediaType = item.title.toLowerCase() as MediaKind; + next.icon = MEDIA_ICONS[mediaType]; + next.group = translation?.group ?? "媒体"; + next.subtext = translation?.subtext ?? next.subtext; + next.aliases = translation?.aliases ?? next.aliases; + next.onItemClick = () => handleMediaPick(mediaType); + } + return next; + }); + + const sanitizedDefaults = localizedDefaults.filter( + (item) => !isHeadingDefaultItem(item) && item.title !== "表格", + ); + const merged = [...customItems, ...sanitizedDefaults]; + return filterSuggestionItems(merged, query); + }, + [currentDocumentId, defaultItems, editor, openPicker, router], + ); + + return ; +} diff --git a/src/components/editor/page-backlinks-panel.tsx b/src/components/editor/page-backlinks-panel.tsx new file mode 100644 index 00000000..3a5be0b8 --- /dev/null +++ b/src/components/editor/page-backlinks-panel.tsx @@ -0,0 +1,77 @@ +"use client"; + +import { useMemo } from "react"; +import { Button } from "@/components/ui/button"; +import { useBacklinks } from "@/hooks/use-backlinks"; +import type { BacklinkRecord } from "@/types/references"; +import { cn } from "@/lib/utils"; + +interface PageBacklinksPanelProps { + workspaceId: string; + documentId: string; + className?: string; +} + +const formatRelative = (value: string) => { + if (!value) return ""; + const date = new Date(value); + return date.toLocaleString(); +}; + +const EmptyState = () => ( +
+ 暂无反向引用。试试输入 [[#{" "} + 来引用其他页面。 +
+); + +const BacklinkItem = ({ record }: { record: BacklinkRecord }) => ( +
+
+ {record.alias || record.sourceTitle || "无标题"} + {record.displayMode === "embed" ? "嵌入块" : "行内引用"} +
+
+ 来自页面:{record.sourceTitle || "无标题"} · 更新:{formatRelative(record.updatedAt)} +
+
+); + +export function PageBacklinksPanel({ workspaceId, documentId, className }: PageBacklinksPanelProps) { + const { data, isLoading, error, refetch, isFetching } = useBacklinks({ + workspaceId, + documentId, + }); + + const records = useMemo(() => data ?? [], [data]); + if (!isLoading && !error && records.length === 0) { + return null; + } + + return ( +
+
+
+

反向引用

+

展示指向当前页面的所有页面或块引用

+
+ +
+ {isLoading ? ( +
加载引用中...
+ ) : error ? ( +
{(error as Error).message}
+ ) : records.length === 0 ? ( + + ) : ( +
+ {records.map((record) => ( + + ))} +
+ )} +
+ ); +} diff --git a/src/components/editor/page-options-sidebar.tsx b/src/components/editor/page-options-sidebar.tsx new file mode 100644 index 00000000..ff400f97 --- /dev/null +++ b/src/components/editor/page-options-sidebar.tsx @@ -0,0 +1,228 @@ +"use client"; + +import { useState, type ComponentType } from "react"; +import { BookOpenCheck, Focus, ListOrdered, ListTree, Maximize2, ShieldCheck, Type } from "lucide-react"; +import { cn } from "@/lib/utils"; +import type { DocumentStats, PageOptionsState } from "@/types/page-options"; +import { DocumentTaskPanel } from "@/components/document-task-panel"; +import { Button } from "@/components/ui/button"; + +type TabId = "page" | "custom" | "global"; + +const TABS: Array<{ id: TabId; label: string }> = [ + { id: "page", label: "页面选项" }, + { id: "custom", label: "自定义页面" }, + { id: "global", label: "全局选项" }, +]; + +const OPTION_META: Record< + keyof PageOptionsState, + { label: string; description: string; icon: ComponentType<{ className?: string }> } +> = { + wideLayout: { + label: "自适应宽度", + description: "让编辑区域根据屏幕自动铺满", + icon: Maximize2, + }, + smallText: { + label: "小字体", + description: "使用更紧凑的字号排版", + icon: Type, + }, + showHeadingNumbers: { + label: "标题编号", + description: "自动为标题添加编号", + icon: ListOrdered, + }, + showToc: { + label: "显示目录", + description: "在右侧展示目录导航", + icon: ListTree, + }, + showStructure: { + label: "块结构线框", + description: "显示块级元素的结构边界", + icon: Focus, + }, + protectEditing: { + label: "编辑保护", + description: "保护内容避免误触修改", + icon: ShieldCheck, + }, + showWordCount: { + label: "字数提示", + description: "实时展示字数和块统计", + icon: BookOpenCheck, + }, +}; + +const CUSTOM_LAYOUT_OPTIONS: (keyof PageOptionsState)[] = ["wideLayout", "smallText"]; +const CUSTOM_STRUCTURE_OPTIONS: (keyof PageOptionsState)[] = ["showHeadingNumbers", "showToc"]; +const GLOBAL_OPTIONS: (keyof PageOptionsState)[] = ["showStructure", "protectEditing", "showWordCount"]; + +interface PageOptionsSidebarProps { + documentId: string; + options: PageOptionsState; + stats?: DocumentStats; + onToggle: (key: keyof PageOptionsState) => void; + onExport: () => void; + onOpenHistory: () => void; +} + +export function PageOptionsSidebar({ + documentId, + options, + stats, + onToggle, + onExport, + onOpenHistory, +}: PageOptionsSidebarProps) { + const [activeTab, setActiveTab] = useState("page"); + + return ( + + ); +} + +function OptionToggleGroup({ + title, + optionKeys, + options, + onToggle, +}: { + title: string; + optionKeys: (keyof PageOptionsState)[]; + options: PageOptionsState; + onToggle: (key: keyof PageOptionsState) => void; +}) { + return ( +
+
{title}
+
+ {optionKeys.map((key) => ( + + ))} +
+
+ ); +} + +function OptionToggle({ + optionKey, + options, + onToggle, +}: { + optionKey: keyof PageOptionsState; + options: PageOptionsState; + onToggle: (key: keyof PageOptionsState) => void; +}) { + const meta = OPTION_META[optionKey]; + const Icon = meta.icon; + const active = options[optionKey]; + + return ( + + ); +} + +function StatsCell({ label, value }: { label: string; value: number }) { + return ( +
+
{label}
+
{value}
+
+ ); +} diff --git a/src/components/editor/schema.ts b/src/components/editor/schema.ts new file mode 100644 index 00000000..113ce72a --- /dev/null +++ b/src/components/editor/schema.ts @@ -0,0 +1,36 @@ +"use client"; + +import { + BlockNoteSchema, + createHeadingBlockSpec, + defaultBlockSpecs, + defaultInlineContentSpecs, + defaultStyleSpecs, +} from "@blocknote/core"; +import { pageReferenceBlock } from "./blocks/PageReferenceBlock"; +import { advancedTodoBlock } from "./blocks/AdvancedTodoBlock"; +import { progressBlock } from "./blocks/ProgressBlock"; +import { mediaBlock } from "./blocks/MediaBlock"; + +const headingSpec = + typeof window === "undefined" + ? defaultBlockSpecs.heading + : createHeadingBlockSpec({ + levels: [1, 2, 3, 4, 5], + allowToggleHeadings: true, + }); + +export const customBlockSchema = BlockNoteSchema.create({ + blockSpecs: { + ...defaultBlockSpecs, + heading: headingSpec, + pageReference: pageReferenceBlock, + advancedTodo: advancedTodoBlock, + progressMeter: progressBlock, + media: mediaBlock, + }, + inlineContentSpecs: defaultInlineContentSpecs, + styleSpecs: defaultStyleSpecs, +}); + +export type CustomBlockSchema = typeof customBlockSchema.blockSchema; diff --git a/src/components/media/image-picker-context.tsx b/src/components/media/image-picker-context.tsx new file mode 100644 index 00000000..f511d2d0 --- /dev/null +++ b/src/components/media/image-picker-context.tsx @@ -0,0 +1,78 @@ +"use client"; + +import { createContext, useContext, useMemo, useState, type ReactNode } from "react"; +import { ImagePickerDialog, type PickerTab } from "@/components/media/image-picker-dialog"; +import type { MediaKind, MediaSelection } from "@/types/media"; + +interface PickerState { + open: boolean; + defaultTab: PickerTab; + mediaType: MediaKind; + onSelect?: (selection: MediaSelection) => void; +} + +interface ImagePickerContextValue { + openPicker: (options: { onSelect: (selection: MediaSelection) => void; defaultTab?: PickerTab; mediaType?: MediaKind }) => void; +} + +const ImagePickerContext = createContext(undefined); + +interface ImagePickerProviderProps { + documentId: string; + workspaceId: string; + children: ReactNode; +} + +export function ImagePickerProvider({ documentId, workspaceId, children }: ImagePickerProviderProps) { + const [state, setState] = useState({ + open: false, + defaultTab: "upload", + mediaType: "image", + }); + + const contextValue = useMemo( + () => ({ + openPicker: ({ onSelect, defaultTab = "upload", mediaType = "image" }) => { + setState({ + open: true, + onSelect, + defaultTab, + mediaType, + }); + }, + }), + [], + ); + + const handleClose = () => { + setState((prev) => ({ ...prev, open: false })); + }; + + const handleSelect = (selection: MediaSelection) => { + state.onSelect?.(selection); + setState((prev) => ({ ...prev, open: false })); + }; + + return ( + + {children} + + + ); +} + +export function useImagePicker() { + const context = useContext(ImagePickerContext); + if (!context) { + throw new Error("useImagePicker 必须在 ImagePickerProvider 中使用"); + } + return context; +} diff --git a/src/components/media/image-picker-dialog.tsx b/src/components/media/image-picker-dialog.tsx new file mode 100644 index 00000000..6fff4888 --- /dev/null +++ b/src/components/media/image-picker-dialog.tsx @@ -0,0 +1,392 @@ +"use client"; + +import { useCallback, useEffect, useMemo, useState } from "react"; +import { useDropzone } from "react-dropzone"; +import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { cn } from "@/lib/utils"; +import type { MediaAsset, MediaKind, MediaSelection } from "@/types/media"; + +export type PickerTab = "upload" | "recent" | "link" | "icon"; + +interface ImagePickerDialogProps { + open: boolean; + defaultTab: PickerTab; + mediaType: MediaKind; + documentId: string; + workspaceId: string; + onClose: () => void; + onSelect: (selection: MediaSelection) => void; +} + +const ICON_PRESETS: Array<{ id: string; label: string; url: string }> = [ + { id: "progress", label: "进度波纹", url: "https://media.giphy.com/media/QBd2kLB5qDmysEXre9/giphy.gif" }, + { id: "heartbeat", label: "心跳", url: "https://media.giphy.com/media/HEPwfdu6T6svpPE1eN/giphy.gif" }, + { id: "sparkles", label: "闪光", url: "https://media.giphy.com/media/f9jQLaPmuFKfa7E55Q/giphy.gif" }, + { id: "loading", label: "加载", url: "https://media.giphy.com/media/52qtwCtj9OLTi/giphy.gif" }, +]; + +const MEDIA_TABS: Record = { + image: ["upload", "recent", "link", "icon"], + video: ["upload", "recent", "link"], + audio: ["upload", "recent", "link"], + file: ["upload", "recent", "link"], +}; + +const TAB_LABELS: Record = { + upload: "上传", + recent: "最近", + link: "链接", + icon: "动态图标", +}; + +const MEDIA_ACCEPTS: Record | null> = { + image: { "image/*": [] }, + video: { "video/*": [] }, + audio: { "audio/*": [] }, + file: null, +}; + +const MEDIA_TITLES: Record = { + image: "选择图片", + video: "选择视频", + audio: "选择音频", + file: "选择文件", +}; + +const formatBytes = (size?: number | null) => { + if (!size || size <= 0) { + return ""; + } + const units = ["B", "KB", "MB", "GB", "TB"]; + let value = size; + let index = 0; + while (value >= 1024 && index < units.length - 1) { + value /= 1024; + index += 1; + } + return `${value.toFixed(value >= 10 ? 0 : 1)} ${units[index]}`; +}; + +const guessFileNameFromUrl = (url: string) => { + try { + const parsed = new URL(url); + const name = parsed.pathname.split("/").filter(Boolean).pop(); + if (name) { + return decodeURIComponent(name); + } + } catch { + const segments = url.split("?")[0]?.split("/") ?? []; + const name = segments.pop(); + if (name) { + return decodeURIComponent(name); + } + } + return "未命名资源"; +}; + +export function ImagePickerDialog({ + open, + defaultTab, + mediaType, + documentId, + workspaceId, + onClose, + onSelect, +}: ImagePickerDialogProps) { + const [tab, setTab] = useState(defaultTab); + const availableTabs = MEDIA_TABS[mediaType]; + const [recent, setRecent] = useState([]); + const [recentLoading, setRecentLoading] = useState(false); + const [linkUrl, setLinkUrl] = useState(""); + const [uploading, setUploading] = useState(false); + const [error, setError] = useState(null); + + useEffect(() => { + if (open) { + const availableTabs = MEDIA_TABS[mediaType]; + const fallback = availableTabs.includes(defaultTab) ? defaultTab : availableTabs[0]; + setTab(fallback); + } + }, [defaultTab, mediaType, open]); + + const fetchRecent = useCallback(async () => { + if (!workspaceId) { + return; + } + setRecentLoading(true); + try { + const response = await fetch( + `/api/media/assets?workspaceId=${workspaceId}&assetType=${mediaType}`, + ); + if (!response.ok) { + throw new Error("无法获取最近上传"); + } + const payload = (await response.json()) as { items: MediaAsset[] }; + setRecent(payload.items ?? []); + } catch (err) { + console.error(err); + setRecent([]); + } finally { + setRecentLoading(false); + } + }, [workspaceId, mediaType]); + + useEffect(() => { + if (open && tab === "recent") { + void fetchRecent(); + } + }, [open, tab, fetchRecent]); + + const handleUpload = useCallback( + async (file: File) => { + if (!workspaceId || !documentId) { + setError("缺少必要参数"); + return; + } + setUploading(true); + setError(null); + try { + const form = new FormData(); + form.append("file", file); + form.append("workspaceId", workspaceId); + form.append("documentId", documentId); + const response = await fetch("/api/media/upload", { + method: "POST", + body: form, + }); + if (!response.ok) { + const payload = await response.json().catch(() => null); + throw new Error(payload?.error ?? "上传失败"); + } + const payload = (await response.json()) as { asset: MediaAsset }; + if (!payload.asset?.file_url) { + throw new Error("返回数据缺少文件地址"); + } + onSelect({ + assetId: payload.asset.id, + fileUrl: payload.asset.file_url, + thumbnailUrl: payload.asset.thumbnail_url, + assetType: payload.asset.asset_type, + fileName: payload.asset.file_name, + fileSize: payload.asset.file_size, + mimeType: payload.asset.mime_type, + }); + onClose(); + } catch (err) { + setError((err as Error).message); + } finally { + setUploading(false); + } + }, + [documentId, onClose, onSelect, workspaceId], + ); + + const onDrop = useCallback( + (acceptedFiles: File[]) => { + if (acceptedFiles.length === 0) return; + void handleUpload(acceptedFiles[0]); + }, + [handleUpload], + ); + + const acceptConfig = MEDIA_ACCEPTS[mediaType]; + + const { getRootProps, getInputProps, isDragActive } = useDropzone({ + onDrop, + accept: acceptConfig ?? undefined, + maxFiles: 1, + }); + + const handleLinkSubmit = async () => { + if (!linkUrl.trim()) return; + try { + const targetUrl = linkUrl.trim(); + const response = await fetch("/api/media/assets", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + workspaceId, + documentId, + fileUrl: targetUrl, + thumbnailUrl: targetUrl, + assetType: mediaType, + fileName: guessFileNameFromUrl(targetUrl), + }), + }); + if (!response.ok) { + const payload = await response.json().catch(() => null); + throw new Error(payload?.error ?? "保存失败"); + } + const payload = (await response.json()) as { asset: MediaAsset }; + if (!payload.asset?.file_url) { + throw new Error("缺少图片地址"); + } + onSelect({ + assetId: payload.asset.id, + fileUrl: payload.asset.file_url, + thumbnailUrl: payload.asset.thumbnail_url, + assetType: payload.asset.asset_type, + fileName: payload.asset.file_name, + fileSize: payload.asset.file_size, + mimeType: payload.asset.mime_type, + }); + setLinkUrl(""); + onClose(); + } catch (err) { + setError((err as Error).message); + } + }; + + const renderRecent = () => { + if (recentLoading) { + return
加载最近上传中...
; + } + if (recent.length === 0) { + return
暂无最近上传的{MEDIA_TITLES[mediaType].replace("选择", "")}
; + } + return ( +
+ {recent.map((asset) => ( + + ))} +
+ ); + }; + + const renderIcons = () => ( +
+ {ICON_PRESETS.map((icon) => ( + + ))} +
+ ); + + const helperText = useMemo(() => { + const label = MEDIA_TITLES[mediaType].replace("选择", ""); + switch (tab) { + case "upload": + return `支持拖拽或点击上传${label},单个文件不超过 200MB`; + case "recent": + return `最近 12 个${label},支持一键选取`; + case "link": + return `输入${label}直链或 CDN 地址`; + case "icon": + return "选择 Wolai 常用动态图标"; + default: + return ""; + } + }, [mediaType, tab]); + + return ( + !next && onClose()}> + + + {MEDIA_TITLES[mediaType]} + {helperText} + + {error &&
{error}
} + setTab(value as PickerTab)}> + + {availableTabs.map((tabKey) => ( + + {TAB_LABELS[tabKey]} + + ))} + + {availableTabs.includes("upload") && ( + +
+ + {uploading ? "上传中..." : "拖拽文件到此处,或点击选择文件"} +
+
+ )} + {availableTabs.includes("recent") && ( + +
+ 最近上传的{MEDIA_TITLES[mediaType].replace("选择", "")} + +
+ {renderRecent()} +
+ )} + {availableTabs.includes("link") && ( + +
+ setLinkUrl(event.target.value)} + placeholder={`输入${MEDIA_TITLES[mediaType].replace("选择", "")}链接,例如 https://example.com/file`} + /> + +
+
+ )} + {availableTabs.includes("icon") && {renderIcons()}} +
+
+
+ ); +} diff --git a/src/components/mindmap/.gitkeep b/src/components/mindmap/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/components/mobile-sidebar-trigger.tsx b/src/components/mobile-sidebar-trigger.tsx new file mode 100644 index 00000000..35e41663 --- /dev/null +++ b/src/components/mobile-sidebar-trigger.tsx @@ -0,0 +1,19 @@ +"use client"; + +import { Menu } from "lucide-react"; +import { useSidebarStore } from "@/store/sidebar"; + +export function MobileSidebarTrigger() { + const setOpen = useSidebarStore((state) => state.setOpen); + + return ( + + ); +} diff --git a/src/components/providers/query-provider.tsx b/src/components/providers/query-provider.tsx new file mode 100644 index 00000000..4f4fa61d --- /dev/null +++ b/src/components/providers/query-provider.tsx @@ -0,0 +1,31 @@ +"use client"; + +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; +import { useState, type ReactNode } from "react"; + +interface QueryProviderProps { + children: ReactNode; +} + +export function QueryProvider({ children }: QueryProviderProps) { + const [client] = useState( + () => + new QueryClient({ + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + refetchOnReconnect: true, + retry: 1, + }, + }, + }), + ); + + return ( + + {children} + + + ); +} diff --git a/src/components/providers/supabase-provider.tsx b/src/components/providers/supabase-provider.tsx new file mode 100644 index 00000000..9b2d1199 --- /dev/null +++ b/src/components/providers/supabase-provider.tsx @@ -0,0 +1,18 @@ +"use client"; + +import type { Session } from "@supabase/supabase-js"; +import { SessionContextProvider } from "@supabase/auth-helpers-react"; +import { supabaseBrowser } from "@/lib/supabase/client"; + +interface SupabaseProviderProps { + session: Session | null; + children: React.ReactNode; +} + +export function SupabaseProvider({ session, children }: SupabaseProviderProps) { + return ( + + {children} + + ); +} diff --git a/src/components/reference/page-hover-card.tsx b/src/components/reference/page-hover-card.tsx new file mode 100644 index 00000000..dc153985 --- /dev/null +++ b/src/components/reference/page-hover-card.tsx @@ -0,0 +1,39 @@ +import { Button } from "@/components/ui/button"; +import type { DocumentSearchResult } from "@/types/search"; + +interface PageHoverCardProps { + result: DocumentSearchResult; + onPreview?: () => void; +} + +const formatRelative = (value: string | null) => { + if (!value) return "未知时间"; + const date = new Date(value); + return date.toLocaleString(); +}; + +export function PageHoverCard({ result, onPreview }: PageHoverCardProps) { + return ( +
+
+

{result.title || "无标题"}

+

+ 最近更新:{formatRelative(result.updatedAt)} · 创建:{formatRelative(result.createdAt)} +

+
+
+ +
+ ); +} diff --git a/src/components/search/search-palette.tsx b/src/components/search/search-palette.tsx new file mode 100644 index 00000000..d45d74bc --- /dev/null +++ b/src/components/search/search-palette.tsx @@ -0,0 +1,654 @@ +"use client"; + +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import type { DragEvent as ReactDragEvent } from "react"; +import { useRouter, useSelectedLayoutSegments } from "next/navigation"; +import { CalendarClock, ChevronsUpDown, Copy, Layers, Search } from "lucide-react"; +import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { HoverCard, HoverCardContent, HoverCardTrigger } from "@/components/ui/hover-card"; +import { cn } from "@/lib/utils"; +import { useSearchPaletteStore, type ReferenceInsertMode, type SearchPaletteMode } from "@/store/search-palette"; +import type { DocumentSearchResult, DocumentSearchRequest, DocumentSearchTimeRange } from "@/types/search"; +import { useDocumentSearch } from "@/hooks/use-document-search"; +import { useReferenceComposer } from "@/hooks/use-reference-composer"; +import { recordRecentPage } from "@/lib/search/record-recent"; +import { PageHoverCard } from "@/components/reference/page-hover-card"; +import { buildSearchRequest } from "@/lib/search/request"; +import { resolveSearchOpenMode } from "@/lib/search/shortcuts"; + +interface SearchPaletteProps { + workspaceId: string | null; +} + +const TIME_RANGE_LABEL: Record = { + any: "全部时间", + "7d": "最近 7 天", + "30d": "最近 30 天", +}; + +const formatDate = (value: string | null) => { + if (!value) return "未知时间"; + const date = new Date(value); + return date.toLocaleString(); +}; + +export function SearchPalette({ workspaceId }: SearchPaletteProps) { + const router = useRouter(); + const segments = useSelectedLayoutSegments(); + const activeDocumentId = segments?.[1] ?? null; + const inputRef = useRef(null); + const { + open, + mode, + query, + filters, + timeRange, + referenceMode, + alias, + recent, + setRecent, + openSearch, + openReference, + close, + setQuery, + toggleFilter, + setTimeRange, + setTimeField, + setCustomRange, + setReferenceMode, + setAlias, + rememberResult, + } = useSearchPaletteStore(); + const [highlightedIndex, setHighlightedIndex] = useState(0); + const { insertReference } = useReferenceComposer({ + workspaceId, + sourcePageId: activeDocumentId ?? null, + }); + const [resultTab, setResultTab] = useState<"all" | "recent">(recent.length > 0 ? "recent" : "all"); + const [referenceFiltersOpen, setReferenceFiltersOpen] = useState(mode === "reference"); + const updateCustomRange = useCallback( + (patch: { from?: string; to?: string }) => { + const next = { ...(filters.customRange ?? {}), ...patch }; + if (!next.from && !next.to) { + setCustomRange(null); + } else { + setCustomRange(next); + } + }, + [filters.customRange, setCustomRange], + ); + const clearCustomRange = useCallback(() => setCustomRange(null), [setCustomRange]); + + const requestPayload = useMemo( + () => + buildSearchRequest({ + workspaceId, + activeDocumentId, + query, + filters, + timeRange, + }), + [workspaceId, activeDocumentId, query, filters, timeRange], + ); + + const searchQueryEnabled = Boolean(open && workspaceId); + const { data, isLoading, isFetching, error } = useDocumentSearch(requestPayload, searchQueryEnabled); + + useEffect(() => { + if (data?.recent) { + setRecent(data.recent); + } + }, [data?.recent, setRecent]); + /* eslint-disable react-hooks/set-state-in-effect */ + useEffect(() => { + if (mode === "reference") { + setReferenceFiltersOpen(true); + } else { + setReferenceFiltersOpen(false); + } + }, [mode]); + /* eslint-enable react-hooks/set-state-in-effect */ + const searchResults = data?.results; + const remoteResults = useMemo(() => searchResults ?? [], [searchResults]); + const showRecent = !query.trim() && recent.length > 0; + const enableRecentTab = showRecent; + const effectiveTab = enableRecentTab ? resultTab : "all"; + const activeResults = effectiveTab === "recent" ? recent : remoteResults; + + useEffect(() => { + if (!open) { + return undefined; + } + inputRef.current?.focus(); + const frame = requestAnimationFrame(() => setHighlightedIndex(0)); + return () => cancelAnimationFrame(frame); + }, [open]); + + useEffect(() => { + if (highlightedIndex >= activeResults.length) { + const frame = requestAnimationFrame(() => + setHighlightedIndex(activeResults.length > 0 ? activeResults.length - 1 : 0), + ); + return () => cancelAnimationFrame(frame); + } + return undefined; + }, [activeResults.length, highlightedIndex]); + + useEffect(() => { + const handleGlobalHotkey = (event: KeyboardEvent) => { + if ((event.metaKey || event.ctrlKey) && !event.shiftKey && event.key.toLowerCase() === "p") { + event.preventDefault(); + openSearch(); + } + if ((event.metaKey || event.ctrlKey) && event.shiftKey && event.key.toLowerCase() === "r") { + event.preventDefault(); + openReference(); + } + }; + window.addEventListener("keydown", handleGlobalHotkey); + return () => window.removeEventListener("keydown", handleGlobalHotkey); + }, [openSearch, openReference]); + + const handleOpenResult = useCallback( + (result: DocumentSearchResult, openMode: "main" | "new-window" | "sidebar") => { + if (openMode === "new-window") { + window.open(result.publicPath, "_blank", "noopener,noreferrer"); + } else if (openMode === "sidebar") { + window.open(`${result.publicPath}?preview=sidebar`, "_blank", "noopener,noreferrer"); + } else { + router.push(result.publicPath); + } + void recordRecentPage(workspaceId, result.id); + rememberResult(result); + close(); + }, + [router, workspaceId, rememberResult, close], + ); + + const handleInsertReference = useCallback( + (result: DocumentSearchResult, overrideMode?: ReferenceInsertMode) => { + const run = async () => { + try { + const effectiveMode = overrideMode ?? referenceMode; + await insertReference(result, { + mode: effectiveMode, + alias: effectiveMode === "inline" ? alias : undefined, + }); + rememberResult(result); + close(); + } catch (error) { + console.error(error); + } + }; + void run(); + }, + [alias, close, insertReference, referenceMode, rememberResult], + ); + + const handleCopyReference = useCallback((result: DocumentSearchResult) => { + if (typeof window === "undefined") { + return; + } + const payload = `((${result.id}))`; + if (navigator?.clipboard) { + navigator.clipboard + .writeText(payload) + .then(() => window.alert("块引用已复制")) + .catch(() => { + window.prompt("复制失败,请手动复制引用内容", payload); + }); + } else { + window.prompt("复制块引用", payload); + } + }, []); + + useEffect(() => { + if (!open) { + return; + } + const handleKey = (event: KeyboardEvent) => { + if (event.key === "ArrowDown") { + event.preventDefault(); + setHighlightedIndex((prev) => Math.min(activeResults.length - 1, prev + 1)); + } else if (event.key === "ArrowUp") { + event.preventDefault(); + setHighlightedIndex((prev) => Math.max(0, prev - 1)); + } else if (event.key === "Enter") { + event.preventDefault(); + if (activeResults.length === 0) { + return; + } + const result = activeResults[highlightedIndex] ?? activeResults[0]; + if (!result) return; + if (mode === "search") { + const openMode = resolveSearchOpenMode(event); + handleOpenResult(result, openMode); + } else { + handleInsertReference(result); + } + } else if (event.key === "Escape") { + event.preventDefault(); + close(); + } + }; + window.addEventListener("keydown", handleKey); + return () => window.removeEventListener("keydown", handleKey); + }, [open, activeResults, highlightedIndex, mode, handleOpenResult, handleInsertReference, close]); + + const pending = isLoading || isFetching; + const dialogTitle = mode === "search" ? "页面搜索面板" : "引用选择面板"; + + return ( + !next && close()}> + + {dialogTitle} +
+
+
+
+ + { + const nextValue = event.target.value; + if (nextValue.trim().length > 0 && resultTab !== "all") { + setResultTab("all"); + } + setQuery(nextValue); + }} + placeholder={mode === "search" ? "搜索页面标题、正文或 OCR 内容..." : "选择要引用的页面"} + className="h-11 w-full rounded-xl border border-[#e2e8f0] bg-white pl-9 text-sm" + /> +
+ + + + + + {(Object.keys(TIME_RANGE_LABEL) as DocumentSearchTimeRange[]).map((range) => ( + setTimeRange(range)} + className={cn(range === timeRange && "bg-[#eef2ff] text-[#2563eb]")} + > + {TIME_RANGE_LABEL[range]} + + ))} + + + + + + + + setTimeField("updated")} + className={cn(filters.timeField === "updated" && "bg-[#eef2ff] text-[#2563eb]")} + > + 按编辑时间 + + setTimeField("created")} + className={cn(filters.timeField === "created" && "bg-[#eef2ff] text-[#2563eb]")} + > + 按创建时间 + + + +
+
+ toggleFilter("titleOnly")} /> + toggleFilter("exact")} /> + toggleFilter("onlyCurrentPage")} + /> + toggleFilter("includeOcr")} + /> + {mode === "reference" && ( + + )} +
+ {mode === "reference" && referenceFiltersOpen && ( +
+ setReferenceMode("inline")} + /> + setReferenceMode("embed")} + /> + {referenceMode === "inline" && ( + setAlias(event.target.value)} + placeholder="引用别名" + className="h-8 w-40 text-xs" + /> + )} + 引用模式将同步到 [[ / # 快捷键 +
+ )} +
+ 自定义时间 + updateCustomRange({ from: event.target.value || undefined })} + className="h-8 w-36 text-xs" + /> + updateCustomRange({ to: event.target.value || undefined })} + className="h-8 w-36 text-xs" + /> + +
+
+
+ {enableRecentTab && ( +
+ setResultTab("recent")} + disabled={!enableRecentTab} + /> + setResultTab("all")} /> +
+ )} + {pending ? ( +
+ 检索中,请稍候... +
+ ) : error ? ( +
+ {(error as Error).message} +
+ ) : activeResults.length === 0 ? ( +
+ {effectiveTab === "recent" ? "暂无最近访问记录" : "暂无匹配结果"} +
+ ) : ( +
+ {activeResults.map((result, index) => ( + handleOpenResult(result, "main")} + onReference={() => handleInsertReference(result)} + onEmbed={() => handleInsertReference(result, "embed")} + onCopy={() => handleCopyReference(result)} + /> + ))} +
+ )} +
+
+ {mode === "search" ? ( +
+ Enter 打开 · Ctrl/Cmd+Enter 新窗口 · Alt+Enter 右侧预览 + Esc 关闭 +
+ ) : ( +
+ + {referenceMode === "inline" ? "插入行内引用(链接高亮)" : "插入一个嵌入的页面块"},可先输入别名 + + Esc 关闭 +
+ )} +
+
+
+
+ ); +} + +function ResultRow({ + result, + highlighted, + mode, + onOpen, + onReference, + onEmbed, + onCopy, +}: { + result: DocumentSearchResult; + highlighted: boolean; + mode: SearchPaletteMode; + onOpen: () => void; + onReference: () => void; + onEmbed: () => void; + onCopy: () => void; +}) { + const handleActivate = () => { + if (mode === "search") { + onOpen(); + } else { + onReference(); + } + }; + + const handleDragStart = (event: ReactDragEvent) => { + if (mode !== "reference") return; + if (event.dataTransfer) { + event.dataTransfer.setData("text/plain", `((${result.id}))`); + event.dataTransfer.effectAllowed = "copy"; + } + }; + + const content = ( +
{ + if (event.key === "Enter") { + event.preventDefault(); + handleActivate(); + } + }} + className={cn( + "cursor-pointer px-4 py-3 transition-colors hover:bg-[#eef2ff]", + highlighted && "bg-[#e3ecff]", + )} + draggable={mode === "reference"} + onDragStart={handleDragStart} + > +
+ {result.title || "无标题"} + {result.matchField !== "recent" && ( + + {result.matchField === "title" ? "标题匹配" : "正文匹配"} + + )} + {result.hasOcr && ( + + OCR + + )} +
+
+
+ 最近编辑:{formatDate(result.updatedAt)} · 创建时间:{formatDate(result.createdAt)} +
+ {mode === "reference" && ( +
+ + + + 也可直接拖拽引用到编辑器 +
+ )} +
+ ); + + return ( + + {content} + + + + + ); +} + +interface FilterToggleProps { + label: string; + active: boolean; + onClick: () => void; + disabled?: boolean; +} + +function FilterToggle({ label, active, onClick, disabled }: FilterToggleProps) { + return ( + + ); +} + +interface TabButtonProps { + label: string; + active: boolean; + onClick: () => void; + disabled?: boolean; +} + +function TabButton({ label, active, onClick, disabled }: TabButtonProps) { + return ( + + ); +} + +interface ReferenceModeToggleProps { + label: string; + active: boolean; + onClick: () => void; +} + +function ReferenceModeToggle({ label, active, onClick }: ReferenceModeToggleProps) { + return ( + + ); +} diff --git a/src/components/sidebar/.gitkeep b/src/components/sidebar/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/components/sidebar/private-tree.tsx b/src/components/sidebar/private-tree.tsx new file mode 100644 index 00000000..cedd615b --- /dev/null +++ b/src/components/sidebar/private-tree.tsx @@ -0,0 +1,257 @@ +"use client"; + +import Link from "next/link"; +import { useCallback, useMemo, useRef, useState } from "react"; +import { + DndContext, + PointerSensor, + closestCenter, + useSensor, + useSensors, + type DragEndEvent, + type DragStartEvent, +} from "@dnd-kit/core"; +import { SortableContext, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable"; +import { CSS } from "@dnd-kit/utilities"; +import { useVirtualizer, type VirtualItem } from "@tanstack/react-virtual"; +import { ChevronRight, GripVertical, MoreHorizontal, Plus } from "lucide-react"; +import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"; +import type { DocumentNode } from "@/lib/documents"; +import { cn } from "@/lib/utils"; +import { flattenDocumentTree } from "@/lib/sidebar-tree"; + +interface PrivateTreeProps { + nodes: DocumentNode[]; + expanded: Set; + activeId: string; + onToggleExpand: (id: string) => void; + onMove: (nodeId: string, parentId: string | null, index: number) => void; + onCreateChild: (parentId: string | null) => void; + onContextMenu: (event: React.MouseEvent, node: DocumentNode) => void; +} + +const ROW_HEIGHT = 36; + +export function PrivateTree({ + nodes, + expanded, + activeId, + onToggleExpand, + onMove, + onCreateChild, + onContextMenu, +}: PrivateTreeProps) { + const scrollAreaRef = useRef(null); + const [activeDragId, setActiveDragId] = useState(null); + + const flatNodes = useMemo(() => flattenDocumentTree(nodes, expanded), [nodes, expanded]); + + const sensors = useSensors( + useSensor(PointerSensor, { + activationConstraint: { distance: 5 }, + }), + ); + + // eslint-disable-next-line react-hooks/incompatible-library + const virtualizer = useVirtualizer({ + count: flatNodes.length, + getScrollElement: () => scrollAreaRef.current, + estimateSize: () => ROW_HEIGHT, + overscan: 10, + }); + + const handleDragStart = useCallback((event: DragStartEvent) => { + setActiveDragId(event.active.id as string); + }, []); + + const handleDragEnd = useCallback( + (event: DragEndEvent) => { + const activeId = event.active.id as string; + const overId = event.over?.id as string | undefined; + setActiveDragId(null); + if (!overId || activeId === overId) { + return; + } + const activeIndex = flatNodes.findIndex((item) => item.node.id === activeId); + const overIndex = flatNodes.findIndex((item) => item.node.id === overId); + if (activeIndex === -1 || overIndex === -1) { + return; + } + const targetParent = flatNodes[overIndex].parentId; + const siblingList = flatNodes.filter((item) => item.parentId === targetParent); + const siblingIndex = siblingList.findIndex((item) => item.node.id === overId); + const position = siblingIndex === -1 ? siblingList.length : siblingIndex; + onMove(activeId, targetParent, position); + }, + [flatNodes, onMove], + ); + + const handleDragCancel = useCallback(() => { + setActiveDragId(null); + }, []); + + if (flatNodes.length === 0) { + return
暂无页面,点击下方按钮创建
; + } + + return ( + + + + item.node.id)} strategy={verticalListSortingStrategy}> +
+
+ {virtualizer.getVirtualItems().map((virtualRow) => { + const item = flatNodes[virtualRow.index]; + return ( + + 0} + activeId={activeId} + isDragging={activeDragId === item.node.id} + onToggleExpand={() => onToggleExpand(item.node.id)} + onCreateChild={() => onCreateChild(item.node.id)} + onContextMenu={(event) => onContextMenu(event, item.node)} + /> + + ); + })} +
+
+
+
+
+ + + + +
+ ); +} + +function VirtualRow({ + children, + virtualRow, +}: { + children: React.ReactNode; + virtualRow: VirtualItem; +}) { + return ( +
+ {children} +
+ ); +} + +interface SortableTreeRowProps { + node: DocumentNode; + depth: number; + expanded: boolean; + hasChildren: boolean; + activeId: string; + isDragging: boolean; + onToggleExpand: () => void; + onCreateChild: () => void; + onContextMenu: (event: React.MouseEvent) => void; +} + +function SortableTreeRow({ + node, + depth, + expanded, + hasChildren, + activeId, + isDragging, + onToggleExpand, + onCreateChild, + onContextMenu, +}: SortableTreeRowProps) { + const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ + id: node.id, + }); + + const style = { + transform: CSS.Translate.toString(transform), + transition, + }; + + return ( +
+ +
+ {hasChildren ? ( + + ) : ( + + )} + + {node.title || "无标题"} + +
+ + +
+ ); +} diff --git a/src/components/sidebar/sidebar.tsx b/src/components/sidebar/sidebar.tsx new file mode 100644 index 00000000..eb8b42fb --- /dev/null +++ b/src/components/sidebar/sidebar.tsx @@ -0,0 +1,1077 @@ +"use client"; + +import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; +import Link from "next/link"; +import { useRouter, useSelectedLayoutSegments } from "next/navigation"; +import { + ArrowRightLeft, + ArrowUpRight, + Bell, + ChevronRight, + Copy, + Dice5, + Edit3, + GitMerge, + Globe, + Hash, + LayoutGrid, + Library, + Link as LinkIcon, + MoreHorizontal, + PanelRightOpen, + PenSquare, + Plus, + Search as SearchIcon, + Share2, + Shield, + Star, + Trash2, + Upload, + Users, +} from "lucide-react"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { Drawer, DrawerContent, DrawerHeader, DrawerTitle } from "@/components/ui/drawer"; +import { cn } from "@/lib/utils"; +import type { DocumentNode } from "@/lib/documents"; +import { buildDocumentTree } from "@/lib/documents"; +import { useSidebarStore } from "@/store/sidebar"; +import type { SidebarInitialData, SidebarSectionId } from "@/components/sidebar/types"; +import { useSidebarData } from "@/hooks/use-sidebar-data"; +import { PrivateTree } from "@/components/sidebar/private-tree"; +import { buildSidebarSectionsFromTree, flattenDocumentTree } from "@/lib/sidebar-tree"; +import { supabaseBrowser } from "@/lib/supabase/client"; +import { useSearchPaletteStore } from "@/store/search-palette"; + +const TOP_BUTTONS = [ + { id: "search", icon: SearchIcon, label: "搜索" }, + { id: "graph", icon: Share2, label: "关系图" }, + { id: "import", icon: Upload, label: "导入" }, + { id: "members", icon: Users, label: "成员" }, + { id: "inbox", icon: Bell, label: "消息箱" }, + { id: "quick-note", icon: PenSquare, label: "今日速记" }, + { id: "lucky", icon: Dice5, label: "手气不错" }, + { id: "more", icon: MoreHorizontal, label: "更多" }, +] as const; + +const SECTION_ICONS: Record, React.ReactNode> = { + starred: , + public: , + shared: , + templates: , +}; + +interface SidebarProps { + initialData: SidebarInitialData; +} + +interface ContextMenuState { + node: DocumentNode; + x: number; + y: number; +} + +export function Sidebar({ initialData }: SidebarProps) { + const { open, setOpen, width, setWidth, collapsedSections, toggleSection, trashConfirm, setTrashConfirm } = + useSidebarStore(); + const openSearchPalette = useSearchPaletteStore((state) => state.openSearch); + const sidebarQuery = useSidebarData(initialData); + const sidebarData = sidebarQuery.data ?? initialData; + const segments = useSelectedLayoutSegments(); + const router = useRouter(); + const activeId = segments?.[1] ?? ""; + + const [tree, setTree] = useState(() => buildDocumentTree(sidebarData.documents)); + const [filter, setFilter] = useState(""); + const [expanded, setExpanded] = useState>(() => collectNodeIds(tree)); + const [contextMenu, setContextMenu] = useState(null); + const [workspaceMenuOpen, setWorkspaceMenuOpen] = useState(false); + const [trashOpen, setTrashOpen] = useState(false); + const [trashSearch, setTrashSearch] = useState(""); + const [emptyingTrash, setEmptyingTrash] = useState(false); + + const workspaceMenuRef = useRef(null); + + useEffect(() => { + setTree(() => { + const nextTree = buildDocumentTree(sidebarData.documents); + setExpanded((expandedPrev) => collectNodeIds(nextTree, new Set(expandedPrev))); + return nextTree; + }); + }, [sidebarData.documents]); + + useEffect(() => { + setOpen(false); + }, [activeId, setOpen]); + + const refreshTree = useCallback(async () => { + await sidebarQuery.refetch(); + }, [sidebarQuery]); + + useEffect(() => { + const channel = supabaseBrowser + .channel("documents-feed") + .on( + "postgres_changes", + { event: "*", schema: "public", table: "documents" }, + () => { + void refreshTree(); + }, + ) + .subscribe(); + return () => { + supabaseBrowser.removeChannel(channel); + }; + }, [refreshTree]); + + const sections = useMemo(() => buildSidebarSectionsFromTree(tree), [tree]); + const starredNodes = useMemo(() => sections.find((section) => section.id === "starred")?.nodes ?? [], [sections]); + const publicNodes = useMemo(() => sections.find((section) => section.id === "public")?.nodes ?? [], [sections]); + const sharedNodes = useMemo(() => sections.find((section) => section.id === "shared")?.nodes ?? [], [sections]); + const templateNodes = useMemo(() => sections.find((section) => section.id === "templates")?.nodes ?? [], [sections]); + const privateTree = useMemo(() => sections.find((section) => section.id === "private")?.nodes ?? [], [sections]); + const filteredPrivateTree = useMemo( + () => (filter ? filterTree(privateTree, filter.toLowerCase()) : privateTree), + [filter, privateTree], + ); + const flattenedPrivate = useMemo( + () => flattenDocumentTree(privateTree, expanded), + [privateTree, expanded], + ); + const filteredTrash = useMemo(() => { + const keyword = trashSearch.trim().toLowerCase(); + if (!keyword) { + return sidebarData.trashedDocuments; + } + return sidebarData.trashedDocuments.filter((item) => + (item.title ?? "无标题").toLowerCase().includes(keyword), + ); + }, [sidebarData.trashedDocuments, trashSearch]); + + const activeWorkspace = + sidebarData.workspaces.find((workspace) => workspace.id === sidebarData.activeWorkspaceId) ?? + sidebarData.workspaces[0]; + + const handleOpenDocument = useCallback( + (documentId: string, mode: "main" | "sidebar") => { + const targetPath = `/documents/${documentId}`; + if (mode === "main") { + router.push(targetPath); + setOpen(false); + return; + } + if (typeof window !== "undefined") { + const sidebarUrl = `${buildDocumentUrl(documentId)}?preview=sidebar`; + window.open(sidebarUrl, "_blank", "noopener,noreferrer"); + } + }, + [router, setOpen], + ); + + const handleCopyLink = useCallback(async (node: DocumentNode, includeTitle = false) => { + const url = buildDocumentUrl(node.id); + const payload = includeTitle ? `${node.title ?? "无标题"}\n${url}` : url; + await copyText(payload, includeTitle ? "标题 + 链接已复制" : "页面链接已复制"); + }, []); + + const handleCopyReference = useCallback(async (node: DocumentNode, mode: "inline" | "embed") => { + const template = mode === "inline" ? `((${node.id}))` : `{{${node.id}}}`; + await copyText(template, mode === "inline" ? "行内引用已复制" : "嵌入引用已复制"); + }, []); + + const handleCopyId = useCallback(async (node: DocumentNode) => { + await copyText(node.id, "页面 ID 已复制"); + }, []); + + const handleDuplicateDocument = useCallback( + async (node: DocumentNode) => { + const response = await fetch("/api/documents/duplicate", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ documentId: node.id }), + }); + if (!response.ok) { + window.alert("复制失败,请稍后再试"); + return; + } + await refreshTree(); + }, + [refreshTree], + ); + + const handleEmbedPrompt = useCallback(async (node: DocumentNode) => { + if (typeof window === "undefined") { + return; + } + const target = window.prompt("输入希望嵌入到的页面 ID"); + if (!target) { + return; + } + const response = await fetch("/api/documents/embed", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ sourceId: node.id, targetId: target.trim() }), + }); + if (!response.ok) { + window.alert("嵌入失败,请检查目标页面 ID"); + return; + } + window.alert("已在目标页面末尾插入引用块"); + }, []); + + const toggleExpand = useCallback((id: string) => { + setExpanded((prev) => { + const next = new Set(prev); + if (next.has(id)) { + next.delete(id); + } else { + next.add(id); + } + return next; + }); + }, []); + + const handleResizeStart = useCallback( + (event: React.MouseEvent) => { + event.preventDefault(); + const startX = event.clientX; + const startWidth = width; + const onMove = (moveEvent: MouseEvent) => { + const delta = moveEvent.clientX - startX; + const targetWidth = Math.min(420, Math.max(240, startWidth + delta)); + setWidth(targetWidth); + }; + const onUp = () => { + document.removeEventListener("mousemove", onMove); + document.removeEventListener("mouseup", onUp); + }; + document.addEventListener("mousemove", onMove); + document.addEventListener("mouseup", onUp); + }, + [setWidth, width], + ); + + const handleCreate = useCallback( + async (parentId: string | null) => { + const response = await fetch("/api/documents/create", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ parentId }), + }); + + if (!response.ok) { + const payload = await response.json().catch(() => ({})); + window.alert(payload?.error ?? "新建页面失败,请稍后再试"); + return; + } + + const payload = (await response.json()) as DocumentNode; + const nextNode: DocumentNode = { + ...payload, + access_scope: payload.access_scope ?? "private", + is_template: payload.is_template ?? false, + updated_at: payload.updated_at ?? payload.created_at, + title: payload.title ?? "无标题", + children: [], + }; + + setTree((prev) => insertNode(prev, parentId, Number.MAX_SAFE_INTEGER, nextNode)); + setExpanded((prev) => { + const next = new Set(prev); + if (parentId) { + next.add(parentId); + } + if (!parentId) { + next.add(nextNode.id); + } + return next; + }); + + await refreshTree(); + router.push(`/documents/${nextNode.id}`); + }, + [refreshTree, router], + ); + + const handleRename = useCallback( + async (documentId: string, currentTitle: string | null) => { + const title = window.prompt("输入新的标题", currentTitle ?? "无标题") ?? ""; + if (!title.trim()) { + return; + } + await fetch("/api/documents/title", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ documentId, title: title.trim() }), + }); + await refreshTree(); + }, + [refreshTree], + ); + + const moveLocalNode = useCallback((currentTree: DocumentNode[], nodeId: string, parentId: string | null, index: number) => { + const cloned = cloneNodes(currentTree); + const { removed, tree: withoutTarget } = removeNode(cloned, nodeId); + if (!removed) { + return currentTree; + } + const next = insertNode(withoutTarget, parentId, index, removed); + return next; + }, []); + + const handleMove = useCallback( + async (documentId: string, parentId: string | null, index: number) => { + setTree((prev) => moveLocalNode(prev, documentId, parentId, index)); + if (parentId) { + setExpanded((prev) => new Set(prev).add(parentId)); + } + await fetch("/api/documents/move", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + documentId, + parentId, + position: index, + }), + }); + await refreshTree(); + }, + [moveLocalNode, refreshTree, setExpanded], + ); + + const handleMovePrompt = useCallback( + async (node: DocumentNode) => { + if (typeof window === "undefined") { + return; + } + const target = window.prompt("输入目标父页面 ID(留空表示移动到根目录)", node.parent_id ?? ""); + if (target === null) { + return; + } + const trimmed = target.trim(); + await handleMove(node.id, trimmed.length > 0 ? trimmed : null, 0); + }, + [handleMove], + ); + + const handleDelete = useCallback( + async (documentId: string) => { + await fetch("/api/documents/delete", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ documentId }), + }); + await refreshTree(); + }, + [refreshTree], + ); + + const handleConvertToChild = useCallback( + async (documentId: string) => { + const flat = flattenedPrivate; + const currentIndex = flat.findIndex((item) => item.node.id === documentId); + if (currentIndex <= 0) { + return; + } + const targetParentId = flat[currentIndex - 1].node.id; + await handleMove(documentId, targetParentId, flat[currentIndex - 1].node.children.length); + }, + [flattenedPrivate, handleMove], + ); + + const confirmTrashAction = useCallback( + (message: string) => { + if (!trashConfirm) { + return true; + } + return window.confirm(message); + }, + [trashConfirm], + ); + + const handleRestoreFromTrash = useCallback( + async (documentId: string) => { + if (!confirmTrashAction("确认恢复该页面吗?")) { + return; + } + await fetch("/api/documents/restore", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ documentId }), + }); + await Promise.all([sidebarQuery.refetch(), refreshTree()]); + }, + [confirmTrashAction, refreshTree, sidebarQuery], + ); + + const handlePurgeFromTrash = useCallback( + async (documentId: string) => { + if (!confirmTrashAction("彻底删除后将无法找回,是否继续?")) { + return; + } + await fetch("/api/documents/purge", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ documentId }), + }); + await Promise.all([sidebarQuery.refetch(), refreshTree()]); + }, + [confirmTrashAction, refreshTree, sidebarQuery], + ); + + const handleEmptyTrash = useCallback(async () => { + if (!sidebarData.activeWorkspaceId) { + window.alert("暂无可清空的工作空间"); + return; + } + if (!confirmTrashAction("清空垃圾桶后将无法恢复,是否继续?")) { + return; + } + setEmptyingTrash(true); + try { + const response = await fetch("/api/documents/empty-trash", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ workspaceId: sidebarData.activeWorkspaceId }), + }); + if (!response.ok) { + const payload = await response.json().catch(() => ({})); + window.alert(payload?.error ?? "清空垃圾桶失败,请稍后再试"); + return; + } + await Promise.all([sidebarQuery.refetch(), refreshTree()]); + } finally { + setEmptyingTrash(false); + } + }, [confirmTrashAction, refreshTree, sidebarData.activeWorkspaceId, sidebarQuery]); + + const handleWorkspaceSwitch = useCallback( + async (workspaceId: string) => { + if (workspaceId === sidebarData.activeWorkspaceId) { + setWorkspaceMenuOpen(false); + return; + } + await fetch("/api/workspaces/switch", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ workspaceId }), + }); + setWorkspaceMenuOpen(false); + await sidebarQuery.refetch(); + }, + [sidebarData.activeWorkspaceId, sidebarQuery], + ); + + const openContextMenu = useCallback((event: React.MouseEvent, node: DocumentNode) => { + event.preventDefault(); + event.stopPropagation(); + setContextMenu({ + node, + x: event.clientX, + y: event.clientY, + }); + }, []); + + const handleTopButtonClick = useCallback( + (buttonId: (typeof TOP_BUTTONS)[number]["id"]) => { + if (buttonId === "search") { + openSearchPalette(); + return; + } + window.alert("该功能即将上线,敬请期待"); + }, + [openSearchPalette], + ); + + useEffect(() => { + if (!contextMenu) { + return; + } + const closeMenu = () => setContextMenu(null); + window.addEventListener("click", closeMenu); + return () => window.removeEventListener("click", closeMenu); + }, [contextMenu]); + + useEffect(() => { + if (!workspaceMenuOpen) { + return; + } + const handleClickOutside = (event: MouseEvent) => { + if ( + workspaceMenuRef.current && + !workspaceMenuRef.current.contains(event.target as Node) + ) { + setWorkspaceMenuOpen(false); + } + }; + window.addEventListener("click", handleClickOutside); + return () => window.removeEventListener("click", handleClickOutside); + }, [workspaceMenuOpen]); + + const sidebarBody = ( +
+
+
当前工作空间
+
+
+
{activeWorkspace?.name ?? "我的空间"}
+
{activeWorkspace?.type === "team" ? "团队空间" : "个人空间"}
+
+
+ + {workspaceMenuOpen && ( +
+ {sidebarData.workspaces.map((workspace) => ( + + ))} +
+ )} +
+
+
+ +
+ {TOP_BUTTONS.map((button) => ( + + ))} +
+ +
+
+
+
+ + 页面树 +
+ setFilter(event.target.value)} + /> +
+ + toggleSection("starred")} + /> + toggleSection("public")} + /> + toggleSection("shared")} + /> + toggleSection("templates")} + /> + +
+ + {!collapsedSections.private ? ( +
+
+ +
+
+ ) : ( +
已折叠
+ )} +
+ +
+ + +
+
+
+
+ ); + + return ( + <> + + + + + 页面目录 + +
{sidebarBody}
+
+
+ {contextMenu && ( + setContextMenu(null)} + onOpenRight={(node) => handleOpenDocument(node.id, "sidebar")} + onMove={handleMovePrompt} + onEmbed={handleEmbedPrompt} + onCopyLink={handleCopyLink} + onCopyReference={handleCopyReference} + onCopyId={handleCopyId} + onDuplicate={handleDuplicateDocument} + onRename={() => void handleRename(contextMenu.node.id, contextMenu.node.title)} + onCreateChild={() => void handleCreate(contextMenu.node.id)} + onConvertChild={() => void handleConvertToChild(contextMenu.node.id)} + onDelete={() => void handleDelete(contextMenu.node.id)} + /> + )} + + + + 垃圾桶 +

180 天内的记录都可以在这里恢复。

+
+
+ setTrashSearch(event.target.value)} + /> +
+ + +
+
+ {filteredTrash.length === 0 ? ( +
暂无已删除页面
+ ) : ( + filteredTrash.map((item) => ( +
+
+
{item.title || "无标题"}
+
+ 删除时间:{new Date(item.deleted_at).toLocaleString()} +
+
+
+ + +
+
+ )) + )} +
+
+
+
+ + ); +} + +interface SectionListProps { + label: string; + icon: React.ReactNode; + nodes: DocumentNode[]; + collapsed: boolean; + onToggle: () => void; +} + +function SectionList({ label, icon, nodes, collapsed, onToggle }: SectionListProps) { + return ( +
+ + {!collapsed && ( +
+ {nodes.length === 0 ? ( +
暂无内容
+ ) : ( + nodes.map((node) => ( + + {node.title || "无标题"} + + )) + )} +
+ )} +
+ ); +} + +interface ContextMenuProps { + contextMenu: ContextMenuState; + onClose: () => void; + onOpenRight: (node: DocumentNode) => void; + onMove: (node: DocumentNode) => void; + onEmbed: (node: DocumentNode) => void; + onCopyLink: (node: DocumentNode, withTitle?: boolean) => void; + onCopyReference: (node: DocumentNode, mode: "inline" | "embed") => void; + onCopyId: (node: DocumentNode) => void; + onDuplicate: (node: DocumentNode) => void; + onRename: () => void; + onCreateChild: () => void; + onConvertChild: () => void; + onDelete: () => void; +} + +function ContextMenu({ + contextMenu, + onClose, + onOpenRight, + onMove, + onEmbed, + onCopyLink, + onCopyReference, + onCopyId, + onDuplicate, + onRename, + onCreateChild, + onConvertChild, + onDelete, +}: ContextMenuProps) { + const { node } = contextMenu; + const menuRef = useRef(null); + const [position, setPosition] = useState({ top: contextMenu.y, left: contextMenu.x }); + + useLayoutEffect(() => { + const clampPosition = () => { + const element = menuRef.current; + if (!element) { + setPosition({ top: contextMenu.y, left: contextMenu.x }); + return; + } + const rect = element.getBoundingClientRect(); + const padding = 12; + const maxLeft = Math.max(padding, window.innerWidth - rect.width - padding); + const maxTop = Math.max(padding, window.innerHeight - rect.height - padding); + const left = Math.min(Math.max(padding, contextMenu.x), maxLeft); + const top = Math.min(Math.max(padding, contextMenu.y), maxTop); + setPosition({ top, left }); + }; + clampPosition(); + window.addEventListener("resize", clampPosition); + return () => window.removeEventListener("resize", clampPosition); + }, [contextMenu]); + + const handleAction = (action: () => void) => { + action(); + onClose(); + }; + + const buttonClass = + "flex w-full items-center gap-2 rounded-sm px-3 py-2 text-left text-sm text-gray-700 hover:bg-[#f5f7fb]"; + + return ( +
+ + + +
+ + +
+
+ +
+ + +
+
+ + +
+ + + + +
+ ); +} + +const cloneNodes = (nodes: DocumentNode[]): DocumentNode[] => + nodes.map((node) => ({ + ...node, + children: cloneNodes(node.children), + })); + +const removeNode = ( + nodes: DocumentNode[], + targetId: string, +): { removed: DocumentNode | null; tree: DocumentNode[] } => { + let removed: DocumentNode | null = null; + const nextTree = nodes + .map((node) => { + if (removed) return node; + if (node.id === targetId) { + removed = node; + return null; + } + const { removed: childRemoved, tree: childTree } = removeNode(node.children, targetId); + if (childRemoved) { + removed = childRemoved; + return { ...node, children: childTree }; + } + return node; + }) + .filter(Boolean) as DocumentNode[]; + return { removed, tree: nextTree }; +}; + +const insertNode = (nodes: DocumentNode[], parentId: string | null, index: number, newNode: DocumentNode): DocumentNode[] => { + if (!parentId) { + const next = [...nodes]; + next.splice(Math.min(index, next.length), 0, newNode); + return next; + } + return nodes.map((node) => { + if (node.id === parentId) { + const children = [...node.children]; + const targetIndex = Math.min(index, children.length); + children.splice(targetIndex, 0, newNode); + return { ...node, children }; + } + return { ...node, children: insertNode(node.children, parentId, index, newNode) }; + }); +}; + +const filterTree = (nodes: DocumentNode[], keyword: string): DocumentNode[] => { + if (!keyword) { + return nodes; + } + const filtered: DocumentNode[] = []; + nodes.forEach((node) => { + const childMatches = filterTree(node.children, keyword); + const title = (node.title ?? "").toLowerCase(); + if (title.includes(keyword) || childMatches.length > 0) { + filtered.push({ ...node, children: childMatches }); + } + }); + return filtered; +}; + +function collectNodeIds(nodes: DocumentNode[], bag: Set = new Set()): Set { + nodes.forEach((node) => { + bag.add(node.id); + collectNodeIds(node.children, bag); + }); + return bag; +} + +const buildDocumentUrl = (documentId: string): string => { + if (typeof window === "undefined" || !window.location) { + return `/documents/${documentId}`; + } + return `${window.location.origin}/documents/${documentId}`; +}; + +const copyText = async (text: string, successMessage: string) => { + if (typeof navigator !== "undefined" && navigator.clipboard) { + try { + await navigator.clipboard.writeText(text); + window.alert(successMessage); + return; + } catch { + // ignore and fallback + } + } + window.prompt("复制失败,请手动复制内容", text); +}; diff --git a/src/components/sidebar/types.ts b/src/components/sidebar/types.ts new file mode 100644 index 00000000..ba5ae566 --- /dev/null +++ b/src/components/sidebar/types.ts @@ -0,0 +1,19 @@ +import type { DocumentRecord } from "@/lib/documents"; +import type { WorkspaceSummary } from "@/lib/workspaces"; + +export type SidebarSectionId = "starred" | "public" | "shared" | "private" | "templates"; + +export interface TrashRecord { + id: string; + title: string | null; + deleted_at: string; + parent_id: string | null; + access_scope: DocumentRecord["access_scope"]; +} + +export interface SidebarInitialData { + activeWorkspaceId: string; + workspaces: WorkspaceSummary[]; + documents: DocumentRecord[]; + trashedDocuments: TrashRecord[]; +} diff --git a/src/components/ui/avatar.tsx b/src/components/ui/avatar.tsx new file mode 100644 index 00000000..71e428b4 --- /dev/null +++ b/src/components/ui/avatar.tsx @@ -0,0 +1,53 @@ +"use client" + +import * as React from "react" +import * as AvatarPrimitive from "@radix-ui/react-avatar" + +import { cn } from "@/lib/utils" + +function Avatar({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarImage({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarFallback({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx new file mode 100644 index 00000000..fd3a406b --- /dev/null +++ b/src/components/ui/badge.tsx @@ -0,0 +1,46 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span" + + return ( + + ) +} + +export { Badge, badgeVariants } diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 00000000..21409a06 --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,60 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: + "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2 has-[>svg]:px-3", + sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", + lg: "h-10 rounded-md px-6 has-[>svg]:px-4", + icon: "size-9", + "icon-sm": "size-8", + "icon-lg": "size-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +function Button({ + className, + variant, + size, + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean + }) { + const Comp = asChild ? Slot : "button" + + return ( + + ) +} + +export { Button, buttonVariants } diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx new file mode 100644 index 00000000..681ad980 --- /dev/null +++ b/src/components/ui/card.tsx @@ -0,0 +1,92 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Card({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardDescription({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardAction({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardAction, + CardDescription, + CardContent, +} diff --git a/src/components/ui/command.tsx b/src/components/ui/command.tsx new file mode 100644 index 00000000..8cb4ca7a --- /dev/null +++ b/src/components/ui/command.tsx @@ -0,0 +1,184 @@ +"use client" + +import * as React from "react" +import { Command as CommandPrimitive } from "cmdk" +import { SearchIcon } from "lucide-react" + +import { cn } from "@/lib/utils" +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" + +function Command({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandDialog({ + title = "Command Palette", + description = "Search for a command to run...", + children, + className, + showCloseButton = true, + ...props +}: React.ComponentProps & { + title?: string + description?: string + className?: string + showCloseButton?: boolean +}) { + return ( + + + {title} + {description} + + + + {children} + + + + ) +} + +function CommandInput({ + className, + ...props +}: React.ComponentProps) { + return ( +
+ + +
+ ) +} + +function CommandList({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandEmpty({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandGroup({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandShortcut({ + className, + ...props +}: React.ComponentProps<"span">) { + return ( + + ) +} + +export { + Command, + CommandDialog, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, + CommandSeparator, +} diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx new file mode 100644 index 00000000..ffbb9d69 --- /dev/null +++ b/src/components/ui/dialog.tsx @@ -0,0 +1,152 @@ +"use client" + +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { XIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Dialog({ + ...props +}: React.ComponentProps) { + return +} + +function DialogTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function DialogPortal({ + ...props +}: React.ComponentProps) { + return +} + +function DialogClose({ + ...props +}: React.ComponentProps) { + return +} + +function DialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogContent({ + className, + children, + showCloseButton = true, + fullScreen = false, + ...props +}: React.ComponentProps & { + showCloseButton?: boolean + fullScreen?: boolean +}) { + const baseClass = + "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"; + const defaultLayout = + "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg"; + const fullscreenLayout = + "fixed inset-0 z-50 grid h-full w-full translate-x-0 translate-y-0 rounded-none border-none p-0 shadow-none duration-200"; + return ( + + + + {children} + {showCloseButton && ( + + + Close + + )} + + + ) +} + +function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +} diff --git a/src/components/ui/drawer.tsx b/src/components/ui/drawer.tsx new file mode 100644 index 00000000..8aa69230 --- /dev/null +++ b/src/components/ui/drawer.tsx @@ -0,0 +1,135 @@ +"use client" + +import * as React from "react" +import { Drawer as DrawerPrimitive } from "vaul" + +import { cn } from "@/lib/utils" + +function Drawer({ + ...props +}: React.ComponentProps) { + return +} + +function DrawerTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function DrawerPortal({ + ...props +}: React.ComponentProps) { + return +} + +function DrawerClose({ + ...props +}: React.ComponentProps) { + return +} + +function DrawerOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DrawerContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + +
+ {children} + + + ) +} + +function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DrawerTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DrawerDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Drawer, + DrawerPortal, + DrawerOverlay, + DrawerTrigger, + DrawerClose, + DrawerContent, + DrawerHeader, + DrawerFooter, + DrawerTitle, + DrawerDescription, +} diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx new file mode 100644 index 00000000..bbe6fb01 --- /dev/null +++ b/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,257 @@ +"use client" + +import * as React from "react" +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" +import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function DropdownMenu({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuContent({ + className, + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function DropdownMenuGroup({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuItem({ + className, + inset, + variant = "default", + ...props +}: React.ComponentProps & { + inset?: boolean + variant?: "default" | "destructive" +}) { + return ( + + ) +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function DropdownMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + ) +} + +function DropdownMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuShortcut({ + className, + ...props +}: React.ComponentProps<"span">) { + return ( + + ) +} + +function DropdownMenuSub({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + {children} + + + ) +} + +function DropdownMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + DropdownMenu, + DropdownMenuPortal, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, +} diff --git a/src/components/ui/hover-card.tsx b/src/components/ui/hover-card.tsx new file mode 100644 index 00000000..47389043 --- /dev/null +++ b/src/components/ui/hover-card.tsx @@ -0,0 +1,30 @@ +"use client"; + +import * as HoverCardPrimitive from "@radix-ui/react-hover-card"; + +import { cn } from "@/lib/utils"; + +const HoverCard = HoverCardPrimitive.Root; + +const HoverCardTrigger = HoverCardPrimitive.Trigger; + +function HoverCardContent({ + className, + align = "center", + sideOffset = 8, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { HoverCard, HoverCardContent, HoverCardTrigger }; diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx new file mode 100644 index 00000000..89169058 --- /dev/null +++ b/src/components/ui/input.tsx @@ -0,0 +1,21 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Input({ className, type, ...props }: React.ComponentProps<"input">) { + return ( + + ) +} + +export { Input } diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx new file mode 100644 index 00000000..fb5fbc3e --- /dev/null +++ b/src/components/ui/label.tsx @@ -0,0 +1,24 @@ +"use client" + +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" + +import { cn } from "@/lib/utils" + +function Label({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Label } diff --git a/src/components/ui/popover.tsx b/src/components/ui/popover.tsx new file mode 100644 index 00000000..01e468b6 --- /dev/null +++ b/src/components/ui/popover.tsx @@ -0,0 +1,48 @@ +"use client" + +import * as React from "react" +import * as PopoverPrimitive from "@radix-ui/react-popover" + +import { cn } from "@/lib/utils" + +function Popover({ + ...props +}: React.ComponentProps) { + return +} + +function PopoverTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function PopoverContent({ + className, + align = "center", + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function PopoverAnchor({ + ...props +}: React.ComponentProps) { + return +} + +export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } diff --git a/src/components/ui/scroll-area.tsx b/src/components/ui/scroll-area.tsx new file mode 100644 index 00000000..8e4fa13f --- /dev/null +++ b/src/components/ui/scroll-area.tsx @@ -0,0 +1,58 @@ +"use client" + +import * as React from "react" +import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" + +import { cn } from "@/lib/utils" + +function ScrollArea({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + {children} + + + + + ) +} + +function ScrollBar({ + className, + orientation = "vertical", + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +export { ScrollArea, ScrollBar } diff --git a/src/components/ui/separator.tsx b/src/components/ui/separator.tsx new file mode 100644 index 00000000..275381ca --- /dev/null +++ b/src/components/ui/separator.tsx @@ -0,0 +1,28 @@ +"use client" + +import * as React from "react" +import * as SeparatorPrimitive from "@radix-ui/react-separator" + +import { cn } from "@/lib/utils" + +function Separator({ + className, + orientation = "horizontal", + decorative = true, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Separator } diff --git a/src/components/ui/sheet.tsx b/src/components/ui/sheet.tsx new file mode 100644 index 00000000..84649ad0 --- /dev/null +++ b/src/components/ui/sheet.tsx @@ -0,0 +1,139 @@ +"use client" + +import * as React from "react" +import * as SheetPrimitive from "@radix-ui/react-dialog" +import { XIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Sheet({ ...props }: React.ComponentProps) { + return +} + +function SheetTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function SheetClose({ + ...props +}: React.ComponentProps) { + return +} + +function SheetPortal({ + ...props +}: React.ComponentProps) { + return +} + +function SheetOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SheetContent({ + className, + children, + side = "right", + ...props +}: React.ComponentProps & { + side?: "top" | "right" | "bottom" | "left" +}) { + return ( + + + + {children} + + + Close + + + + ) +} + +function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function SheetTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SheetDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Sheet, + SheetTrigger, + SheetClose, + SheetContent, + SheetHeader, + SheetFooter, + SheetTitle, + SheetDescription, +} diff --git a/src/components/ui/skeleton.tsx b/src/components/ui/skeleton.tsx new file mode 100644 index 00000000..32ea0ef7 --- /dev/null +++ b/src/components/ui/skeleton.tsx @@ -0,0 +1,13 @@ +import { cn } from "@/lib/utils" + +function Skeleton({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { Skeleton } diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx new file mode 100644 index 00000000..497ba5ea --- /dev/null +++ b/src/components/ui/tabs.tsx @@ -0,0 +1,66 @@ +"use client" + +import * as React from "react" +import * as TabsPrimitive from "@radix-ui/react-tabs" + +import { cn } from "@/lib/utils" + +function Tabs({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function TabsList({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function TabsTrigger({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function TabsContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Tabs, TabsList, TabsTrigger, TabsContent } diff --git a/src/components/ui/textarea.tsx b/src/components/ui/textarea.tsx new file mode 100644 index 00000000..7f21b5e7 --- /dev/null +++ b/src/components/ui/textarea.tsx @@ -0,0 +1,18 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { + return ( +