diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml new file mode 100644 index 000000000..39d3f6baf --- /dev/null +++ b/.github/workflows/website.yml @@ -0,0 +1,86 @@ +name: Website + +on: + push: + branches: [main] + paths: + - "website/**" + - ".github/workflows/website.yml" + pull_request: + paths: + - "website/**" + - ".github/workflows/website.yml" + workflow_dispatch: + release: + types: [published] + # Releases published by GITHUB_TOKEN do not trigger another release workflow. + workflow_run: + workflows: [Release] + types: [completed] + +permissions: + contents: read + +concurrency: + group: website-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest + permissions: + contents: read + pages: read + defaults: + run: + working-directory: website + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + package_json_file: website/package.json + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + cache-dependency-path: website/pnpm-lock.yaml + - run: pnpm install --frozen-lockfile + - run: pnpm test + - name: Refresh official release downloads + env: + GITHUB_TOKEN: ${{ github.token }} + run: pnpm release:refresh + # A PR must be testable before Pages has been enabled in repository settings. + - id: pages + if: github.event_name != 'pull_request' + uses: actions/configure-pages@v5 + - name: Build static homepage + env: + BASE_PATH: ${{ github.event_name == 'pull_request' && format('/{0}', github.event.repository.name) || steps.pages.outputs.base_path }} + VITE_SITE_URL: ${{ steps.pages.outputs.base_url }} + run: pnpm build && pnpm typecheck && pnpm check:static + # Also verify a custom-domain / user-site root with no repository prefix. + - name: Check root deployment + if: github.event_name == 'pull_request' + env: + BASE_PATH: / + run: pnpm build && pnpm check:static + - uses: actions/upload-pages-artifact@v4 + if: github.event_name != 'pull_request' + with: + path: website/dist/client + + deploy: + if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + needs: build + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/website/.gitignore b/website/.gitignore new file mode 100644 index 000000000..effbf8da8 --- /dev/null +++ b/website/.gitignore @@ -0,0 +1,7 @@ +node_modules/ +dist/ +.tanstack/ +.output/ +.nitro/ +src/routeTree.gen.ts +*.tsbuildinfo diff --git a/website/README.md b/website/README.md new file mode 100644 index 000000000..4f0fd1dba --- /dev/null +++ b/website/README.md @@ -0,0 +1,61 @@ +# OpenIDEA website + +The dark, responsive product homepage uses TanStack Start, StyleX and Base UI. +It is an independent pnpm package; desktop dependencies and commands are unchanged. +Its local workspace boundary keeps installation independent of the parent workspace. + +```sh +cd website +pnpm install --frozen-lockfile +pnpm dev +``` + +Node 22.12+ and pnpm 11 are required. The image preview uses Base UI's Dialog for +keyboard focus management and Escape dismissal. Navigation and downloads are native +links. The debugger screenshot, logo and Inter font are hosted locally. Inter's license +is retained in `public/fonts/OFL.txt`. + +## Static build + +```sh +pnpm test +BASE_PATH=/openidea/ pnpm build +pnpm typecheck +BASE_PATH=/openidea/ pnpm check:static +pnpm preview +``` + +Open the preview at `/openidea/` when using that base path. Use `BASE_PATH=/` for a +custom-domain root or a user/organization Pages site. The deployable directory is +`dist/client/`; the server bundle is only used during prerendering and is not deployed. +No running Node server or API is required on GitHub Pages. + +`check:static` validates that the initial HTML contains the homepage, benchmark and +measurement caveat, that component styles have been compiled, and that local media, +fonts and bundles exist under the selected base path. + +## GitHub Pages + +1. In the target repository, select **Settings → Pages → Build and deployment → + Source: GitHub Actions**. Do this once before the first deployment. +2. Merge the website and `.github/workflows/website.yml` into `main`. +3. The Website workflow builds and deploys relevant main pushes. It can also be + triggered manually from Actions on `main`. PRs build and validate without publishing. + +`actions/configure-pages` supplies the repository prefix or custom-domain root and +canonical URL. The workflow uploads only `website/dist/client`. Deployment permissions +are restricted to the deploy job; no personal access token is needed by the workflow. +Check the existing `github-pages` environment's branch rules if GitHub blocks a deploy. + +Homepage download buttons open the matching macOS, Windows or Linux page when a desktop +platform can be identified. Mobile and unknown systems open the platform chooser. Each +platform page links directly to actual installer assets, with explicit architecture and +package format choices. All download pages are prerendered and work without JavaScript. + +`src/data/release.json` is a checked-in snapshot of the official stable release so local +builds work offline. Run `pnpm release:refresh` to refresh it from GitHub. CI refreshes it +before building; publishing a release or completing the Release workflow also rebuilds +the website. No browser-time GitHub API requests or API tokens are needed. + +The benchmark follows the root README; update `src/components/Home.tsx` when the published +measurements change. diff --git a/website/docs/screenshots/README.md b/website/docs/screenshots/README.md new file mode 100644 index 000000000..f44eb1d43 --- /dev/null +++ b/website/docs/screenshots/README.md @@ -0,0 +1,11 @@ +# Website screenshots + +Full-page desktop captures of the prerendered production website, served as static +files at `/openidea/`. These images show only the web page, without browser chrome. + +| Page | Width | Screenshot | +| ---------------- | ------ | --------------------------------- | +| Homepage | 1280px | [Full page](desktop.jpg) | +| macOS download | 1280px | [Full page](download-macos.jpg) | +| Windows download | 1280px | [Full page](download-windows.jpg) | +| Linux download | 1280px | [Full page](download-linux.jpg) | diff --git a/website/docs/screenshots/desktop.jpg b/website/docs/screenshots/desktop.jpg new file mode 100644 index 000000000..8ca094a45 Binary files /dev/null and b/website/docs/screenshots/desktop.jpg differ diff --git a/website/docs/screenshots/download-linux.jpg b/website/docs/screenshots/download-linux.jpg new file mode 100644 index 000000000..16e046051 Binary files /dev/null and b/website/docs/screenshots/download-linux.jpg differ diff --git a/website/docs/screenshots/download-macos.jpg b/website/docs/screenshots/download-macos.jpg new file mode 100644 index 000000000..02af82c30 Binary files /dev/null and b/website/docs/screenshots/download-macos.jpg differ diff --git a/website/docs/screenshots/download-windows.jpg b/website/docs/screenshots/download-windows.jpg new file mode 100644 index 000000000..d17b66eb6 Binary files /dev/null and b/website/docs/screenshots/download-windows.jpg differ diff --git a/website/package.json b/website/package.json new file mode 100644 index 000000000..074c92422 --- /dev/null +++ b/website/package.json @@ -0,0 +1,37 @@ +{ + "name": "@openidea/website", + "private": true, + "type": "module", + "license": "Apache-2.0", + "packageManager": "pnpm@11.0.0", + "engines": { + "node": ">=22.12" + }, + "scripts": { + "dev": "vite --host 127.0.0.1 --port 3000", + "build": "vite build", + "preview": "vite preview --host 127.0.0.1 --port 3000", + "typecheck": "tsc --noEmit", + "test": "node --test tests/*.test.mjs", + "release:refresh": "node scripts/update-release.mjs", + "check:static": "node scripts/check-static.mjs" + }, + "dependencies": { + "@base-ui/react": "1.9.0", + "@stylexjs/stylex": "0.19.1", + "@tanstack/react-router": "1.170.46", + "@tanstack/react-start": "1.169.4", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@stylexjs/unplugin": "0.19.1", + "@types/node": "^22.0.0", + "@types/react": "^19.2.0", + "@types/react-dom": "^19.2.0", + "@vitejs/plugin-react": "^6.0.0", + "typescript": "^5.9.0", + "unplugin": "^2.3.11", + "vite": "^8.0.0" + } +} diff --git a/website/pnpm-lock.yaml b/website/pnpm-lock.yaml new file mode 100644 index 000000000..bb127cedc --- /dev/null +++ b/website/pnpm-lock.yaml @@ -0,0 +1,1712 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@base-ui/react': + specifier: 1.9.0 + version: 1.9.0(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@stylexjs/stylex': + specifier: 0.19.1 + version: 0.19.1 + '@tanstack/react-router': + specifier: 1.170.46 + version: 1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@tanstack/react-start': + specifier: 1.169.4 + version: 1.169.4(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(rolldown@1.2.15)(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0)) + react: + specifier: ^19.2.0 + version: 19.3.1 + react-dom: + specifier: ^19.2.0 + version: 19.3.1(react@19.3.1) + devDependencies: + '@stylexjs/unplugin': + specifier: 0.19.1 + version: 0.19.1(unplugin@2.3.11) + '@types/node': + specifier: ^22.0.0 + version: 22.20.5 + '@types/react': + specifier: ^19.2.0 + version: 19.3.0 + '@types/react-dom': + specifier: ^19.2.0 + version: 19.3.0(@types/react@19.3.0) + '@vitejs/plugin-react': + specifier: ^6.0.0 + version: 6.1.2(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0)) + typescript: + specifier: ^5.9.0 + version: 5.9.3 + unplugin: + specifier: ^2.3.11 + version: 2.3.11 + vite: + specifier: ^8.0.0 + version: 8.3.5(@types/node@22.20.5)(jiti@2.7.0) + +packages: + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.29.11': + resolution: {integrity: sha512-snZbO7MEDOof+hvNa97EjEY7qD7h2kwvQr5AJC3ZhQudKW5dnej6k3kP9NQV88hJwaS8vDqRLFo9rivLEhle2g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.10': + resolution: {integrity: sha512-EMCx3AGZ3WfAl6ht7AyQoPm2Lh+BGYEMdc4Q6Hf7uSCDOZFuLq44qNwL+iaim8VlyYhRAo4X43+weadK8ZB4Yg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.11': + resolution: {integrity: sha512-OZ6+oaK7GMyg3IfCpj8JOmn8n+w2rJbDT0LLfVDTLb1ZFeKDh3AiNELgCMUw175IJHSkLl74hG0M0VLsvx+gag==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-flow@7.29.7': + resolution: {integrity: sha512-ajMX6QPcyomotqwpzhkYGxcK2i/us0rs1Qo9QvUpa+Fca0FTmqrzKrctoIYLMxcOhGZldGT/BAVkRGTWBiR8gQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.29.7': + resolution: {integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.29.7': + resolution: {integrity: sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@8.0.8': + resolution: {integrity: sha512-dEu8nGlRqjsJsvviUUoSMfcRHpwomCiRlXsc2mPfJ79+ffTpDm+JtfUtTMzUrqCApHQnCsVPD3gT1ZT8RgBRCQ==} + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.10': + resolution: {integrity: sha512-B3lYAs2nkKskbgQ1nfy8Ma9ao9Q1rntTAQHrzzyDuj+TSO+X3le6PfWwqDvodsb+OumE10eMFfuMCTQSQ5iuIQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.11': + resolution: {integrity: sha512-WCsemW40Cpc6gouC1SrY6PBaZ+oLRlEVY9XBvZBI7il/HyUrb2nJ505wE1MHEFyDZNnrWDEuy4jL50WVHfTTSQ==} + engines: {node: '>=6.9.0'} + + '@base-ui/react@1.9.0': + resolution: {integrity: sha512-S8CSYosASBKtpL8SWUfS78rFElfLijiCgA7oHOK22jCJ95FULsYyKwBNFOgudt0RA+/7yNc7F81bOvQnRgbBiQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@date-fns/tz': ^1.2.0 + '@types/react': ^17 || ^18 || ^19 + date-fns: ^4.0.0 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@date-fns/tz': + optional: true + '@types/react': + optional: true + date-fns: + optional: true + + '@base-ui/utils@0.5.0': + resolution: {integrity: sha512-dYGGcEttjkYiMoa5nHm8vLaJ2UcuTWxo3BFAwOYXeRg/q7UVVvA6cacEIXEs3FgBfK1CGtW1ptElqs7wsx+t9A==} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + + '@dual-bundle/import-meta-resolve@4.2.1': + resolution: {integrity: sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==} + + '@floating-ui/core@1.8.0': + resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==} + + '@floating-ui/dom@1.8.0': + resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==} + + '@floating-ui/react-dom@2.1.9': + resolution: {integrity: sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.12': + resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} + + '@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.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@oozcitak/dom@2.0.2': + resolution: {integrity: sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==} + engines: {node: '>=20.0'} + + '@oozcitak/infra@2.0.2': + resolution: {integrity: sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==} + engines: {node: '>=20.0'} + + '@oozcitak/url@3.0.0': + resolution: {integrity: sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==} + engines: {node: '>=20.0'} + + '@oozcitak/util@10.0.0': + resolution: {integrity: sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==} + engines: {node: '>=20.0'} + + '@oxc-project/types@0.155.0': + resolution: {integrity: sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==} + + '@rolldown/binding-android-arm-eabi@1.2.15': + resolution: {integrity: sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@rolldown/binding-android-arm64@1.2.15': + resolution: {integrity: sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.2.15': + resolution: {integrity: sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.2.15': + resolution: {integrity: sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.2.15': + resolution: {integrity: sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.2.15': + resolution: {integrity: sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.2.15': + resolution: {integrity: sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.2.15': + resolution: {integrity: sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.2.15': + resolution: {integrity: sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.2.15': + resolution: {integrity: sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.2.15': + resolution: {integrity: sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.2.15': + resolution: {integrity: sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.2.15': + resolution: {integrity: sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-win32-arm64-msvc@1.2.15': + resolution: {integrity: sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.2.15': + resolution: {integrity: sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@stylexjs/babel-plugin@0.19.1': + resolution: {integrity: sha512-Ig3crX6MuGWDEAx+f89aLxTQUWVeEc2Aco2moIdcObyvo7hZJgU26rxJN3k7geFjhi+5dfna6TNR8iTRK0PQGA==} + + '@stylexjs/shared@0.19.1': + resolution: {integrity: sha512-oFBtW0NPNLJOT1gLweWRNKrIJHjJMwOmSV7fgd6ewok4fwb/Nh95PEaYGKu+ZONk0nNghjLFfOwiIsxJdvh3TQ==} + + '@stylexjs/stylex@0.19.1': + resolution: {integrity: sha512-JwNFm0MOYPqi+M4Ax5Un4ZxfZp4HEAX2sAWetZ88KALFcv1eEiHNJs75oO3V3U7RVWnzfkiM8i9eBowC3hqgUw==} + + '@stylexjs/unplugin@0.19.1': + resolution: {integrity: sha512-MJz/IPrFe3hSHbZtjbxaYd3kLgS718/NFBEY/Mf+njteJKLdY7bHHfVka3051LCYy9fKfyZapGCmUpibraHqmQ==} + peerDependencies: + unplugin: ^2.3.11 + + '@tanstack/history@1.162.5': + resolution: {integrity: sha512-w1+YvwmTkwt5n8yUqEH3IWZ9DsmorCZW/EQ3KYHnqEgIkOZpH54NvW6/Epq3Dzb8H0ifIeYX8PExvrNLIH5FIA==} + engines: {node: '>=20.19'} + + '@tanstack/react-router@1.170.46': + resolution: {integrity: sha512-ez1iNIhsPjGlaDHg3BXWs67EWVIYzB2tbopEHYDESdkO7owgkGb5de52+5Kv2v1fxdkggcNzo35bdk4arTVGQw==} + engines: {node: '>=20.19'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-start-client@1.168.44': + resolution: {integrity: sha512-WvrYhQ0EgwYpxnP9mFCCo+jctqXV3qq8GfIyiSGLiZzz4GDyw+GuQ2lyA3BTN64wbNNNVeMll+9PV5OlGYi2/w==} + engines: {node: '>=22.12.0'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-start-rsc@0.1.65': + resolution: {integrity: sha512-5MmzmQoADjMA/d2XawkwKAkgBaQFrfifw/wn8qwCaLIntGYd2jkrCga/KdQW2xdjBu9IoP98WFhZilm7DfI/4g==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@rspack/core': '>=2.0.0-0' + '@vitejs/plugin-rsc': '>=0.5.30' + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + react-server-dom-rspack: '>=0.0.2' + peerDependenciesMeta: + '@rspack/core': + optional: true + '@vitejs/plugin-rsc': + optional: true + react-server-dom-rspack: + optional: true + + '@tanstack/react-start-server@1.167.52': + resolution: {integrity: sha512-131olF9oWx1CqZg8JYmIJbLNKqS/vN3UbYuc9a++pRtvfY67tpPmPzuYj4OXSxRAYalGW3f1yYlFozxqE1LE7w==} + engines: {node: '>=22.12.0'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-start@1.169.4': + resolution: {integrity: sha512-+DmlNPeQ1rsvo025I79GrlNgDm+zVCVAGg9gMIGmAevK2TJRMpKahgEKZZ1j4VSxDxjfTpkfLyuXiUxxjMJCaw==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@rsbuild/core': ^2.0.0 + '@vitejs/plugin-rsc': '*' + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + vite: '>=8.0.0' + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@vitejs/plugin-rsc': + optional: true + vite: + optional: true + + '@tanstack/react-store@0.11.2': + resolution: {integrity: sha512-oj5O5DmiMWE+ih+SioX2ayC1kbK7d3fpLx0B75fPJr9nY3zU+hoW010yr64qXsY/9fyiLVE2bn5mGNV3owm8RQ==} + 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/router-core@1.171.39': + resolution: {integrity: sha512-qUhoJ0meuSUqGYQbHbcJYdASr06YtK+bulbj6vtrhKYFkLgkSsZ6tXmMyym7sFxiSJSPYgasgozrL01LyyR/6A==} + engines: {node: '>=20.19'} + + '@tanstack/router-generator@1.167.46': + resolution: {integrity: sha512-JSailAThcqPvqBzE3+MhNh6zQyZM2IdmIsHOxZgAc061Lh++SZqamNm/Whe7QNXWK5sLP4E0J1F8AI0hP8wTSw==} + engines: {node: '>=20.19'} + + '@tanstack/router-plugin@1.168.48': + resolution: {integrity: sha512-oLDEZO/vhvF5JLrQ6qMNYcCjMMhlHA0Byx6ZXl9AHJ6qVLRxUeCU41vlZQ4buisONY2p0Zl9O09/qwLiVrIBCQ==} + engines: {node: '>=20.19'} + peerDependencies: + '@rsbuild/core': '>=1.0.2 || ^2.0.0' + '@tanstack/react-router': ^1.170.46 + vite: '>=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0' + vite-plugin-solid: ^2.11.10 || ^3.0.0-0 + webpack: '>=5.92.0' + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@tanstack/react-router': + optional: true + vite: + optional: true + vite-plugin-solid: + optional: true + webpack: + optional: true + + '@tanstack/router-utils@1.162.4': + resolution: {integrity: sha512-3TSH3rwAQTqQOtTBF8IXMFXmGNJWnjwIm+l87uguyC/of0pSRKcU9GJrozaf0fY9it8dLQvUZJA2MOlfqbW1sA==} + engines: {node: '>=20.19'} + + '@tanstack/start-client-core@1.170.39': + resolution: {integrity: sha512-G0VJbZFf9/dYomQjZkWapaTjkjEI4vbk1jnxhhVtQ3nTRb3sIRc196j+S+qZcySfEV5W9TJHu4KatjSzjZZQwQ==} + engines: {node: '>=22.12.0'} + + '@tanstack/start-fn-stubs@1.162.0': + resolution: {integrity: sha512-QWfUZ3Yo923tdQn38LyKMU8rcTw69zc+T4dAvgTWV4O56SqFRsGfS0lSWIMhJRwXIx/bvdi7nTUBDdZtTHtpTQ==} + engines: {node: '>=22.12.0'} + + '@tanstack/start-plugin-core@1.171.55': + resolution: {integrity: sha512-8FjTuuxIE8MNJoveXahZPBCfEpm8p9tMFyWTvbllfqlysdhry34rw/nCwULfcVwTG39ezXEu/RYE83NSV+miog==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@rsbuild/core': ^2.0.0 + vite: '>=8.0.0' + peerDependenciesMeta: + '@rsbuild/core': + optional: true + vite: + optional: true + + '@tanstack/start-server-core@1.169.45': + resolution: {integrity: sha512-fKySLUGIy7aVYR6ZRgjC19TQdsZ+q/54M9hVfHrJQQVpM/T5qq5djZ3gsqhugmrWP+gyd9qpa9D6cxRtR6CJvg==} + engines: {node: '>=22.12.0'} + + '@tanstack/start-storage-context@1.167.41': + resolution: {integrity: sha512-MY+Z4cZBPbH7hjORcROMX7K3kV1X25ArFKmRbks+EukPP9UVwCXbZFVzYkTt1u0AHthvQTcpa4J9B9i0o6fEnA==} + engines: {node: '>=22.12.0'} + + '@tanstack/store@0.11.2': + resolution: {integrity: sha512-sJ4mjol8uQsHV0gOJzzjwXfh2Fwm+Sz0+8deqiTm4jGbMdjzNSW+xZCFm0kUa870uhd8yi+DpKnZb5Kc4apa0Q==} + + '@tanstack/virtual-file-routes@1.162.0': + resolution: {integrity: sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==} + engines: {node: '>=20.19'} + + '@types/node@22.20.5': + resolution: {integrity: sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA==} + + '@types/react-dom@19.3.0': + resolution: {integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==} + peerDependencies: + '@types/react': ^19.3.0 + + '@types/react@19.3.0': + resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==} + + '@vitejs/plugin-react@6.1.2': + resolution: {integrity: sha512-fhJNGUdscQa4HkI0xFxwonWyhnVReCPDbXI7FH7jmzpnVCrFQI7PRrhWecO263610vOrs9tr2Y4xcf8uAdFxbw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + oxc-transform-react: ^0.152.0 + vite: ^8.0.0 + peerDependenciesMeta: + '@rolldown/plugin-babel': + optional: true + babel-plugin-react-compiler: + optional: true + oxc-transform-react: + optional: true + + acorn@8.19.0: + resolution: {integrity: sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ansis@4.4.0: + resolution: {integrity: sha512-9k3v7xcHwgdO/DruxGIg4HtjvlAZlcnsX/mzqUb1t3NkYnl9kK2UJ+Gq0io+vQf7iT//BD/HB/NBkUR1LWxoeA==} + engines: {node: '>=14'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + babel-dead-code-elimination@1.0.12: + resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} + + baseline-browser-mapping@2.11.34: + resolution: {integrity: sha512-Aqr8mA1kIvyJ3UY5YAY7ib8LSo1DmDMbMnVqGPtsKW1LxaFQFwn9Eb3yvq2fUKJsRvaXjnAV7R5osqETapzNiA==} + engines: {node: '>=6.0.0'} + hasBin: true + + browserslist@4.29.5: + resolution: {integrity: sha512-khTmKu5NGYTotqcYo8Bew2k4RAE9PuXRSFRXG2lQBrCEQHyeQ/vX6gKMxfokwywBsLiXZMnHsmWMG1pnO8J7uQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + caniuse-lite@1.0.30001819: + resolution: {integrity: sha512-LFUqIIAwpzsIuevnKnsR9qnStBcgzPShTX61lBwN9uFkkf8o8zLiebEjbW8AYtZiF+1YKDWfdt/pWDtMuG8Xwg==} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-es@3.1.1: + resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} + + css-mediaquery@0.1.2: + resolution: {integrity: sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + diff@9.0.0: + resolution: {integrity: sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==} + engines: {node: '>=0.3.1'} + + electron-to-chromium@1.5.467: + resolution: {integrity: sha512-Nw9X371rtZmYcBSnEijnCDONILjs93biCZO34juC7MBOmK8E+GFnyD4T/WvyrlJkppul7oxg6TwvtKst9SODTw==} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + exsolve@1.2.0: + resolution: {integrity: sha512-h1pQPR9XoeSMdntRNCjyTznaume4UpfXrULBnlkZ2CUM/G5eSa+pBByGldO5uR8dxbPC+OuJXsPPNf+JZ81ADg==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fetchdts@0.2.0: + resolution: {integrity: sha512-PJb4ZTGT2/wK78RmVrxZITStWabhZlKBsL52VOgq+c7clEkdHdEB+0rtzrXCbZJqeYJj+IwNWYqB5/G6vouA6A==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + + isbot@5.2.2: + resolution: {integrity: sha512-iQcBXcd+Rv/pkubRyGh2utW2j1oPG5hZY6TUhVPpqK4G+o3IbxpJNx04hgksjc/N7GK5pEorUxDeg31cFgEk/w==} + engines: {node: '>=18'} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.3.2: + resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} + + 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==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.20: + resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-releases@2.0.60: + resolution: {integrity: sha512-OmO8+GM1JUZqXET720VrJCwkjUCXmCMQm0Z3UDDRbfNLHS4NEAvY60j5jiFv0tkKw2PNNlqOLhahVmwJIOLDIQ==} + engines: {node: '>=18'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.32: + resolution: {integrity: sha512-LJlKCCAUFKOuZxipUdYw1NzIITEsPcgyOG9LkvRJvuKj/bRzbuRY0ARXvL0pWGpsZvn8jku+LMep2eU0seHp8g==} + engines: {node: ^10 || ^12 || >=14} + + prettier@3.9.10: + resolution: {integrity: sha512-skGHTH1Yb9QvaTC4hWnRTzEYtCpApF0UMBPz+t/0ZPzP8ihefo/btKd+QA7pUE0fEwA1SbS/NmhyEcstdXOIdA==} + engines: {node: '>=14'} + hasBin: true + + react-dom@19.3.1: + resolution: {integrity: sha512-Y0bARz53lhEC1NMCASs0/j+faB/zqt3R8hpvg1e8+61ZVJ4UL0UdC4cBbXfZMcIuhrfgeILTLe+ZeBCavQPtKQ==} + peerDependencies: + react: ^19.3.1 + + react@19.3.1: + resolution: {integrity: sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==} + engines: {node: '>=0.10.0'} + + readdirp@5.1.1: + resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==} + engines: {node: '>= 20.19.0'} + + reselect@5.3.0: + resolution: {integrity: sha512-XGoLeRAVzUTcJ1qkxPQhDJyIZ5d6zzZD9nT7AEZOaaU9UbWclhycElmhO+VD5bFeLuzhPBaOV2oXC8uG35ZSpg==} + + rolldown@1.2.15: + resolution: {integrity: sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + scheduler@0.28.0: + resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + seroval-plugins@1.7.2: + resolution: {integrity: sha512-ud8kMCGLHmGkW9YtVDluJtqTukSx/4YBqtmPAvAz/HxbIwhwMeZU52imxeyZ1zoAXtqBDiaLwSasbnK9DptrDg==} + engines: {node: '>=20'} + peerDependencies: + seroval: ^1.0 + + seroval@1.7.2: + resolution: {integrity: sha512-NPOYrDVbvtuTo5m9InqKE7O6wBASON46OabjyqLUGPvoXNDYp0pReuFYkqOQwGsoj1OpZVj6mIdnRRgt5O1/gQ==} + engines: {node: '>=20'} + + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + srvx@1.0.8: + resolution: {integrity: sha512-ngFS/J6St4PJfHRHGjr78xkPPtbyXtdMOLNE4x/XZunEK3OhV7aGUWMHf9WTUEy6wm1U0W4okkd82ZFFWRVQTw==} + engines: {node: '>=20.16.0'} + hasBin: true + + styleq@0.2.1: + resolution: {integrity: sha512-L0TR0NQb+X4/ktDEKmjWyp27gla+LUYi/by5k5SjKXf6/pvZP7wbwEB5J+tqxdFVPgzbsuz+d4RTScO/QZquBw==} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} + engines: {node: '>=18.12.0'} + + unplugin@3.7.0: + resolution: {integrity: sha512-GrM2uq3DQo3hvLU2FjeYhooJ8BY9N6j1Fbzgx7Pta3VVJevsD3VP4dPjZkZOS0mLvN8w9zzr9OlP+31bSMyuLw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@farmfe/core': '*' + '@rsbuild/core': '*' + '@rspack/core': '*' + bun-types-no-globals: '*' + esbuild: '*' + rolldown: '*' + rollup: '*' + unloader: '*' + vite: '*' + webpack: '*' + peerDependenciesMeta: + '@farmfe/core': + optional: true + '@rsbuild/core': + optional: true + '@rspack/core': + optional: true + bun-types-no-globals: + optional: true + esbuild: + optional: true + rolldown: + optional: true + rollup: + optional: true + unloader: + optional: true + vite: + optional: true + webpack: + optional: true + + update-browserslist-db@1.3.4: + resolution: {integrity: sha512-t8wonIOdQyOjtPd2VktlBu6QjTVTks6v8bSi7kd0r2Vll8TK1JYDZtRRdbmCHOAMphkZgrzK+L+vXK4pyZ8t4A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + use-sync-external-store@1.7.0: + resolution: {integrity: sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + vite@8.3.5: + resolution: {integrity: sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.7.1 || ^0.8.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.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 + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.1.3: + resolution: {integrity: sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + vite: + optional: true + + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + xmlbuilder2@4.0.3: + resolution: {integrity: sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==} + engines: {node: '>=20.0'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + zod@4.6.7: + resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} + +snapshots: + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.10 + '@babel/parser': 7.29.11 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.10 + '@babel/types': 7.29.11 + '@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.29.8': + dependencies: + '@babel/parser': 7.29.11 + '@babel/types': 7.29.11 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.29.5 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.10 + '@babel/types': 7.29.11 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.10 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.29.7': {} + + '@babel/helper-string-parser@7.29.11': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.10': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.11 + + '@babel/parser@7.29.11': + dependencies: + '@babel/types': 7.29.11 + + '@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/runtime@8.0.8': {} + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.11 + '@babel/types': 7.29.11 + + '@babel/traverse@7.29.10': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.11 + '@babel/template': 7.29.7 + '@babel/types': 7.29.11 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.11': + dependencies: + '@babel/helper-string-parser': 7.29.11 + '@babel/helper-validator-identifier': 7.29.7 + + '@base-ui/react@1.9.0(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': + dependencies: + '@babel/runtime': 8.0.8 + '@base-ui/utils': 0.5.0(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@floating-ui/react-dom': 2.1.9(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@floating-ui/utils': 0.2.12 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + use-sync-external-store: 1.7.0(react@19.3.1) + optionalDependencies: + '@types/react': 19.3.0 + + '@base-ui/utils@0.5.0(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': + dependencies: + '@babel/runtime': 8.0.8 + '@floating-ui/utils': 0.2.12 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + reselect: 5.3.0 + use-sync-external-store: 1.7.0(react@19.3.1) + optionalDependencies: + '@types/react': 19.3.0 + + '@dual-bundle/import-meta-resolve@4.2.1': {} + + '@floating-ui/core@1.8.0': + dependencies: + '@floating-ui/utils': 0.2.12 + + '@floating-ui/dom@1.8.0': + dependencies: + '@floating-ui/core': 1.8.0 + '@floating-ui/utils': 0.2.12 + + '@floating-ui/react-dom@2.1.9(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': + dependencies: + '@floating-ui/dom': 1.8.0 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + + '@floating-ui/utils@0.2.12': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + '@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.6.0': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.6.0 + + '@oozcitak/dom@2.0.2': + dependencies: + '@oozcitak/infra': 2.0.2 + '@oozcitak/url': 3.0.0 + '@oozcitak/util': 10.0.0 + + '@oozcitak/infra@2.0.2': + dependencies: + '@oozcitak/util': 10.0.0 + + '@oozcitak/url@3.0.0': + dependencies: + '@oozcitak/infra': 2.0.2 + '@oozcitak/util': 10.0.0 + + '@oozcitak/util@10.0.0': {} + + '@oxc-project/types@0.155.0': {} + + '@rolldown/binding-android-arm-eabi@1.2.15': + optional: true + + '@rolldown/binding-android-arm64@1.2.15': + optional: true + + '@rolldown/binding-darwin-arm64@1.2.15': + optional: true + + '@rolldown/binding-darwin-x64@1.2.15': + optional: true + + '@rolldown/binding-freebsd-x64@1.2.15': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.2.15': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.2.15': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.2.15': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.2.15': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.2.15': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.2.15': + optional: true + + '@rolldown/binding-linux-x64-musl@1.2.15': + optional: true + + '@rolldown/binding-openharmony-arm64@1.2.15': + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.2.15': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.2.15': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@stylexjs/babel-plugin@0.19.1': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/traverse': 7.29.10 + '@babel/types': 7.29.11 + '@dual-bundle/import-meta-resolve': 4.2.1 + '@stylexjs/shared': 0.19.1 + '@stylexjs/stylex': 0.19.1 + postcss-value-parser: 4.2.0 + transitivePeerDependencies: + - supports-color + + '@stylexjs/shared@0.19.1': {} + + '@stylexjs/stylex@0.19.1': + dependencies: + css-mediaquery: 0.1.2 + invariant: 2.2.4 + styleq: 0.2.1 + + '@stylexjs/unplugin@0.19.1(unplugin@2.3.11)': + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-syntax-flow': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) + '@stylexjs/babel-plugin': 0.19.1 + browserslist: 4.29.5 + lightningcss: 1.33.0 + unplugin: 2.3.11 + transitivePeerDependencies: + - supports-color + + '@tanstack/history@1.162.5': {} + + '@tanstack/react-router@1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': + dependencies: + '@tanstack/history': 1.162.5 + '@tanstack/react-store': 0.11.2(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@tanstack/router-core': 1.171.39 + isbot: 5.2.2 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + + '@tanstack/react-start-client@1.168.44(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': + dependencies: + '@tanstack/react-router': 1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@tanstack/router-core': 1.171.39 + '@tanstack/start-client-core': 1.170.39 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + + '@tanstack/react-start-rsc@0.1.65(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(rolldown@1.2.15)(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0))': + dependencies: + '@tanstack/react-router': 1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@tanstack/router-core': 1.171.39 + '@tanstack/router-utils': 1.162.4 + '@tanstack/start-client-core': 1.170.39 + '@tanstack/start-fn-stubs': 1.162.0 + '@tanstack/start-plugin-core': 1.171.55(@tanstack/react-router@1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(rolldown@1.2.15)(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0)) + '@tanstack/start-storage-context': 1.167.41 + pathe: 2.0.3 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + transitivePeerDependencies: + - '@farmfe/core' + - '@rsbuild/core' + - bun-types-no-globals + - esbuild + - rolldown + - rollup + - supports-color + - unloader + - vite + - vite-plugin-solid + - webpack + + '@tanstack/react-start-server@1.167.52(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': + dependencies: + '@tanstack/react-router': 1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@tanstack/router-core': 1.171.39 + '@tanstack/start-server-core': 1.169.45 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + + '@tanstack/react-start@1.169.4(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(rolldown@1.2.15)(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0))': + dependencies: + '@tanstack/react-router': 1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@tanstack/react-start-client': 1.168.44(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@tanstack/react-start-rsc': 0.1.65(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(rolldown@1.2.15)(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0)) + '@tanstack/react-start-server': 1.167.52(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + '@tanstack/router-utils': 1.162.4 + '@tanstack/start-client-core': 1.170.39 + '@tanstack/start-plugin-core': 1.171.55(@tanstack/react-router@1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(rolldown@1.2.15)(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0)) + '@tanstack/start-server-core': 1.169.45 + pathe: 2.0.3 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + optionalDependencies: + vite: 8.3.5(@types/node@22.20.5)(jiti@2.7.0) + transitivePeerDependencies: + - '@farmfe/core' + - '@rspack/core' + - bun-types-no-globals + - esbuild + - react-server-dom-rspack + - rolldown + - rollup + - supports-color + - unloader + - vite-plugin-solid + - webpack + + '@tanstack/react-store@0.11.2(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': + dependencies: + '@tanstack/store': 0.11.2 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + use-sync-external-store: 1.7.0(react@19.3.1) + + '@tanstack/router-core@1.171.39': + dependencies: + '@tanstack/history': 1.162.5 + cookie-es: 3.1.1 + seroval: 1.7.2 + seroval-plugins: 1.7.2(seroval@1.7.2) + + '@tanstack/router-generator@1.167.46': + dependencies: + '@babel/types': 7.29.11 + '@tanstack/router-core': 1.171.39 + '@tanstack/router-utils': 1.162.4 + '@tanstack/virtual-file-routes': 1.162.0 + jiti: 2.7.0 + magic-string: 0.30.21 + prettier: 3.9.10 + zod: 4.6.7 + transitivePeerDependencies: + - supports-color + + '@tanstack/router-plugin@1.168.48(@tanstack/react-router@1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(rolldown@1.2.15)(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0))': + dependencies: + '@babel/core': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.11 + '@tanstack/router-core': 1.171.39 + '@tanstack/router-generator': 1.167.46 + '@tanstack/router-utils': 1.162.4 + chokidar: 5.0.0 + unplugin: 3.7.0(rolldown@1.2.15)(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0)) + zod: 4.6.7 + optionalDependencies: + '@tanstack/react-router': 1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1) + vite: 8.3.5(@types/node@22.20.5)(jiti@2.7.0) + transitivePeerDependencies: + - '@farmfe/core' + - '@rspack/core' + - bun-types-no-globals + - esbuild + - rolldown + - rollup + - supports-color + - unloader + + '@tanstack/router-utils@1.162.4': + dependencies: + '@babel/generator': 7.29.8 + '@babel/parser': 7.29.11 + '@babel/types': 7.29.11 + ansis: 4.4.0 + babel-dead-code-elimination: 1.0.12 + diff: 9.0.0 + pathe: 2.0.3 + tinyglobby: 0.2.17 + transitivePeerDependencies: + - supports-color + + '@tanstack/start-client-core@1.170.39': + dependencies: + '@tanstack/router-core': 1.171.39 + '@tanstack/start-fn-stubs': 1.162.0 + '@tanstack/start-storage-context': 1.167.41 + seroval: 1.7.2 + + '@tanstack/start-fn-stubs@1.162.0': {} + + '@tanstack/start-plugin-core@1.171.55(@tanstack/react-router@1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(rolldown@1.2.15)(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0))': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/core': 7.29.7 + '@babel/types': 7.29.11 + '@jridgewell/remapping': 2.3.5 + '@tanstack/router-core': 1.171.39 + '@tanstack/router-generator': 1.167.46 + '@tanstack/router-plugin': 1.168.48(@tanstack/react-router@1.170.46(react-dom@19.3.1(react@19.3.1))(react@19.3.1))(rolldown@1.2.15)(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0)) + '@tanstack/router-utils': 1.162.4 + '@tanstack/start-server-core': 1.169.45 + exsolve: 1.2.0 + lightningcss: 1.33.0 + pathe: 2.0.3 + picomatch: 4.0.7 + seroval: 1.7.2 + source-map: 0.7.6 + srvx: 1.0.8 + tinyglobby: 0.2.17 + ufo: 1.6.4 + vitefu: 1.1.3(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0)) + xmlbuilder2: 4.0.3 + zod: 4.6.7 + optionalDependencies: + vite: 8.3.5(@types/node@22.20.5)(jiti@2.7.0) + transitivePeerDependencies: + - '@farmfe/core' + - '@rspack/core' + - '@tanstack/react-router' + - bun-types-no-globals + - esbuild + - rolldown + - rollup + - supports-color + - unloader + - vite-plugin-solid + - webpack + + '@tanstack/start-server-core@1.169.45': + dependencies: + '@tanstack/history': 1.162.5 + '@tanstack/router-core': 1.171.39 + '@tanstack/start-client-core': 1.170.39 + '@tanstack/start-storage-context': 1.167.41 + cookie-es: 3.1.1 + fetchdts: 0.2.0 + seroval: 1.7.2 + + '@tanstack/start-storage-context@1.167.41': + dependencies: + '@tanstack/router-core': 1.171.39 + + '@tanstack/store@0.11.2': {} + + '@tanstack/virtual-file-routes@1.162.0': {} + + '@types/node@22.20.5': + dependencies: + undici-types: 6.21.0 + + '@types/react-dom@19.3.0(@types/react@19.3.0)': + dependencies: + '@types/react': 19.3.0 + + '@types/react@19.3.0': + dependencies: + csstype: 3.2.3 + + '@vitejs/plugin-react@6.1.2(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 8.3.5(@types/node@22.20.5)(jiti@2.7.0) + + acorn@8.19.0: {} + + ansis@4.4.0: {} + + argparse@2.0.1: {} + + babel-dead-code-elimination@1.0.12: + dependencies: + '@babel/core': 7.29.7 + '@babel/parser': 7.29.11 + '@babel/traverse': 7.29.10 + '@babel/types': 7.29.11 + transitivePeerDependencies: + - supports-color + + baseline-browser-mapping@2.11.34: {} + + browserslist@4.29.5: + dependencies: + baseline-browser-mapping: 2.11.34 + caniuse-lite: 1.0.30001819 + electron-to-chromium: 1.5.467 + node-releases: 2.0.60 + update-browserslist-db: 1.3.4(browserslist@4.29.5) + + caniuse-lite@1.0.30001819: {} + + chokidar@5.0.0: + dependencies: + readdirp: 5.1.1 + + convert-source-map@2.0.0: {} + + cookie-es@3.1.1: {} + + css-mediaquery@0.1.2: {} + + csstype@3.2.3: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + detect-libc@2.1.2: {} + + diff@9.0.0: {} + + electron-to-chromium@1.5.467: {} + + escalade@3.2.0: {} + + exsolve@1.2.0: {} + + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + + fetchdts@0.2.0: {} + + fsevents@2.3.3: + optional: true + + gensync@1.0.0-beta.2: {} + + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 + + isbot@5.2.2: {} + + jiti@2.7.0: {} + + js-tokens@4.0.0: {} + + js-yaml@4.3.2: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json5@2.2.3: {} + + lightningcss-android-arm64@1.33.0: + optional: true + + lightningcss-darwin-arm64@1.33.0: + optional: true + + lightningcss-darwin-x64@1.33.0: + optional: true + + lightningcss-freebsd-x64@1.33.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + + lightningcss-linux-arm64-gnu@1.33.0: + optional: true + + lightningcss-linux-arm64-musl@1.33.0: + optional: true + + lightningcss-linux-x64-gnu@1.33.0: + optional: true + + lightningcss-linux-x64-musl@1.33.0: + optional: true + + lightningcss-win32-arm64-msvc@1.33.0: + optional: true + + lightningcss-win32-x64-msvc@1.33.0: + optional: true + + lightningcss@1.33.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 + + 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.6.0 + + ms@2.1.3: {} + + nanoid@3.3.20: {} + + node-releases@2.0.60: {} + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@4.0.7: {} + + postcss-value-parser@4.2.0: {} + + postcss@8.5.32: + dependencies: + nanoid: 3.3.20 + picocolors: 1.1.1 + source-map-js: 1.2.2 + + prettier@3.9.10: {} + + react-dom@19.3.1(react@19.3.1): + dependencies: + react: 19.3.1 + scheduler: 0.28.0 + + react@19.3.1: {} + + readdirp@5.1.1: {} + + reselect@5.3.0: {} + + rolldown@1.2.15: + dependencies: + '@oxc-project/types': 0.155.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.15 + '@rolldown/binding-android-arm64': 1.2.15 + '@rolldown/binding-darwin-arm64': 1.2.15 + '@rolldown/binding-darwin-x64': 1.2.15 + '@rolldown/binding-freebsd-x64': 1.2.15 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.15 + '@rolldown/binding-linux-arm64-gnu': 1.2.15 + '@rolldown/binding-linux-arm64-musl': 1.2.15 + '@rolldown/binding-linux-ppc64-gnu': 1.2.15 + '@rolldown/binding-linux-s390x-gnu': 1.2.15 + '@rolldown/binding-linux-x64-gnu': 1.2.15 + '@rolldown/binding-linux-x64-musl': 1.2.15 + '@rolldown/binding-openharmony-arm64': 1.2.15 + '@rolldown/binding-win32-arm64-msvc': 1.2.15 + '@rolldown/binding-win32-x64-msvc': 1.2.15 + + scheduler@0.28.0: {} + + semver@6.3.1: {} + + seroval-plugins@1.7.2(seroval@1.7.2): + dependencies: + seroval: 1.7.2 + + seroval@1.7.2: {} + + source-map-js@1.2.2: {} + + source-map@0.7.6: {} + + srvx@1.0.8: {} + + styleq@0.2.1: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + + typescript@5.9.3: {} + + ufo@1.6.4: {} + + undici-types@6.21.0: {} + + unplugin@2.3.11: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.19.0 + picomatch: 4.0.7 + webpack-virtual-modules: 0.6.2 + + unplugin@3.7.0(rolldown@1.2.15)(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0)): + dependencies: + '@jridgewell/remapping': 2.3.5 + '@rolldown/pluginutils': 1.0.1 + picomatch: 4.0.7 + webpack-virtual-modules: 0.6.2 + optionalDependencies: + rolldown: 1.2.15 + vite: 8.3.5(@types/node@22.20.5)(jiti@2.7.0) + + update-browserslist-db@1.3.4(browserslist@4.29.5): + dependencies: + browserslist: 4.29.5 + escalade: 3.2.0 + picocolors: 1.1.1 + + use-sync-external-store@1.7.0(react@19.3.1): + dependencies: + react: 19.3.1 + + vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0): + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.7 + postcss: 8.5.32 + rolldown: 1.2.15 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 22.20.5 + fsevents: 2.3.3 + jiti: 2.7.0 + + vitefu@1.1.3(vite@8.3.5(@types/node@22.20.5)(jiti@2.7.0)): + optionalDependencies: + vite: 8.3.5(@types/node@22.20.5)(jiti@2.7.0) + + webpack-virtual-modules@0.6.2: {} + + xmlbuilder2@4.0.3: + dependencies: + '@oozcitak/dom': 2.0.2 + '@oozcitak/infra': 2.0.2 + '@oozcitak/util': 10.0.0 + js-yaml: 4.3.2 + + yallist@3.1.1: {} + + zod@4.6.7: {} diff --git a/website/pnpm-workspace.yaml b/website/pnpm-workspace.yaml new file mode 100644 index 000000000..ef9e0e70b --- /dev/null +++ b/website/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +# Keep this standalone package independent of the desktop workspace above it. +packages: [] diff --git a/website/public/.nojekyll b/website/public/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/website/public/fonts/OFL.txt b/website/public/fonts/OFL.txt new file mode 100644 index 000000000..40589daa9 --- /dev/null +++ b/website/public/fonts/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2016 The Inter Project Authors (https://github.com/rsms/inter) Inter-Italic[opsz,wght].ttf: Copyright 2016 The Inter Project Authors (https://github.com/rsms/inter) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/website/public/fonts/inter-latin-wght-normal.woff2 b/website/public/fonts/inter-latin-wght-normal.woff2 new file mode 100644 index 000000000..d15208de0 Binary files /dev/null and b/website/public/fonts/inter-latin-wght-normal.woff2 differ diff --git a/website/public/mark.svg b/website/public/mark.svg new file mode 100644 index 000000000..a9728d7fd --- /dev/null +++ b/website/public/mark.svg @@ -0,0 +1 @@ +OpenIDEA diff --git a/website/public/media/debug.jpg b/website/public/media/debug.jpg new file mode 100644 index 000000000..41fa4be5b Binary files /dev/null and b/website/public/media/debug.jpg differ diff --git a/website/scripts/check-static.mjs b/website/scripts/check-static.mjs new file mode 100644 index 000000000..aa8adb9e2 --- /dev/null +++ b/website/scripts/check-static.mjs @@ -0,0 +1,67 @@ +import assert from "node:assert/strict"; +import { access, readFile, readdir, stat } from "node:fs/promises"; +import { resolve } from "node:path"; +import { pathToFileURL } from "node:url"; +import { normalizeBasePath } from "../src/lib/paths.mjs"; + +export async function checkStatic(root, basePath = "/") { + const base = normalizeBasePath(basePath); + const html = await readFile(resolve(root, "index.html"), "utf8"); + const visibleText = html.replace(/<[^>]*>/g, " ").replace(/\s+/g, " "); + assert.match(visibleText, /The IDE you know,\s*rebuilt in Rust\./, "Missing prerendered homepage"); + for (const text of [ + "Keep your way of working.", + "Startup and memory.", + "169 MB", + "Warm caches", + "IDEA analyses Python more deeply", + "Try OpenIDEA.", + ]) { + assert.ok(visibleText.includes(text), `Missing prerendered homepage content: ${text}`); + } + + const checked = new Set(); + async function checkAsset(reference, parent = new URL(base, "https://pages.test")) { + if (/^(?:https?:|data:|mailto:|#|\/\/)/.test(reference)) return; + const url = new URL(reference, parent); + assert.ok(url.pathname.startsWith(base), `Asset escaped base path ${base}: ${reference}`); + const relative = decodeURIComponent(url.pathname.slice(base.length)); + if (!relative || checked.has(relative)) return; + checked.add(relative); + const file = resolve(root, relative); + assert.ok(file.startsWith(`${resolve(root)}/`), `Asset escaped output directory: ${reference}`); + await access(file).catch(() => { + throw new Error(`Missing asset: ${reference}`); + }); + if ((await stat(file)).isDirectory()) { + await access(resolve(file, "index.html")).catch(() => { + throw new Error(`Missing prerendered index: ${reference}`); + }); + } + if (relative.endsWith(".css")) { + const css = await readFile(file, "utf8"); + assert.ok( + css.includes("cursor:zoom-in") || css.includes("cursor: zoom-in"), + "Missing compiled StyleX component styles", + ); + for (const match of css.matchAll(/url\(["']?([^\s)"']+)["']?\)/g)) await checkAsset(match[1], url); + } + } + const pages = (await readdir(root, { recursive: true })).filter((name) => name.endsWith(".html")); + for (const page of pages) { + const pageHtml = await readFile(resolve(root, page), "utf8"); + const pageUrl = new URL(`${base}${page.replace(/index\.html$/, "")}`, "https://pages.test"); + for (const match of pageHtml.matchAll(/(?:src|href)="([^"]+)"/g)) await checkAsset(match[1], pageUrl); + } + assert.ok(checked.size > 0, "No local assets in prerendered homepage"); + return { assets: checked.size, basePath: base, pages: pages.length }; +} + +if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) { + const result = await checkStatic(resolve("dist/client"), process.env.BASE_PATH); + for (const route of ["download", "download/macos", "download/windows", "download/linux"]) { + const page = await readFile(resolve("dist/client", route, "index.html"), "utf8"); + assert.match(page, /]*>Download/, `Missing prerendered download page: ${route}`); + } + console.log(`Static website verified: ${result.pages} pages, ${result.assets} assets, base path ${result.basePath}`); +} diff --git a/website/scripts/update-release.mjs b/website/scripts/update-release.mjs new file mode 100644 index 000000000..cfc1651e3 --- /dev/null +++ b/website/scripts/update-release.mjs @@ -0,0 +1,24 @@ +import { readFile, mkdir, writeFile } from "node:fs/promises"; +import { buildDownloadManifest } from "../src/lib/downloads.mjs"; + +// A saved GitHub API response can be used for a reproducible, offline refresh. +const input = process.argv[2]; +let release; +if (input) { + release = JSON.parse(await readFile(input, "utf8")); +} else { + const response = await fetch("https://api.github.com/repos/l0ng-ai/openidea/releases/latest", { + headers: { + Accept: "application/vnd.github+json", + ...(process.env.GITHUB_TOKEN ? { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` } : {}), + }, + signal: AbortSignal.timeout(30_000), + }); + if (!response.ok) throw new Error(`Unable to load the latest release (${response.status})`); + release = await response.json(); +} +const manifest = buildDownloadManifest(release); +const destination = new URL("../src/data/", import.meta.url); +await mkdir(destination, { recursive: true }); +await writeFile(new URL("release.json", destination), `${JSON.stringify(manifest, null, 2)}\n`); +console.log(`Download manifest: ${manifest.tag}, ${Object.values(manifest.packages).flat().length} installers`); diff --git a/website/src/components/DevStyles.tsx b/website/src/components/DevStyles.tsx new file mode 100644 index 000000000..ff4b96698 --- /dev/null +++ b/website/src/components/DevStyles.tsx @@ -0,0 +1,13 @@ +import { useEffect } from "react"; +import { publicAsset } from "../lib/paths.mjs"; + +// Start has no index.html entry for StyleX's automatic dev-server injection. +// Production CSS is extracted into the normal Vite stylesheet instead. +export function DevStyles() { + useEffect(() => { + if (import.meta.env.DEV) void import("virtual:stylex:css-only"); + }, []); + return import.meta.env.DEV ? ( + + ) : null; +} diff --git a/website/src/components/Downloads.tsx b/website/src/components/Downloads.tsx new file mode 100644 index 000000000..d41f68857 --- /dev/null +++ b/website/src/components/Downloads.tsx @@ -0,0 +1,143 @@ +import * as stylex from "@stylexjs/stylex"; +import manifest from "../data/release.json"; +import type { Platform } from "../lib/downloads.mjs"; +import { publicAsset } from "../lib/paths.mjs"; +import { SiteHeader, SiteFooter, docs } from "./SiteLayout"; +import { styles as shared } from "./home.stylex"; +import { styles as s } from "./download.stylex"; + +const platforms = [ + { + id: "macos", + name: "macOS", + detail: "Apple Silicon and Intel Macs.", + instruction: "Open the DMG and drag OpenIDEA into Applications. Requires macOS 11 or later.", + }, + { + id: "windows", + name: "Windows", + detail: "64-bit Intel and AMD PCs.", + instruction: + "Download the EXE and follow the setup steps. The MSI package is also available for managed installations.", + }, + { + id: "linux", + name: "Linux", + detail: "AppImage, DEB and RPM for x86_64.", + instruction: + "Make the AppImage executable, then open it. For Debian or Ubuntu, use the DEB package; for Fedora or RHEL, use the RPM package. This release contains x86_64 Linux packages.", + }, +] as const; + +function DownloadIntro({ title }: { title: string }) { + return ( +
+ +

{title}

+
+ Version {manifest.version} + + Release notes + +
+
+ ); +} + +export function DownloadsPage() { + return ( + <> + +
+ +

Choose your desktop platform.

+
+ {platforms.map((platform) => ( +
+

+ {platform.name} +

+

{platform.detail}

+ + Download for {platform.name} + +
+ ))} +
+
+ + + ); +} + +export function DownloadPlatformPage({ platform }: { platform: Platform }) { + const current = platforms.find((item) => item.id === platform)!; + const packages = manifest.packages[platform]; + return ( + <> + +
+ + +
+ {packages.map((pkg, index) => ( +
+

+ {pkg.label} +

+

{pkg.detail}

+ + Download {pkg.format} + + {(pkg.size / 1_000_000).toFixed(1)} MB +
+ ))} + {packages.length === 0 && ( +

+ Installation packages for {current.name} are not available in this release. You can build OpenIDEA from + source. +

+ )} +
+ {packages.length > 0 && ( +
+

+ Installation +

+

{current.instruction}

+
+ )} +

+ + All platforms + + {" · "} + + Build from source + +

+
+ + + ); +} diff --git a/website/src/components/Home.tsx b/website/src/components/Home.tsx new file mode 100644 index 000000000..9d58f6a0d --- /dev/null +++ b/website/src/components/Home.tsx @@ -0,0 +1,170 @@ +import * as stylex from "@stylexjs/stylex"; +import { Dialog } from "@base-ui/react/dialog"; +import { publicAsset } from "../lib/paths.mjs"; +import { styles as s } from "./home.stylex"; +import { SiteHeader, SiteFooter, repository, docs } from "./SiteLayout"; +import { useDownloadPath } from "./useDownloadPath"; + +const screenshot = publicAsset("media/debug.jpg", import.meta.env.BASE_URL); +const imageDescription = "A Rust project in OpenIDEA, paused at a breakpoint with variables visible in the debugger."; + +function ProductPreview() { + return ( + + + {imageDescription} + + + + +
+ Rust debugging in OpenIDEA + Close +
+ {imageDescription} + + Breakpoints, variable inspection and your project in one window. + +
+
+
+ ); +} + +export function Home() { + const downloads = useDownloadPath(); + return ( + <> + +
+
+ +

+ The IDE you know, +
+ rebuilt in Rust. +

+

+ An open-source IDE with the keymap, tool windows +
and Search Everywhere you already know. +

+ +
macOS, Windows and Linux
+
+
+
+

+ Keep your way of working. +

+

+ Move between your code and your tools with the habits you have built in IntelliJ IDEA. +

+
+
+
+
+ Search Everywhere{" "} + + Shift + Shift + +
+
Find files, symbols, actions and settings from one place.
+
+
+
Edit, run and debug
+
+ Code insight, breakpoints and variable inspection, with support for 60+ languages. +
+
+
+
Your tools in one window
+
+ Git, terminal, database and HTTP clients built into the workbench. +
+
+
+
+
+

+ Startup and memory. +

+

Opening freqtrade, a Python project with about 770 files.

+ + + + + + + + + + {[ + ["Project window", "0.9 s", "3.1 s"], + ["Ready, CPU settled", "1.1 s", "13.2 s"], + ["Memory, USS", "169 MB", "2011 MB"], + ].map(([name, openidea, idea]) => ( + + + + + + ))} + +
+ Measurement + + OpenIDEA + + IntelliJ IDEA +
+ 2026.2.3 +
+ {name} + {openidea}{idea}
+

+ Warm caches, median of 5 runs. Windows 11, 32-core AMD, 62 GB RAM. OpenIDEA release build from main; IDEA + with default settings and plugins. Memory includes all processes. IDEA analyses Python more deeply, so + “ready” does not mean the same work on both sides. +

+ + Read the methodology and run it yourself + +
+
+

+ Try OpenIDEA. +

+

+ Available for macOS, Windows and Linux. +
+ Open source under Apache 2.0. +

+ + + Or build from source + +
+
+ + + ); +} diff --git a/website/src/components/SiteLayout.tsx b/website/src/components/SiteLayout.tsx new file mode 100644 index 000000000..1ac50bc06 --- /dev/null +++ b/website/src/components/SiteLayout.tsx @@ -0,0 +1,59 @@ +import * as stylex from "@stylexjs/stylex"; +import { publicAsset } from "../lib/paths.mjs"; +import { useDownloadPath } from "./useDownloadPath"; +import { styles as s } from "./home.stylex"; + +export const repository = "https://github.com/l0ng-ai/openidea"; +export const docs = `${repository}#build`; + +export function SiteHeader() { + const downloadPath = useDownloadPath(); + return ( + <> + + Skip to content + +
+ + + OpenIDEA + + +
+ + ); +} + +export function SiteFooter() { + return ( +
+
+ OpenIDEA + +
+

+ Not affiliated with JetBrains. IntelliJ IDEA is a trademark of JetBrains s.r.o. +

+
+ ); +} diff --git a/website/src/components/download.stylex.ts b/website/src/components/download.stylex.ts new file mode 100644 index 000000000..bc41b7a3a --- /dev/null +++ b/website/src/components/download.stylex.ts @@ -0,0 +1,63 @@ +import * as stylex from "@stylexjs/stylex"; + +export const styles = stylex.create({ + main: { minHeight: "calc(100dvh - 220px)", paddingBottom: { default: 92, "@media (max-width: 600px)": 56 } }, + intro: { paddingTop: { default: 58, "@media (max-width: 600px)": 34 }, textAlign: "center" }, + logo: { width: 64, height: 64, display: "block", marginInline: "auto", marginBottom: 25 }, + title: { + fontSize: { default: 42, "@media (max-width: 600px)": 32 }, + fontWeight: 550, + letterSpacing: "-1.3px", + lineHeight: 1.18, + }, + version: { + display: "flex", + flexWrap: "wrap", + justifyContent: "center", + gap: "8px 20px", + color: "#a5a8af", + fontSize: 14, + marginTop: 19, + }, + notes: { textDecorationLine: "underline", textUnderlineOffset: 4, textDecorationColor: "#777b84" }, + platforms: { + display: "flex", + justifyContent: "center", + gap: { default: 28, "@media (max-width: 600px)": 22 }, + marginTop: 35, + }, + platformLink: { + color: { default: "#a5a8af", ":hover": "#dfe1e5" }, + fontSize: 14, + paddingBlock: 10, + borderBottomWidth: 1, + borderBottomStyle: "solid", + borderBottomColor: "transparent", + }, + selected: { color: "#dfe1e5", borderBottomColor: "#dfe1e5" }, + grid: { + display: "grid", + gridTemplateColumns: { default: "repeat(auto-fit, minmax(230px, 1fr))", "@media (max-width: 600px)": "1fr" }, + gap: 20, + marginTop: { default: 50, "@media (max-width: 600px)": 32 }, + }, + card: { + borderWidth: 1, + borderStyle: "solid", + borderColor: "#34363b", + borderRadius: 8, + padding: { default: 28, "@media (max-width: 600px)": 24 }, + display: "flex", + flexDirection: "column", + alignItems: "flex-start", + }, + cardTitle: { fontSize: 22, fontWeight: 550, letterSpacing: "-.4px", lineHeight: 1.4 }, + description: { color: "#a5a8af", fontSize: 14, lineHeight: 1.7, marginTop: 10, marginBottom: 25 }, + action: { marginTop: "auto", minWidth: 150 }, + size: { color: "#a5a8af", fontSize: 12, marginTop: 12 }, + install: { borderTopWidth: 1, borderTopStyle: "solid", borderTopColor: "#34363b", paddingTop: 28, marginTop: 39 }, + installTitle: { fontSize: 17, fontWeight: 550, marginBottom: 10 }, + installText: { color: "#a5a8af", fontSize: 14, lineHeight: 1.8 }, + other: { textAlign: "center", marginTop: 35, color: "#a5a8af", fontSize: 13 }, + indexCopy: { marginTop: 23, color: "#a5a8af", fontSize: 14, textAlign: "center" }, +}); diff --git a/website/src/components/home.stylex.ts b/website/src/components/home.stylex.ts new file mode 100644 index 000000000..720c76135 --- /dev/null +++ b/website/src/components/home.stylex.ts @@ -0,0 +1,285 @@ +import * as stylex from "@stylexjs/stylex"; + +export const styles = stylex.create({ + wide: { + width: { default: "min(1112px, calc(100% - 64px))", "@media (max-width: 600px)": "calc(100% - 40px)" }, + marginInline: "auto", + }, + content: { + width: { default: "min(840px, calc(100% - 48px))", "@media (max-width: 600px)": "calc(100% - 40px)" }, + marginInline: "auto", + }, + header: { + height: { default: 88, "@media (max-width: 600px)": 76 }, + display: "flex", + alignItems: "center", + justifyContent: "space-between", + }, + brand: { + display: "flex", + alignItems: "center", + gap: { default: 10, "@media (max-width: 600px)": 8 }, + fontSize: { default: 21, "@media (max-width: 600px)": 19 }, + fontWeight: 650, + letterSpacing: "-.8px", + lineHeight: 1, + }, + mark: { + width: { default: 39, "@media (max-width: 600px)": 33 }, + height: { default: 39, "@media (max-width: 600px)": 33 }, + }, + nav: { + display: "flex", + alignItems: "center", + gap: { default: 29, "@media (max-width: 600px)": 20 }, + fontSize: { default: 13, "@media (max-width: 600px)": 12 }, + color: "#a5a8af", + }, + navLink: { paddingBlock: 12, color: { default: "inherit", ":hover": "#ffffff" } }, + navDownload: { display: { default: "block", "@media (max-width: 600px)": "none" }, color: "#dfe1e5" }, + hero: { + paddingTop: { default: 34, "@media (max-width: 600px)": 23 }, + paddingBottom: { default: 104, "@media (max-width: 600px)": 65 }, + textAlign: "center", + }, + product: { + display: "block", + width: "100%", + padding: 0, + backgroundColor: "transparent", + borderWidth: 1, + borderStyle: "solid", + borderColor: "#40434a", + borderRadius: { default: 11, "@media (max-width: 600px)": 7 }, + overflow: "hidden", + lineHeight: 0, + cursor: "zoom-in", + }, + productImage: { display: "block", width: "100%", height: "auto" }, + headline: { + marginTop: { default: 32, "@media (max-width: 600px)": 31 }, + fontSize: { default: 42, "@media (max-width: 600px)": 34, "@media (max-width: 360px)": 30 }, + fontWeight: 550, + letterSpacing: { default: "-1.8px", "@media (max-width: 600px)": "-1.3px" }, + lineHeight: 1.12, + }, + description: { + color: "#a5a8af", + maxWidth: { default: 570, "@media (max-width: 600px)": 325 }, + marginInline: "auto", + marginTop: 18, + fontSize: { default: 15, "@media (max-width: 600px)": 14 }, + lineHeight: 1.75, + }, + desktopBreak: { display: { default: "inline", "@media (max-width: 600px)": "none" } }, + actions: { + display: "flex", + justifyContent: "center", + gap: { default: 12, "@media (max-width: 600px)": 10 }, + marginTop: { default: 26, "@media (max-width: 600px)": 24 }, + }, + button: { + display: "inline-flex", + alignItems: "center", + justifyContent: "center", + minHeight: { default: 45, "@media (max-width: 600px)": 46 }, + paddingBlock: { default: 10, "@media (max-width: 600px)": 12 }, + paddingInline: { default: 24, "@media (max-width: 600px)": 17, "@media (max-width: 360px)": 12 }, + borderWidth: 1, + borderStyle: "solid", + borderColor: { default: "#34363b", ":hover": "#777b84" }, + borderRadius: 6, + backgroundColor: "transparent", + color: "#dfe1e5", + fontSize: { default: 13, "@media (max-width: 600px)": 12 }, + fontWeight: 550, + lineHeight: 1.4, + textAlign: "center", + cursor: "pointer", + }, + primary: { + backgroundColor: { default: "#f5f4f1", ":hover": "#ffffff" }, + color: "#191a1c", + borderColor: { default: "#f5f4f1", ":hover": "#ffffff" }, + }, + platforms: { + marginTop: { default: 14, "@media (max-width: 600px)": 15 }, + fontSize: { default: 12, "@media (max-width: 600px)": 11 }, + color: "#a5a8af", + }, + section: { + borderTopWidth: 1, + borderTopStyle: "solid", + borderTopColor: "#34363b", + paddingBlock: { default: 62, "@media (max-width: 600px)": 42 }, + }, + heading: { + fontSize: { default: 27, "@media (max-width: 600px)": 25 }, + fontWeight: 550, + letterSpacing: { default: "-.8px", "@media (max-width: 600px)": "-.7px" }, + lineHeight: 1.3, + }, + workflow: { + display: { default: "grid", "@media (max-width: 600px)": "block" }, + gridTemplateColumns: "1fr 1fr", + gap: 76, + }, + intro: { + marginTop: { default: 17, "@media (max-width: 600px)": 14 }, + maxWidth: { default: 330, "@media (max-width: 600px)": "none" }, + color: "#a5a8af", + fontSize: { default: 15, "@media (max-width: 600px)": 14 }, + }, + workflowList: { + margin: 0, + marginTop: { default: 0, "@media (max-width: 600px)": 29 }, + display: "flex", + flexDirection: "column", + gap: { default: 23, "@media (max-width: 600px)": 25 }, + }, + term: { fontSize: { default: 15, "@media (max-width: 600px)": 14 }, fontWeight: 550, lineHeight: 1.4 }, + definition: { margin: 0, marginTop: 6, color: "#a5a8af", fontSize: 14, lineHeight: 1.65 }, + keys: { + display: "inline-flex", + gap: 5, + marginLeft: { default: 8, "@media (max-width: 600px)": 7 }, + verticalAlign: "middle", + }, + key: { + fontFamily: "Inter, Arial, sans-serif", + fontSize: { default: 12, "@media (max-width: 600px)": 11 }, + paddingBlock: 3, + paddingInline: { default: 7, "@media (max-width: 600px)": 6 }, + borderWidth: 1, + borderStyle: "solid", + borderColor: "#4b4e55", + borderRadius: 4, + whiteSpace: "nowrap", + color: "#dfe1e5", + }, + benchmarkIntro: { + marginTop: { default: 13, "@media (max-width: 600px)": 14 }, + maxWidth: 650, + color: "#a5a8af", + fontSize: { default: 15, "@media (max-width: 600px)": 14 }, + }, + table: { + width: "100%", + borderCollapse: "collapse", + marginTop: { default: 28, "@media (max-width: 600px)": 23 }, + tableLayout: "fixed", + fontSize: { default: 14, "@media (max-width: 600px)": 13 }, + }, + cell: { + paddingBlock: { default: 14, "@media (max-width: 600px)": 15 }, + paddingInline: 0, + borderBottomWidth: 1, + borderBottomStyle: "solid", + borderBottomColor: "#34363b", + textAlign: "right", + fontWeight: 400, + fontVariantNumeric: "tabular-nums", + }, + columnHeading: { + fontSize: { default: 12, "@media (max-width: 600px)": 11 }, + color: "#a5a8af", + verticalAlign: "bottom", + lineHeight: 1.5, + }, + measurement: { + width: { default: "44%", "@media (max-width: 600px)": "41%" }, + textAlign: "left", + paddingRight: { default: 0, "@media (max-width: 600px)": 12 }, + }, + result: { fontWeight: 550 }, + muted: { color: "#a5a8af" }, + conditions: { + maxWidth: 760, + marginTop: { default: 23, "@media (max-width: 600px)": 22 }, + fontSize: { default: 12, "@media (max-width: 600px)": 11 }, + lineHeight: { default: 1.75, "@media (max-width: 600px)": 1.85 }, + color: "#a5a8af", + }, + textLink: { + display: "inline-block", + marginTop: { default: 15, "@media (max-width: 600px)": 16 }, + fontSize: { default: 13, "@media (max-width: 600px)": 12 }, + textDecorationLine: "underline", + textUnderlineOffset: 4, + textDecorationColor: "#777b84", + color: { default: "inherit", ":hover": "#ffffff" }, + }, + getStarted: { + textAlign: "center", + paddingTop: { default: 66, "@media (max-width: 600px)": 48 }, + paddingBottom: { default: 76, "@media (max-width: 600px)": 52 }, + }, + downloadCopy: { + maxWidth: { default: 480, "@media (max-width: 600px)": 300 }, + marginInline: "auto", + marginTop: 16, + color: "#a5a8af", + fontSize: { default: 15, "@media (max-width: 600px)": 14 }, + }, + downloadActions: { + marginTop: { default: 23, "@media (max-width: 600px)": 24 }, + flexDirection: { default: "row", "@media (max-width: 600px)": "column" }, + alignItems: "center", + }, + downloadButton: { minWidth: { default: "auto", "@media (max-width: 600px)": 200 } }, + sourceLink: { color: "#a5a8af", marginTop: 18 }, + footer: { + borderTopWidth: 1, + borderTopStyle: "solid", + borderTopColor: "#34363b", + paddingTop: { default: 25, "@media (max-width: 600px)": 23 }, + paddingBottom: { default: 32, "@media (max-width: 600px)": 28 }, + color: "#a5a8af", + fontSize: 11, + lineHeight: 1.7, + }, + footerMain: { + display: { default: "flex", "@media (max-width: 600px)": "block" }, + justifyContent: "space-between", + gap: 20, + }, + footerLinks: { display: "flex", gap: 23, marginTop: { default: 0, "@media (max-width: 600px)": 15 } }, + trademark: { + marginTop: { default: 14, "@media (max-width: 600px)": 18 }, + fontSize: 10, + color: "#9498a1", + maxWidth: { default: "none", "@media (max-width: 600px)": 310 }, + }, + skipLink: { + position: "fixed", + top: 8, + left: 8, + padding: 12, + backgroundColor: "#f5f4f1", + color: "#191a1c", + borderRadius: 4, + zIndex: 100, + transform: { default: "translateY(-150%)", ":focus": "translateY(0)" }, + }, + backdrop: { position: "fixed", inset: 0, backgroundColor: "rgb(0 0 0 / .85)", zIndex: 10 }, + popup: { + position: "fixed", + top: "50%", + left: "50%", + transform: "translate(-50%, -50%)", + width: "min(1400px, calc(100vw - 32px))", + maxHeight: "calc(100dvh - 32px)", + overflow: "auto", + backgroundColor: "#191a1c", + borderWidth: 1, + borderStyle: "solid", + borderColor: "#40434a", + borderRadius: 8, + padding: 16, + zIndex: 11, + }, + dialogHeader: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16, marginBottom: 16 }, + dialogTitle: { fontSize: 15, fontWeight: 550, lineHeight: 1.4 }, + dialogImage: { display: "block", width: "100%", height: "auto", borderRadius: 4 }, + dialogDescription: { fontSize: 12, color: "#a5a8af", marginTop: 12 }, +}); diff --git a/website/src/components/useDownloadPath.ts b/website/src/components/useDownloadPath.ts new file mode 100644 index 000000000..92f2904a7 --- /dev/null +++ b/website/src/components/useDownloadPath.ts @@ -0,0 +1,12 @@ +import { useSyncExternalStore } from "react"; +import { detectDesktopPlatform } from "../lib/downloads.mjs"; +import { publicAsset } from "../lib/paths.mjs"; + +const subscribe = () => () => undefined; +const serverPlatform = () => null; +const browserPlatform = () => detectDesktopPlatform(navigator.userAgent, navigator.maxTouchPoints); + +export function useDownloadPath() { + const platform = useSyncExternalStore(subscribe, browserPlatform, serverPlatform); + return publicAsset(platform ? `download/${platform}/` : "download/", import.meta.env.BASE_URL); +} diff --git a/website/src/data/release.json b/website/src/data/release.json new file mode 100644 index 000000000..42e2be3aa --- /dev/null +++ b/website/src/data/release.json @@ -0,0 +1,76 @@ +{ + "version": "0.1.24", + "tag": "v0.1.24", + "releaseUrl": "https://github.com/l0ng-ai/openidea/releases/tag/v0.1.24", + "packages": { + "macos": [ + { + "id": "mac-arm", + "label": "Apple Silicon", + "detail": "Macs with an Apple Silicon processor", + "format": "DMG", + "url": "https://github.com/l0ng-ai/openidea/releases/download/v0.1.24/OpenIDEA_0.1.24_aarch64.dmg", + "name": "OpenIDEA_0.1.24_aarch64.dmg", + "size": 43591698 + }, + { + "id": "mac-intel", + "label": "Intel", + "detail": "Macs with an Intel processor", + "format": "DMG", + "url": "https://github.com/l0ng-ai/openidea/releases/download/v0.1.24/OpenIDEA_0.1.24_x64.dmg", + "name": "OpenIDEA_0.1.24_x64.dmg", + "size": 47708074 + } + ], + "windows": [ + { + "id": "windows-exe", + "label": "Windows installer", + "detail": "64-bit Intel and AMD PCs", + "format": "EXE", + "url": "https://github.com/l0ng-ai/openidea/releases/download/v0.1.24/OpenIDEA_0.1.24_x64-setup.exe", + "name": "OpenIDEA_0.1.24_x64-setup.exe", + "size": 36126071 + }, + { + "id": "windows-msi", + "label": "MSI package", + "detail": "64-bit installer for managed deployments", + "format": "MSI", + "url": "https://github.com/l0ng-ai/openidea/releases/download/v0.1.24/OpenIDEA_0.1.24_x64_en-US.msi", + "name": "OpenIDEA_0.1.24_x64_en-US.msi", + "size": 48439296 + } + ], + "linux": [ + { + "id": "linux-appimage", + "label": "AppImage", + "detail": "Standalone app for x86_64 Linux", + "format": "AppImage", + "url": "https://github.com/l0ng-ai/openidea/releases/download/v0.1.24/OpenIDEA_0.1.24_amd64.AppImage", + "name": "OpenIDEA_0.1.24_amd64.AppImage", + "size": 122984952 + }, + { + "id": "linux-deb", + "label": "Debian / Ubuntu", + "detail": "DEB package for x86_64", + "format": "DEB", + "url": "https://github.com/l0ng-ai/openidea/releases/download/v0.1.24/OpenIDEA_0.1.24_amd64.deb", + "name": "OpenIDEA_0.1.24_amd64.deb", + "size": 48842078 + }, + { + "id": "linux-rpm", + "label": "Fedora / RHEL", + "detail": "RPM package for x86_64", + "format": "RPM", + "url": "https://github.com/l0ng-ai/openidea/releases/download/v0.1.24/OpenIDEA-0.1.24-1.x86_64.rpm", + "name": "OpenIDEA-0.1.24-1.x86_64.rpm", + "size": 48845523 + } + ] + } +} diff --git a/website/src/env.d.ts b/website/src/env.d.ts new file mode 100644 index 000000000..07a2fa814 --- /dev/null +++ b/website/src/env.d.ts @@ -0,0 +1,2 @@ +/// +declare module "virtual:stylex:css-only"; diff --git a/website/src/lib/downloads.mjs b/website/src/lib/downloads.mjs new file mode 100644 index 000000000..67569cf9a --- /dev/null +++ b/website/src/lib/downloads.mjs @@ -0,0 +1,103 @@ +/** @typedef {"macos" | "windows" | "linux"} Platform */ +/** @typedef {{id:string,label:string,detail:string,format:string,url:string,name:string,size:number}} DownloadPackage */ +/** @typedef {{tag_name:string,html_url:string,draft?:boolean,prerelease?:boolean,assets:{name:string,browser_download_url:string,size:number}[]}} Release */ + +/** @param {string} userAgent @param {number} [touchPoints] @returns {Platform | null} */ +export function detectDesktopPlatform(userAgent, touchPoints = 0) { + if (/Android|iPhone|iPad|iPod|Windows Phone|CrOS/i.test(userAgent)) return null; + if (/Macintosh|Mac OS X/i.test(userAgent)) return touchPoints > 1 ? null : "macos"; + if (/Windows NT/i.test(userAgent)) return "windows"; + if (/Linux/i.test(userAgent)) return "linux"; + return null; +} + +/** @type {{platform:Platform,id:string,label:string,detail:string,format:string,pattern:RegExp}[]} */ +const installers = [ + { + platform: "macos", + id: "mac-arm", + label: "Apple Silicon", + detail: "Macs with an Apple Silicon processor", + format: "DMG", + pattern: /^OpenIDEA.*_(?:aarch64|arm64)\.dmg$/i, + }, + { + platform: "macos", + id: "mac-intel", + label: "Intel", + detail: "Macs with an Intel processor", + format: "DMG", + pattern: /^OpenIDEA.*_x64\.dmg$/i, + }, + { + platform: "windows", + id: "windows-exe", + label: "Windows installer", + detail: "64-bit Intel and AMD PCs", + format: "EXE", + pattern: /^OpenIDEA.*_x64-setup\.exe$/i, + }, + { + platform: "windows", + id: "windows-msi", + label: "MSI package", + detail: "64-bit installer for managed deployments", + format: "MSI", + pattern: /^OpenIDEA.*_x64(?:_[\w-]+)?\.msi$/i, + }, + { + platform: "linux", + id: "linux-appimage", + label: "AppImage", + detail: "Standalone app for x86_64 Linux", + format: "AppImage", + pattern: /^OpenIDEA.*_amd64\.AppImage$/i, + }, + { + platform: "linux", + id: "linux-deb", + label: "Debian / Ubuntu", + detail: "DEB package for x86_64", + format: "DEB", + pattern: /^OpenIDEA.*_amd64\.deb$/i, + }, + { + platform: "linux", + id: "linux-rpm", + label: "Fedora / RHEL", + detail: "RPM package for x86_64", + format: "RPM", + pattern: /^OpenIDEA.*\.x86_64\.rpm$/i, + }, +]; + +/** @param {Release} release */ +export function buildDownloadManifest(release) { + if (release.draft || release.prerelease || !/^v?\d+\.\d+\.\d+$/.test(release.tag_name)) { + throw new Error("Expected a published stable release"); + } + const prefix = `https://github.com/l0ng-ai/openidea/releases/download/${release.tag_name}/`; + /** @type {Record} */ + const packages = { macos: [], windows: [], linux: [] }; + for (const installer of installers) { + const asset = release.assets.find((item) => installer.pattern.test(item.name)); + if (!asset) continue; + if ( + !asset.browser_download_url.startsWith(prefix) || + decodeURIComponent(new URL(asset.browser_download_url).pathname.split("/").pop() ?? "") !== asset.name + ) { + throw new Error(`Unexpected download URL for ${asset.name}`); + } + packages[installer.platform].push({ + id: installer.id, + label: installer.label, + detail: installer.detail, + format: installer.format, + url: asset.browser_download_url, + name: asset.name, + size: asset.size, + }); + } + if (!Object.values(packages).some((items) => items.length)) throw new Error("No desktop installers in release"); + return { version: release.tag_name.replace(/^v/, ""), tag: release.tag_name, releaseUrl: release.html_url, packages }; +} diff --git a/website/src/lib/metadata.ts b/website/src/lib/metadata.ts new file mode 100644 index 000000000..2351fc45a --- /dev/null +++ b/website/src/lib/metadata.ts @@ -0,0 +1,7 @@ +export function pageHead(title: string, path = "") { + const siteUrl = import.meta.env.VITE_SITE_URL?.replace(/\/$/, ""); + return { + meta: [{ title: `${title} — OpenIDEA` }], + links: siteUrl ? [{ rel: "canonical", href: `${siteUrl}/${path}` }] : [], + }; +} diff --git a/website/src/lib/paths.mjs b/website/src/lib/paths.mjs new file mode 100644 index 000000000..75bac603d --- /dev/null +++ b/website/src/lib/paths.mjs @@ -0,0 +1,10 @@ +/** @param {string} [path] */ +export function normalizeBasePath(path = "/") { + const clean = path.replace(/^\/+|\/+$/g, ""); + return clean ? `/${clean}/` : "/"; +} + +/** @param {string} asset @param {string} [basePath] */ +export function publicAsset(asset, basePath = "/") { + return `${normalizeBasePath(basePath)}${asset.replace(/^\/+/, "")}`; +} diff --git a/website/src/router.tsx b/website/src/router.tsx new file mode 100644 index 000000000..8d38a831c --- /dev/null +++ b/website/src/router.tsx @@ -0,0 +1,16 @@ +import { createRouter } from "@tanstack/react-router"; +import { routeTree } from "./routeTree.gen"; + +export function getRouter() { + return createRouter({ + routeTree, + basepath: import.meta.env.BASE_URL, + scrollRestoration: true, + }); +} + +declare module "@tanstack/react-router" { + interface Register { + router: ReturnType; + } +} diff --git a/website/src/routes/__root.tsx b/website/src/routes/__root.tsx new file mode 100644 index 000000000..b96fa37c3 --- /dev/null +++ b/website/src/routes/__root.tsx @@ -0,0 +1,37 @@ +import { createRootRoute, HeadContent, Outlet, Scripts } from "@tanstack/react-router"; +import { publicAsset } from "../lib/paths.mjs"; +import { DevStyles } from "../components/DevStyles"; +import "../styles/global.css"; + +export const Route = createRootRoute({ + head: () => ({ + meta: [ + { charSet: "utf-8" }, + { name: "viewport", content: "width=device-width, initial-scale=1" }, + { title: "OpenIDEA — The IDE you know, rebuilt in Rust." }, + { + name: "description", + content: + "An open-source IDE with the keymap, tool windows and Search Everywhere you already know. Built with a Rust core for macOS, Windows and Linux.", + }, + { name: "theme-color", content: "#191a1c" }, + ], + links: [{ rel: "icon", type: "image/svg+xml", href: publicAsset("mark.svg", import.meta.env.BASE_URL) }], + }), + component: Root, +}); + +function Root() { + return ( + + + + + + + + + + + ); +} diff --git a/website/src/routes/download.index.tsx b/website/src/routes/download.index.tsx new file mode 100644 index 000000000..9d3e12b5f --- /dev/null +++ b/website/src/routes/download.index.tsx @@ -0,0 +1,8 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { DownloadsPage } from "../components/Downloads"; +import { pageHead } from "../lib/metadata"; + +export const Route = createFileRoute("/download/")({ + head: () => pageHead("Download", "download/"), + component: DownloadsPage, +}); diff --git a/website/src/routes/download.linux.tsx b/website/src/routes/download.linux.tsx new file mode 100644 index 000000000..ee2a8b727 --- /dev/null +++ b/website/src/routes/download.linux.tsx @@ -0,0 +1,8 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { DownloadPlatformPage } from "../components/Downloads"; +import { pageHead } from "../lib/metadata"; + +export const Route = createFileRoute("/download/linux")({ + head: () => pageHead("Download for Linux", "download/linux/"), + component: () => , +}); diff --git a/website/src/routes/download.macos.tsx b/website/src/routes/download.macos.tsx new file mode 100644 index 000000000..8ee515f32 --- /dev/null +++ b/website/src/routes/download.macos.tsx @@ -0,0 +1,8 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { DownloadPlatformPage } from "../components/Downloads"; +import { pageHead } from "../lib/metadata"; + +export const Route = createFileRoute("/download/macos")({ + head: () => pageHead("Download for macOS", "download/macos/"), + component: () => , +}); diff --git a/website/src/routes/download.windows.tsx b/website/src/routes/download.windows.tsx new file mode 100644 index 000000000..3fd987ae1 --- /dev/null +++ b/website/src/routes/download.windows.tsx @@ -0,0 +1,8 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { DownloadPlatformPage } from "../components/Downloads"; +import { pageHead } from "../lib/metadata"; + +export const Route = createFileRoute("/download/windows")({ + head: () => pageHead("Download for Windows", "download/windows/"), + component: () => , +}); diff --git a/website/src/routes/index.tsx b/website/src/routes/index.tsx new file mode 100644 index 000000000..0f08f587b --- /dev/null +++ b/website/src/routes/index.tsx @@ -0,0 +1,8 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { Home } from "../components/Home"; +import { pageHead } from "../lib/metadata"; + +export const Route = createFileRoute("/")({ + head: () => pageHead("The IDE you know, rebuilt in Rust."), + component: Home, +}); diff --git a/website/src/styles/global.css b/website/src/styles/global.css new file mode 100644 index 000000000..1239a89ac --- /dev/null +++ b/website/src/styles/global.css @@ -0,0 +1,45 @@ +@font-face { + font-family: Inter; + src: url("/fonts/inter-latin-wght-normal.woff2") format("woff2"); + font-style: normal; + font-weight: 100 900; + font-display: swap; +} + +@layer reset { + * { + box-sizing: border-box; + } + html { + color-scheme: dark; + background: #191a1c; + } + body { + margin: 0; + color: #dfe1e5; + font: + 15px/1.7 Inter, + Arial, + sans-serif; + -webkit-font-smoothing: antialiased; + } + p, + h1, + h2, + h3, + figure { + margin: 0; + } + a { + color: inherit; + text-decoration: none; + } + button { + font: inherit; + color: inherit; + } + :focus-visible { + outline: 2px solid #dfe1e5; + outline-offset: 5px; + } +} diff --git a/website/tests/downloads.test.mjs b/website/tests/downloads.test.mjs new file mode 100644 index 000000000..148737441 --- /dev/null +++ b/website/tests/downloads.test.mjs @@ -0,0 +1,73 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { detectDesktopPlatform, buildDownloadManifest } from "../src/lib/downloads.mjs"; + +test("detects desktop platforms without guessing mobile devices are desktops", () => { + assert.equal(detectDesktopPlatform("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"), "macos"); + assert.equal(detectDesktopPlatform("Mozilla/5.0 (Windows NT 10.0; Win64; x64)"), "windows"); + assert.equal(detectDesktopPlatform("Mozilla/5.0 (X11; Linux x86_64)"), "linux"); + assert.equal(detectDesktopPlatform("Mozilla/5.0 (Linux; Android 15)"), null); + assert.equal(detectDesktopPlatform("Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X)"), null); + assert.equal(detectDesktopPlatform("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)", 5), null); + assert.equal(detectDesktopPlatform("Mozilla/5.0 (X11; CrOS x86_64)"), null); + assert.equal(detectDesktopPlatform("Mozilla/5.0 (X11; FreeBSD amd64)"), null); + assert.equal(detectDesktopPlatform(""), null); +}); + +function release(names) { + return { + tag_name: "v0.1.24", + html_url: "https://github.com/l0ng-ai/openidea/releases/tag/v0.1.24", + assets: names.map((name) => ({ + name, + size: 1234, + browser_download_url: `https://github.com/l0ng-ai/openidea/releases/download/v0.1.24/${name}`, + })), + }; +} + +test("maps real installer assets to platform-specific direct downloads", () => { + const result = buildDownloadManifest( + release([ + "OpenIDEA_0.1.24_aarch64.dmg", + "OpenIDEA_0.1.24_x64.dmg", + "OpenIDEA_0.1.24_x64-setup.exe", + "OpenIDEA_0.1.24_x64_en-US.msi", + "OpenIDEA_0.1.24_amd64.AppImage", + "OpenIDEA_0.1.24_amd64.deb", + "OpenIDEA-0.1.24-1.x86_64.rpm", + "OpenIDEA_0.1.24_amd64.AppImage.sig", + "openidea-server-linux-aarch64.gz", + "latest.json", + ]), + ); + assert.equal(result.version, "0.1.24"); + assert.deepEqual( + result.packages.macos.map((p) => p.label), + ["Apple Silicon", "Intel"], + ); + assert.deepEqual( + result.packages.windows.map((p) => p.format), + ["EXE", "MSI"], + ); + assert.deepEqual( + result.packages.linux.map((p) => p.format), + ["AppImage", "DEB", "RPM"], + ); + assert.ok(result.packages.macos[0].url.endsWith("/OpenIDEA_0.1.24_aarch64.dmg")); + assert.equal(Object.values(result.packages).flat().length, 7); +}); + +test("does not invent download links for missing platform packages", () => { + const result = buildDownloadManifest(release(["OpenIDEA_0.1.24_aarch64.dmg"])); + assert.deepEqual(result.packages.windows, []); + assert.deepEqual(result.packages.linux, []); +}); + +test("rejects draft or prerelease data and untrusted installer destinations", () => { + const data = release(["OpenIDEA_0.1.24_aarch64.dmg"]); + assert.throws(() => buildDownloadManifest({ ...data, draft: true }), /stable/i); + assert.throws(() => buildDownloadManifest({ ...data, prerelease: true }), /stable/i); + data.assets[0].browser_download_url = "https://example.com/installer.dmg"; + assert.throws(() => buildDownloadManifest(data), /download URL/i); +}); diff --git a/website/tests/paths.test.mjs b/website/tests/paths.test.mjs new file mode 100644 index 000000000..e76a60ae6 --- /dev/null +++ b/website/tests/paths.test.mjs @@ -0,0 +1,16 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { normalizeBasePath, publicAsset } from "../src/lib/paths.mjs"; + +test("normalizes both repository Pages and custom-domain roots", () => { + assert.equal(normalizeBasePath(), "/"); + assert.equal(normalizeBasePath(""), "/"); + assert.equal(normalizeBasePath("/openidea"), "/openidea/"); + assert.equal(normalizeBasePath("/openidea/"), "/openidea/"); +}); + +test("keeps public media under the deployed repository prefix", () => { + assert.equal(publicAsset("media/debug.jpg", "/openidea/"), "/openidea/media/debug.jpg"); + assert.equal(publicAsset("/media/debug.jpg", "/openidea"), "/openidea/media/debug.jpg"); + assert.equal(publicAsset("media/debug.jpg", "/"), "/media/debug.jpg"); +}); diff --git a/website/tests/static.test.mjs b/website/tests/static.test.mjs new file mode 100644 index 000000000..01c8d6cdc --- /dev/null +++ b/website/tests/static.test.mjs @@ -0,0 +1,53 @@ +import assert from "node:assert/strict"; +import { mkdtemp, mkdir, writeFile, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import test from "node:test"; +import { checkStatic } from "../scripts/check-static.mjs"; + +async function fixture(t, body, css = ".x{cursor:zoom-in}") { + const root = await mkdtemp(join(tmpdir(), "openidea-pages-")); + t.after(() => rm(root, { recursive: true, force: true })); + await mkdir(join(root, "assets")); + await writeFile(join(root, "assets/site.css"), css); + await writeFile( + join(root, "index.html"), + `OpenIDEA${body}`, + ); + return root; +} + +const content = `

The IDE you know,
rebuilt in Rust.

Keep your way of working.

Startup and memory.

169 MB. Warm caches, median of 5 runs. IDEA analyses Python more deeply.

Try OpenIDEA.

`; + +test("rejects a client-only shell instead of publishing an empty homepage", async (t) => { + const root = await fixture(t, '
'); + await assert.rejects(checkStatic(root, "/openidea/"), /prerendered homepage/i); +}); + +test("rejects public media that escaped the GitHub Pages prefix", async (t) => { + const root = await fixture(t, `${content}IDE`); + await assert.rejects(checkStatic(root, "/openidea/"), /base path/i); +}); + +test("rejects missing deployment assets", async (t) => { + const root = await fixture(t, `${content}IDE`); + await assert.rejects(checkStatic(root, "/openidea/"), /missing asset/i); +}); + +test("checks a complete static page without needing a server", async (t) => { + const root = await fixture(t, content); + assert.equal((await checkStatic(root, "/openidea/")).assets, 1); +}); + +test("rejects a linked download directory without a prerendered index", async (t) => { + const root = await fixture(t, `${content}Download`); + await mkdir(join(root, "download/macos"), { recursive: true }); + await assert.rejects(checkStatic(root, "/openidea/"), /missing.*index/i); +}); + +test("also checks local assets referenced from platform download pages", async (t) => { + const root = await fixture(t, `${content}Download`); + await mkdir(join(root, "download")); + await writeFile(join(root, "download/index.html"), '

Download OpenIDEA

'); + await assert.rejects(checkStatic(root, "/openidea/"), /missing asset/i); +}); diff --git a/website/tsconfig.json b/website/tsconfig.json new file mode 100644 index 000000000..471d19ba6 --- /dev/null +++ b/website/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "jsx": "react-jsx", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "skipLibCheck": true, + "noEmit": true, + "allowJs": true, + "resolveJsonModule": true, + "checkJs": true, + "types": ["vite/client", "node"] + }, + "include": ["src", "vite.config.ts"] +} diff --git a/website/vite.config.ts b/website/vite.config.ts new file mode 100644 index 000000000..46b7b3310 --- /dev/null +++ b/website/vite.config.ts @@ -0,0 +1,22 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import stylex from "@stylexjs/unplugin"; +import { tanstackStart } from "@tanstack/react-start/plugin/vite"; +import { normalizeBasePath } from "./src/lib/paths.mjs"; + +export default defineConfig(({ mode }) => ({ + base: normalizeBasePath(process.env.BASE_PATH), + plugins: [ + stylex.vite({ + devMode: "css-only", + dev: mode === "development", + // Keep atomic styles above the reset layer regardless of dev stylesheet load order. + useCSSLayers: false, + runtimeInjection: false, + }), + tanstackStart({ + prerender: { enabled: true, crawlLinks: false, failOnError: true }, + }), + react(), + ], +}));