From 440549765869cc996598a5033cec61ff405b7ead Mon Sep 17 00:00:00 2001 From: Julien Calixte Date: Thu, 2 Jul 2026 18:12:20 +0200 Subject: [PATCH] feat: scaffold blueprints SPA with List functional-blueprint illustration --- .dockerignore | 6 + .gitignore | 24 + .oxfmtrc.json | 5 + .oxlintrc.json | 11 + .vscode/extensions.json | 3 + .zed/settings.json | 31 + Dockerfile | 11 + README.md | 40 + archive/list-illustration.html | 1500 ++++++++++++++++++++++++++++ index.html | 13 + nginx.conf | 15 + package.json | 31 + pnpm-lock.yaml | 1468 +++++++++++++++++++++++++++ public/favicon.svg | 23 + src/App.vue | 446 +++++++++ src/assets/icons/README.md | 37 + src/components/CompositionMap.vue | 120 +++ src/components/FunctionReadout.vue | 124 +++ src/components/ListSpecimen.vue | 579 +++++++++++ src/components/StateMachine.vue | 165 +++ src/data/listBlueprint.ts | 318 ++++++ src/main.ts | 5 + src/style.css | 76 ++ tsconfig.app.json | 16 + tsconfig.json | 4 + tsconfig.node.json | 23 + vite.config.ts | 14 + 27 files changed, 5108 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 .oxfmtrc.json create mode 100644 .oxlintrc.json create mode 100644 .vscode/extensions.json create mode 100644 .zed/settings.json create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 archive/list-illustration.html create mode 100644 index.html create mode 100644 nginx.conf create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 public/favicon.svg create mode 100644 src/App.vue create mode 100644 src/assets/icons/README.md create mode 100644 src/components/CompositionMap.vue create mode 100644 src/components/FunctionReadout.vue create mode 100644 src/components/ListSpecimen.vue create mode 100644 src/components/StateMachine.vue create mode 100644 src/data/listBlueprint.ts create mode 100644 src/main.ts create mode 100644 src/style.css create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..587e382 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +node_modules +dist +.git +.zed +.vscode +archive diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 0000000..5d41335 --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,5 @@ +{ + "$schema": "./node_modules/oxfmt/configuration_schema.json", + "semi": false, + "singleQuote": false +} diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000..31e054f --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,11 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": ["typescript", "unicorn", "oxc"], + "categories": { + "correctness": "error" + }, + "rules": {}, + "env": { + "builtin": true + } +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..a7cea0b --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["Vue.volar"] +} diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 0000000..cb88f18 --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,31 @@ +{ + "languages": { + "TypeScript": { + "format_on_save": "on", + "formatter": { + "external": { + "command": "./node_modules/.bin/oxfmt", + "arguments": ["--stdin-filepath", "{buffer_path}"] + } + } + }, + "JavaScript": { + "format_on_save": "on", + "formatter": { + "external": { + "command": "./node_modules/.bin/oxfmt", + "arguments": ["--stdin-filepath", "{buffer_path}"] + } + } + }, + "Vue.js": { + "format_on_save": "on", + "formatter": { + "external": { + "command": "./node_modules/.bin/oxfmt", + "arguments": ["--stdin-filepath", "{buffer_path}"] + } + } + } + } +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..af20aa9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM node:22-alpine AS build +WORKDIR /app +COPY package.json pnpm-lock.yaml* ./ +RUN corepack enable && pnpm install --frozen-lockfile +COPY . . +RUN pnpm build + +FROM nginx:alpine +COPY --from=build /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 diff --git a/README.md b/README.md new file mode 100644 index 0000000..9e84cd5 --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# blueprints + +Deployed at https://blueprints.apoena.dev + +Interactive illustrations of UI-pattern **blueprints** — the formal, framework-agnostic +contracts from [`blueprint-ontology`](https://git.apoena.dev) (signature, state machine, +behaviors, invariants, critical performance, failure modes), rendered in a cyanotype +"blueprint" style: monospace, blueprint-blue paper, faint grid, amber annotations. + +The first screen illustrates the **List** blueprint and its seven functions — +Display · Scroll · Load · Filter · Sort · Select · Act — as a specimen-under-glass with a +full contract readout, an anatomy/composition map, and the `LoadState` machine. + +## Develop + +```bash +pnpm dev # frontend on :5173 +pnpm build # type-check (vue-tsc) + production build → dist/ +pnpm lint # oxlint (pnpm lint:fix to autofix) +pnpm fmt # oxfmt (pnpm fmt:check to verify only) +``` + +## Stack + +- **Vite + Vue 3 + TypeScript** SPA (no backend) +- **Tailwind v4 + DaisyUI** with a custom `blueprint` dark theme (`src/style.css`) +- **oxlint + oxfmt** for lint/format (no semicolons, double quotes) +- Served in production by **nginx** (see `Dockerfile` + `nginx.conf`) + +Blueprint content lives as typed data in `src/data/`; the viewer components render it. +Source of truth: the `list` blueprint in `blueprint-ontology` +(`blueprints/list/README.md`, `list.als`, `list.test.als`). + +The original single-file static illustration is archived at +[`archive/list-illustration.html`](archive/list-illustration.html). + +## Deploy + +Pushes to `main` are picked up by Coolify at https://platform.apoena.dev and deployed to +https://blueprints.apoena.dev. diff --git a/archive/list-illustration.html b/archive/list-illustration.html new file mode 100644 index 0000000..a603933 --- /dev/null +++ b/archive/list-illustration.html @@ -0,0 +1,1500 @@ + + + + + + List<Item> — Functional Blueprint + + + +
+ +
+
+

+ List<Item> — Functional + Blueprint +

+
+ A scrollable, ordered set of items · rendered as an interactive schematic of its 7 + functions +
+
+
+
Extends
+
Set<Item>
+
+
+
Sheet
+
1 / 1
+
+
+
Composition
+
+5 caps
+
+
+ + +
+ highlighted region — the part of the list this function + owns + skeleton placeholder + subset + assignment / effect + failure mode + critical-performance threshold +
+ + +

Functional viewer — select a function

+
+ +
+
+
+ Specimen · List<Item>FIG.00 +
+
+
+
+
Readout · Contract§ list.als
+
+
+
+ + +

Anatomy — where the 7 functions come from

+
+
+ Composition mapSet ◁ List ◁ capabilities +
+
+
+ + +

Lifecycle — LoadState machine

+
+
+ Composed state machine · List + Async + Paginated + PullableloadState : LoadState +
+
+
+ +
+
+ SOURCE  blueprint-ontology / blueprints / list  ·  + formal model: list.als, list.test.als +
+
+ READS AS  a concept (Jackson) / contract — + declarative, categorical, abstract. See BLUEPRINT-METAPHOR.md +
+
+ SCOPE  standard composition: + List + Async + Paginated + Pullable + Selectable + Filterable +
+
+
+ + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..a70141a --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + Blueprints · UI pattern contracts, illustrated + + +
+ + + diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..9b70c7f --- /dev/null +++ b/nginx.conf @@ -0,0 +1,15 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } + + location /assets/ { + expires 1y; + add_header Cache-Control "public, immutable"; + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..5a6087a --- /dev/null +++ b/package.json @@ -0,0 +1,31 @@ +{ + "name": "blueprints", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc -b && vite build", + "preview": "vite preview", + "lint": "oxlint", + "lint:fix": "oxlint --fix", + "fmt": "oxfmt", + "fmt:check": "oxfmt --check" + }, + "dependencies": { + "daisyui": "^5.6.6", + "vue": "^3.5.39" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.3.2", + "@types/node": "^24.13.2", + "@vitejs/plugin-vue": "^6.0.7", + "@vue/tsconfig": "^0.9.1", + "oxfmt": "^0.57.0", + "oxlint": "^1.72.0", + "tailwindcss": "^4.3.2", + "typescript": "~6.0.2", + "vite": "^8.1.1", + "vue-tsc": "^3.3.5" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..49f8746 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1468 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + daisyui: + specifier: ^5.6.6 + version: 5.6.6 + vue: + specifier: ^3.5.39 + version: 3.5.39(typescript@6.0.3) + devDependencies: + '@tailwindcss/vite': + specifier: ^4.3.2 + version: 4.3.2(vite@8.1.2(@types/node@24.13.2)(jiti@2.7.0)) + '@types/node': + specifier: ^24.13.2 + version: 24.13.2 + '@vitejs/plugin-vue': + specifier: ^6.0.7 + version: 6.0.7(vite@8.1.2(@types/node@24.13.2)(jiti@2.7.0))(vue@3.5.39(typescript@6.0.3)) + '@vue/tsconfig': + specifier: ^0.9.1 + version: 0.9.1(typescript@6.0.3)(vue@3.5.39(typescript@6.0.3)) + oxfmt: + specifier: ^0.57.0 + version: 0.57.0 + oxlint: + specifier: ^1.72.0 + version: 1.72.0 + tailwindcss: + specifier: ^4.3.2 + version: 4.3.2 + typescript: + specifier: ~6.0.2 + version: 6.0.3 + vite: + specifier: ^8.1.1 + version: 8.1.2(@types/node@24.13.2)(jiti@2.7.0) + vue-tsc: + specifier: ^3.3.5 + version: 3.3.6(typescript@6.0.3) + +packages: + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + 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/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@emnapi/core@1.11.1': + resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} + + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@napi-rs/wasm-runtime@1.1.6': + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@oxc-project/types@0.138.0': + resolution: {integrity: sha512-1a7ZKmrRTCoN1XMZ4L0PyyqrMnrNlLyPuOkdSX2MZg7IiIGRUyurNhAm73ptDOraoBcIordsIGKNPKUzy3ZmfA==} + + '@oxfmt/binding-android-arm-eabi@0.57.0': + resolution: {integrity: sha512-qVBsEO+KugOsCmUHcO8iqNnqc65p7PCKpCs8M66mPZ+Ri+CWbcpoQOEJBg2OTu03+0qu++NK1jj6IzvQVs0Sig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxfmt/binding-android-arm64@0.57.0': + resolution: {integrity: sha512-mp6PibWbao3aizijcheOeHQaYEhcUAt8pwLniYbtLfHxL/psFF0BykAwCj+s3c6qIpa8yN8keZICWrqtZ70w8g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxfmt/binding-darwin-arm64@0.57.0': + resolution: {integrity: sha512-T+0stuCBqmUVY+aMIvrgXhzGhHO3sD5tNiiEcYqgSdPsnukskQqn2u5qOVD0sv1l7RLdFS5Z/f5Wi9Ktyjr3Eg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxfmt/binding-darwin-x64@0.57.0': + resolution: {integrity: sha512-O+3JbqWs/mCI2oi4xfhRO2IVPFJNDDEBV8Odo+ZpmsUOeKJfjXoNH7nDmBEQcDgK7NfjDIyE7kRgYSZcTLDO0A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxfmt/binding-freebsd-x64@0.57.0': + resolution: {integrity: sha512-pxwhxVC+JkLX9twOQ/8C/vbuOQcMZyKIDmiRDZfO7yITuVcIdZCiLRqqf4QOxb2+8FWrRXzQpm+1DBKcMpHSSQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxfmt/binding-linux-arm-gnueabihf@0.57.0': + resolution: {integrity: sha512-pxBU4zH2imB/MDBfth2rOMeVxXUMjRQLCazagwLARIFH3hVlxZJBlM4nSnHXaIHJK4/qezoFCIORN6AY8Mra4A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxfmt/binding-linux-arm-musleabihf@0.57.0': + resolution: {integrity: sha512-JAprOzt8tycYou36ZgEw14DlRHTiN8qdtKANdV3VZIRIvTI/lh/cX13c9pJ/EnDk2GT3FASH7KvCgQ2AufAifQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxfmt/binding-linux-arm64-gnu@0.57.0': + resolution: {integrity: sha512-ajtjaxSaj9xl4BW7REt+Cef/ttzbAq00Bq4z7JUDZEfgFXdwSjH8K9bF+IcIJzZB9lKqMfQ4eHuSFOvvlvtqOg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-arm64-musl@0.57.0': + resolution: {integrity: sha512-p4Y/+RYk9Bk5WO+zHSUXAClRmZ2fbJCejMuCAsU2HhyME4jqf6Ftt/mJYEwIah1wGCBDYOB7wEGV1x5bCEZ6hA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxfmt/binding-linux-ppc64-gnu@0.57.0': + resolution: {integrity: sha512-By6tRALAZsno0F4zedmtG+wdMvJiJmJoXM4d3+A9zHE4HRXLqXITwRH8mgrlcXc5yJM2g2W3riRPwTYdgemZLQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-riscv64-gnu@0.57.0': + resolution: {integrity: sha512-skYeG+RgvyzspqVEBsEprL90OYYZfoVNqB3HcCNR6QDJyXKOzfDRT3zncnHmUaFluIlBHuY23mU1b5WGgR98hA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-riscv64-musl@0.57.0': + resolution: {integrity: sha512-FFgACrZOXAXUh5KQh2mt1CDOVOZmn+QzHP71wM9QobNwyQvoFfyAeefVUltW83g3sm7LTiH3yfFqLLVUpA5ZFQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxfmt/binding-linux-s390x-gnu@0.57.0': + resolution: {integrity: sha512-Nm/BAOfQeFiiKd502mZn/GAVKJwtd0RdCg17G3Wz/WSOIQmDi3+7/SZH4BHn1Ye5KvTVH3ua8WvfwLLycNIuvA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-x64-gnu@0.57.0': + resolution: {integrity: sha512-BiSy5Ku3mQqyxS6YIqAJgd403wEUWvI7kerfzPxc2l/txZVmZM0pSj7oDM+4bGBExowxOi7o73jEam1W0EDTZg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-x64-musl@0.57.0': + resolution: {integrity: sha512-BCRkJiotz5s9afLYD2LuMvzAoDYx9H17E/YbDyu4xK7l4zHDPeny9ErSXL//i/nJyaOwRk08x4b8cgJC00+JDg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxfmt/binding-openharmony-arm64@0.57.0': + resolution: {integrity: sha512-4Oaxe1qrGgXfpCJ1C/ERJ2iCtV2rN1R79ga9fsfyVHfSQRu/hVW780u2KDqZWFZ/iGTHODJji0JemxqFZ63eIQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxfmt/binding-win32-arm64-msvc@0.57.0': + resolution: {integrity: sha512-MYLAsDnhdNsSGheLYhWgbk0vfIrlS84iQYun/y21fX6u0jj8iBtYtbpZMdiqYeuf8U12eVPUjVY2xE2NrCfJ0g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxfmt/binding-win32-ia32-msvc@0.57.0': + resolution: {integrity: sha512-PBwdzZALJY/jcCx2E6is0yu+cuVXeySTDmwuseD+9j0mHqlRNxwlKgsyRTBed/woPeqfVfuXfWjoq4Cx2Zt3Eg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxfmt/binding-win32-x64-msvc@0.57.0': + resolution: {integrity: sha512-bQJdH9i4RRfw55jm7+8/xS7GzHLLTbHx4huhrrDxQJaJtbSDbsyOnODvP1ftT7EG0KFKAYO2S+q6AcioXODx8w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@oxlint/binding-android-arm-eabi@1.72.0': + resolution: {integrity: sha512-zhCmvn+1Mj3UchAc/90i99S0t7jJUsHmFVSPg4UWrjO8b8eaSGwscgO6QAUtvHBstkjQwBttQNswEnAF1mIQdA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxlint/binding-android-arm64@1.72.0': + resolution: {integrity: sha512-mtH+aY/ozv1eZoCUC2owjFAtyNBKHpJHygKeEu9zXXnQGW1Q2/qOpvx+I+Lf23+TvTz66F4iiXUbl2cGvoLPCQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxlint/binding-darwin-arm64@1.72.0': + resolution: {integrity: sha512-EvnajNPDtfknB3ZieeOOyDTwJn9QXDiwfnF4ZDQqART6RG6hjY4WigQcZdGoK2dkB3e1vrmEzN9aYbQCUkh/gQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxlint/binding-darwin-x64@1.72.0': + resolution: {integrity: sha512-ZkCdEa/G80A7vEHfeCDz/+L3m33DE73v32mDKhgOIgz8Uwf0DFcK7+uu6qC+7LEhmz5fpOe1osWKyjSNMydFIQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxlint/binding-freebsd-x64@1.72.0': + resolution: {integrity: sha512-NroXv2vh+sxVY1uya/rM5pjhx1hm8BzlYpx9q67QP0Xhw5MH2bf5GJylpvLEC+781p1Xli/317EoV9AlGwViag==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxlint/binding-linux-arm-gnueabihf@1.72.0': + resolution: {integrity: sha512-0NDywYgfj279Ou/BcQuCYSj7NJwBfmWn5qc5uGO/Ny7fUWmXyIpvawqX/8acQlWG6IXelJsJhj+JAy6sjsKj0A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxlint/binding-linux-arm-musleabihf@1.72.0': + resolution: {integrity: sha512-4vpXB06h65Ezsy4hRyrGjGrfa1SkVPii09yaajiYhmVpgsFiLD+KNxIx/BNAY+XiO+i1yqp9HHdwqM8VTqa5XQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxlint/binding-linux-arm64-gnu@1.72.0': + resolution: {integrity: sha512-immaN4g2ZGFiOkKrvRX9LvzZdd2GkQM5wR+UyzYyUuyhUTXGQ4HKUJH18xp4G8OfhCVaVAJfKZxwE1r8+4hhaQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-arm64-musl@1.72.0': + resolution: {integrity: sha512-JGHS9Mnr7iWyyLDxgCv1MhzVpAckgptg00F2gnxt/GD7lQ2SW1BRcxHqhSTaSdDpjWRrBkBxMMh4+Hn3aVtExg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxlint/binding-linux-ppc64-gnu@1.72.0': + resolution: {integrity: sha512-AOYgBZqxNshrg83P9v0RYv+m8s10Cqkj4/PxXFDhcS3k7FqsIG5+CxErshZCIN7G8iy4Y+VGfAsuEdar8AcbBg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-riscv64-gnu@1.72.0': + resolution: {integrity: sha512-QMybPS5ij3/vrKG67mqzHwW++91sYxK/PPUVi6SBtNCEzW4niS52fVBdXbQ6nou0wWbUPEpx8Sl/ZjtgE3clXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-riscv64-musl@1.72.0': + resolution: {integrity: sha512-gOc3W7JV0PXRpIL7stUlLe3Wa9Gp0Kdlup87IT3gHDvPKck2xNgMIl/Gs2lldYY2lyXZDC4rWi3hmoLUobkgbQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxlint/binding-linux-s390x-gnu@1.72.0': + resolution: {integrity: sha512-rpGxph+FjjHcYI5q6uxB3Az+tnfmEnDbSA8+PK9ZE/VzyUAkvBOMeuY7ZQMhu5mpZH7YQDsTdW6Cx4kV/msc6w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-x64-gnu@1.72.0': + resolution: {integrity: sha512-WND+uhf/Ko13SLqQMWQUgsZuLvYYEvL0ZKgg0tgGYfLqxG7l8Ju123fHDMJyYSDl5E3bUbpFUuii/OvMreFQzw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-x64-musl@1.72.0': + resolution: {integrity: sha512-SrpbrUL70nG9vh6zP4/oKHWgLuHquwsr7MW9XOn0olBVgh10Uqr8qscKhQoBGEn6olK/IUpn5GSKcdQ5AjUhGA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxlint/binding-openharmony-arm64@1.72.0': + resolution: {integrity: sha512-qkrsEn6NmgFKr7U/QnezQMb+q/vzAy0Dd9Y95gQGQTyjzDLN+HRZMuM5u70iyH4nBLCfKBzhjMsYCehKay2jyg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxlint/binding-win32-arm64-msvc@1.72.0': + resolution: {integrity: sha512-LWR6ZlFZph+KPjXv8opgZsXRDCdrdQe8VL8Cg9zxCoBS73h6znzZpydVgmdnwj8mB9AuSM5jxEgDJDpQkjboeg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxlint/binding-win32-ia32-msvc@1.72.0': + resolution: {integrity: sha512-yt6HEh7IsHvtjRWtmeZRX134eaXKHq5Gnqlf1xBJdJl1JtdoRUEJw3nAxpZoUDS860cX/foKbztO441anVBtVQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxlint/binding-win32-x64-msvc@1.72.0': + resolution: {integrity: sha512-b2eKFD2hX7tIwmo/cyH6TDq8vzWRZ2qNHrzoGntUTmq0h3zQh/uX3eTSHCwI8OB/ADQfJCRelLItK8BsxuucDA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/binding-android-arm64@1.1.4': + resolution: {integrity: sha512-EZLpf/8y7GXkkra90ML47kzik/GMP3EMcE9bPyHmRfxLC6z9+aW5A8poCsoxjrT5GfEcNAAvWwUHjvP1pUQkfw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.1.4': + resolution: {integrity: sha512-aUi+HBvmYb7j8krl1+qJgkG8C17fO79gk3c+jPw4S8glRFc1DTija9S3EyaTSQUm5GJXYKDAsugBEhFHH2vYiQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.1.4': + resolution: {integrity: sha512-F7hHC3gwY11+vByKPRWqwGbeXWVgKmL+pTGCinaEhdihzBV2aQ0fvZOch9cXYUOKuKKq429HeYXOqQLc7wFCEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.1.4': + resolution: {integrity: sha512-sI5yw+7s92SK6odiEhD5lKCBlWcpjHS5qyqpVQbZAJ0fIzEUXrmbl3DH2ybR3PZogulNJF+COLtmA8hUfvkCCQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.1.4': + resolution: {integrity: sha512-mCi0OKgEieFircrtVYmQAFGszRtMnZ6fpZAXrxanXAu7lqZcsK1E1RAaZNG0uKAnxox3B1f4EyQNnoyMfN1vAA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.1.4': + resolution: {integrity: sha512-B9Ial3Kv5sh0SHnB1g/QWcUQCEvCF6QKGAl4zXypYj65mVI+B4AhFBwPtSN7pDrJeIx8Z7zdy4ntx+wQABom7w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.1.4': + resolution: {integrity: sha512-lZVym0PuHE1KZ22gmFTC15lAkrg9iTszR617oYRB/iPY1A56ywoJzVKOJBKaot5RiikCObmur6pogpse3gRcng==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.1.4': + resolution: {integrity: sha512-t2DNiLJWNTbnEHyUzTumldML6ET4/g16467LZoDDJ3tSxGvguL5/NyC2lCsNKuyRycg9XeDQF5SSv+TNOhQEXg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.1.4': + resolution: {integrity: sha512-0WIRnL1Uw4BvTZRLQt+PVgo6ZKTJadlC2btP+/EOXv2f/DWbY0rEgl+y834mIVwP1FkTlWVTrGGJXf12lru7EQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.1.4': + resolution: {integrity: sha512-JWtGshGfX+oENAKonoNkqEJX+7hC8yfhi9GUyPX1VX4mdh1y5r+ZiJLR5XzAB0aoP6s/PcILsGjKq8O0mm24bw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.1.4': + resolution: {integrity: sha512-rT6yQcxUuXs4CnbofqwHRRV0iem349rLMYpTjkgQGLjrY4ado/eDzwPZPTCgTOlF6Nkp8NEv70yLMTn6qkWxsQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.1.4': + resolution: {integrity: sha512-KXMGoboq5cyaCQjDA4GLuRiOwBQ0EyFnJoVViLeZ45/3rFItRODEr+NdsBcVpll40hhNArlm/speWGRvj08LzA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.1.4': + resolution: {integrity: sha512-5K83rb36oJiY7BCyE9zLZtGcPV4g5wvq+xwdO0XPIwDVZI8cyB/AUjkNXGb92/rnmezEkjMOpgY61rtwjQtFwg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.1.4': + resolution: {integrity: sha512-PnWBtw3TV5KOg69HQQDR0mnQuyCmSGR2pAB4DC1rPF808fgKeTUMj2EOEyKATpgiuxuR5APQmiDO7PDgEjTFSA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.1.4': + resolution: {integrity: sha512-M1lpniBePobTfsa7Ks9a199e1akxsXn+GYBUKsEzv3YFzOm1HJAMNwKI3qr0Zq+mxwx9gOZoTdP1yXRYsZUocQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@tailwindcss/node@4.3.2': + resolution: {integrity: sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg==} + + '@tailwindcss/oxide-android-arm64@4.3.2': + resolution: {integrity: sha512-WHxqIuHpvZ5VtdX6GTl1Ik/Vp2YuN42Et+0CdeaVd/frQ9jAvGmvR8vLT+jk3e8/Q3x8kECB9+R17pgpp2BulA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.2': + resolution: {integrity: sha512-GZypeUY/IDJW3877KeM+O67vbXr3MBnbtEL4aYhNErv/JWZhye2vGSWWG9tB6iiqR2MqRNkY8IOUy4NdSZV26w==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.2': + resolution: {integrity: sha512-UIIzmefR6KO1sDU7MzRqAxC8iBpft/VhkGjTjnhoS6k7Z3rQ9wEgA1ODSiyH/tcSYssulNm4Ci3hOeK1jH7ccQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.2': + resolution: {integrity: sha512-GN+uAmcI6DNspnCDwtOAZrTz6oukJnp337qZvxqCGLd3BHBzJpO0ZbTLRvJNdztOeAmTzewewGIMPb0tk2R4WA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.2': + resolution: {integrity: sha512-4ABn7qSbdHRwTiDiuWNegCyb5+2FJ4vKIKc3DmKrvAFw7MU1Lm11dIkTPwUaFdTzc7IsOpDbqBrlh0x6y36U/w==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.2': + resolution: {integrity: sha512-wDgEIGwoM8w8pufh9LVt1PahDgNdKXrLC2qfAnV3vAmococ9RWbxeAw4pxPttd/TsJfwjyLf90Dg1y9y8I6Emw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.2': + resolution: {integrity: sha512-J5Nuk0uZQIiMTJj3LEx4sAA9tMFUoXQZFv1J6An+QGYe53HKRJuFDi0rpq/tuouCZeAbOBY3kQ6g8qeD4TUjtA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.2': + resolution: {integrity: sha512-kqCZpSKOBEJO4mz7OqWoofBZeXTAwaVGPj0ErAj7CojmhKpWVWVOnrt9dE8odoIraZq4oj3ausM37kXi+Tow8w==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.3.2': + resolution: {integrity: sha512-cixpqbh2toJDmkuCRI68nXA8ZxNmdK9Y+9v5h3MC3ZQKy/0BO8AWzlkWyRM7JAFSGBlfig4YVTPsK6MVgqz1uw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.3.2': + resolution: {integrity: sha512-4ec2Z/LOmRsAgU23CS4xeJfcJlmRg94A/XrbGRCF1gyU/zdDfRLYDVsS+ynSZCmGNxQ1jQriQOKMQeQxBA3Isw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.2': + resolution: {integrity: sha512-Zyr/M0+XcYZu3bZrUytc7TXvrk0ftWfl8gN2MwekNDzhqhKRUucMPSeOzM0o0wH5AWOU49BsKRrfKxI2atCPMQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.2': + resolution: {integrity: sha512-QI9BO7KlNZsp2GuO0jwAAj5jCDABOKXRkCk2XuKTSaNEFSdfzqswYVTtCHBNKHLsqyjFyFkqlDiwkNbTYSssMQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.2': + resolution: {integrity: sha512-z8ZgnzX8gdNoWLBLqBPoh/sjnxkwvf9ZuWjnO0l0yIzbLa5/9S+eC5QxGZKRobVHIC3/1BoMWjHblqWjcgFgag==} + engines: {node: '>= 20'} + + '@tailwindcss/vite@4.3.2': + resolution: {integrity: sha512-eHpMeX4JXfVNJDEcsouTeCBubJBTcTLigeaw/NTUW6PB5ATKKXdyonnXgTBX2VuRbjz1hjfz6C5XAhr52ImQXA==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 || ^8 + + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + + '@types/node@24.13.2': + resolution: {integrity: sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==} + + '@vitejs/plugin-vue@6.0.7': + resolution: {integrity: sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + vue: ^3.2.25 + + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + + '@vue/compiler-core@3.5.39': + resolution: {integrity: sha512-16KBTEXAJCpDr0mwlw+AZyhu8iyC7R3S2vBwsI7QnWJU6X3WKc9VKeNEZpiMdZ569qWhz9574L3vV55qRL0Vtw==} + + '@vue/compiler-dom@3.5.39': + resolution: {integrity: sha512-oQPigALqYbNxTNPvNgSOe+czwVExfbVF02lz8jP0S3AXJiu3jxYDygNUiqSep4ezzW8XgnubqH63My2A7JR/vg==} + + '@vue/compiler-sfc@3.5.39': + resolution: {integrity: sha512-d0ki86iOyN8LoZPBmk5SJWNwHP19CnDDCfuo//+2WJa2g5Ke0Jay983PIBIcSSzldC68I8DrD5GrHV3OSDfodg==} + + '@vue/compiler-ssr@3.5.39': + resolution: {integrity: sha512-Ce7/wvwMHai74bdszfXExdazFigYnlF9zgCmEQUcM1j0fOymlouZ7XilTYNo8oUjhlnjYOZbGrcYKuqjz89Ucw==} + + '@vue/language-core@3.3.6': + resolution: {integrity: sha512-LgBMZAy2sR3cQWknpyaxnI6yBkqDfLBPkbdhwRhQCvzfNJRQXPilgQIrdI/v4ytJ0sAq9bWhaPsjqBqneomJ3Q==} + + '@vue/reactivity@3.5.39': + resolution: {integrity: sha512-TpsuBJ9gGlZa5d23XcM2y8EXanz9dZeVDQBXRwzy46ItgvM+rWpzs+UVM0wcRLxGvcav0HE5jz2gNL53xlRAog==} + + '@vue/runtime-core@3.5.39': + resolution: {integrity: sha512-9GLtNyRvPAUMbX+7ono0RC2j0guo2LXVi8LvcmAooImACUKm0oFf0jjwbX8/H0AE/t1nxhAkn8RSl9PMCzzxZw==} + + '@vue/runtime-dom@3.5.39': + resolution: {integrity: sha512-7Y6aAGboKcXAZ3ECuUy7RrS5yy2r47dhTp2SKaJmYxjopImaVFaNa5Ne66NwGovsrxVAl5S5rwc7m22UG7Lmww==} + + '@vue/server-renderer@3.5.39': + resolution: {integrity: sha512-yZSakiAGw85rZfG7UM8akMnIF+FmeiNk47uvHf2nVBBSe+dIKUhZuZq9+XgJhbV3nS5Z4ALH23/MpXofW+mbcw==} + peerDependencies: + vue: 3.5.39 + + '@vue/shared@3.5.39': + resolution: {integrity: sha512-l1rrBtBfTnmxvtsvdQDXltUUy8S1Y+ZaqdfUzmAnJkTd8Z8rv5v/ytW+TKiqEOWyHPoqtPlNFSs0lhRmYVSHVA==} + + '@vue/tsconfig@0.9.1': + resolution: {integrity: sha512-buvjm+9NzLCJL29KY1j1991YYJ5e6275OiK+G4jtmfIb+z4POywbdm0wXusT9adVWqe0xqg70TbI7+mRx4uU9w==} + peerDependencies: + typescript: '>= 5.8' + vue: ^3.4.0 + peerDependenciesMeta: + typescript: + optional: true + vue: + optional: true + + alien-signals@3.2.1: + resolution: {integrity: sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + daisyui@5.6.6: + resolution: {integrity: sha512-UFiuIZYucF7ylrnY3PT1SqwaEbVB10mqTZRyeRchZk0bud+HihYLLhXdxGDVmR/ftrM9G9YVr9FFPRVVIZJ5hA==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + enhanced-resolve@5.21.6: + resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==} + engines: {node: '>=10.13.0'} + + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + nanoid@3.3.15: + resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + oxfmt@0.57.0: + resolution: {integrity: sha512-ZB7Bi+rGDSqmVIo9jwcLyFgjxXvQhDdU+jx+ZrVy6VRiVXK2+CHc4hO3J4dUQjHe7V0ymHB+MDuv5z+NhK07HA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + svelte: ^5.0.0 + vite-plus: '*' + peerDependenciesMeta: + svelte: + optional: true + vite-plus: + optional: true + + oxlint@1.72.0: + resolution: {integrity: sha512-1rhdZIP/EvoI91ABIwNU5Q8+bWf8mjrS5UzIOZld4d4bXxJvtlUhlQvaoTogIGin/qdErMOrwaIJvCSIAKTLhA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + oxlint-tsgolint: '>=0.22.1' + vite-plus: '*' + peerDependenciesMeta: + oxlint-tsgolint: + optional: true + vite-plus: + optional: true + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + postcss@8.5.16: + resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==} + engines: {node: ^10 || ^12 || >=14} + + rolldown@1.1.4: + resolution: {integrity: sha512-IjZYiLxZwpnhwhdBH2ugdTGVSdhCQUmLxLoqyjiL0JxYjyRst+5a0P3xfrTxJ5F638j4Mvvw5FAX5XE6eHpXbA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + tailwindcss@4.3.2: + resolution: {integrity: sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinypool@2.1.0: + resolution: {integrity: sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==} + engines: {node: ^20.0.0 || >=22.0.0} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + vite@8.1.2: + resolution: {integrity: sha512-6YYPbRXTxx6bRXmOn7XdnQAy5DQNHhDgtjhDHI13oe4pY93kkcdGJWxpGwOm++/Wh0QpQhDrpIoVMrmrsI5AGQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.3.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 + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + + vue-tsc@3.3.6: + resolution: {integrity: sha512-ERXGgbKSBGFUkavrJ1Iwj0ZVxKqB/5UOx65IXy7fPf2UsoI21n3ssQLwdvx8xyUGgJe9PvSZTM/FYzIdwUDPFA==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + + vue@3.5.39: + resolution: {integrity: sha512-xmZCYabFGcirU8r0fTuvl/LICc1OU620rnqepaJDL/a141ZigkG7AyaxQLdqJ02ZRYzWe6YPaDHeQx7MfknQfA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + +snapshots: + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@emnapi/core@1.11.1': + dependencies: + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@tybys/wasm-util': 0.10.3 + optional: true + + '@oxc-project/types@0.138.0': {} + + '@oxfmt/binding-android-arm-eabi@0.57.0': + optional: true + + '@oxfmt/binding-android-arm64@0.57.0': + optional: true + + '@oxfmt/binding-darwin-arm64@0.57.0': + optional: true + + '@oxfmt/binding-darwin-x64@0.57.0': + optional: true + + '@oxfmt/binding-freebsd-x64@0.57.0': + optional: true + + '@oxfmt/binding-linux-arm-gnueabihf@0.57.0': + optional: true + + '@oxfmt/binding-linux-arm-musleabihf@0.57.0': + optional: true + + '@oxfmt/binding-linux-arm64-gnu@0.57.0': + optional: true + + '@oxfmt/binding-linux-arm64-musl@0.57.0': + optional: true + + '@oxfmt/binding-linux-ppc64-gnu@0.57.0': + optional: true + + '@oxfmt/binding-linux-riscv64-gnu@0.57.0': + optional: true + + '@oxfmt/binding-linux-riscv64-musl@0.57.0': + optional: true + + '@oxfmt/binding-linux-s390x-gnu@0.57.0': + optional: true + + '@oxfmt/binding-linux-x64-gnu@0.57.0': + optional: true + + '@oxfmt/binding-linux-x64-musl@0.57.0': + optional: true + + '@oxfmt/binding-openharmony-arm64@0.57.0': + optional: true + + '@oxfmt/binding-win32-arm64-msvc@0.57.0': + optional: true + + '@oxfmt/binding-win32-ia32-msvc@0.57.0': + optional: true + + '@oxfmt/binding-win32-x64-msvc@0.57.0': + optional: true + + '@oxlint/binding-android-arm-eabi@1.72.0': + optional: true + + '@oxlint/binding-android-arm64@1.72.0': + optional: true + + '@oxlint/binding-darwin-arm64@1.72.0': + optional: true + + '@oxlint/binding-darwin-x64@1.72.0': + optional: true + + '@oxlint/binding-freebsd-x64@1.72.0': + optional: true + + '@oxlint/binding-linux-arm-gnueabihf@1.72.0': + optional: true + + '@oxlint/binding-linux-arm-musleabihf@1.72.0': + optional: true + + '@oxlint/binding-linux-arm64-gnu@1.72.0': + optional: true + + '@oxlint/binding-linux-arm64-musl@1.72.0': + optional: true + + '@oxlint/binding-linux-ppc64-gnu@1.72.0': + optional: true + + '@oxlint/binding-linux-riscv64-gnu@1.72.0': + optional: true + + '@oxlint/binding-linux-riscv64-musl@1.72.0': + optional: true + + '@oxlint/binding-linux-s390x-gnu@1.72.0': + optional: true + + '@oxlint/binding-linux-x64-gnu@1.72.0': + optional: true + + '@oxlint/binding-linux-x64-musl@1.72.0': + optional: true + + '@oxlint/binding-openharmony-arm64@1.72.0': + optional: true + + '@oxlint/binding-win32-arm64-msvc@1.72.0': + optional: true + + '@oxlint/binding-win32-ia32-msvc@1.72.0': + optional: true + + '@oxlint/binding-win32-x64-msvc@1.72.0': + optional: true + + '@rolldown/binding-android-arm64@1.1.4': + optional: true + + '@rolldown/binding-darwin-arm64@1.1.4': + optional: true + + '@rolldown/binding-darwin-x64@1.1.4': + optional: true + + '@rolldown/binding-freebsd-x64@1.1.4': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.1.4': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.1.4': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.1.4': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.1.4': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.1.4': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.1.4': + optional: true + + '@rolldown/binding-linux-x64-musl@1.1.4': + optional: true + + '@rolldown/binding-openharmony-arm64@1.1.4': + optional: true + + '@rolldown/binding-wasm32-wasi@1.1.4': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.1.4': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.1.4': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@tailwindcss/node@4.3.2': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.21.6 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.2 + + '@tailwindcss/oxide-android-arm64@4.3.2': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.2': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.2': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.2': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.2': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.2': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.2': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.2': + optional: true + + '@tailwindcss/oxide@4.3.2': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.2 + '@tailwindcss/oxide-darwin-arm64': 4.3.2 + '@tailwindcss/oxide-darwin-x64': 4.3.2 + '@tailwindcss/oxide-freebsd-x64': 4.3.2 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.2 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.2 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.2 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.2 + '@tailwindcss/oxide-linux-x64-musl': 4.3.2 + '@tailwindcss/oxide-wasm32-wasi': 4.3.2 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.2 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.2 + + '@tailwindcss/vite@4.3.2(vite@8.1.2(@types/node@24.13.2)(jiti@2.7.0))': + dependencies: + '@tailwindcss/node': 4.3.2 + '@tailwindcss/oxide': 4.3.2 + tailwindcss: 4.3.2 + vite: 8.1.2(@types/node@24.13.2)(jiti@2.7.0) + + '@tybys/wasm-util@0.10.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/node@24.13.2': + dependencies: + undici-types: 7.18.2 + + '@vitejs/plugin-vue@6.0.7(vite@8.1.2(@types/node@24.13.2)(jiti@2.7.0))(vue@3.5.39(typescript@6.0.3))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 8.1.2(@types/node@24.13.2)(jiti@2.7.0) + vue: 3.5.39(typescript@6.0.3) + + '@volar/language-core@2.4.28': + dependencies: + '@volar/source-map': 2.4.28 + + '@volar/source-map@2.4.28': {} + + '@volar/typescript@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@vue/compiler-core@3.5.39': + dependencies: + '@babel/parser': 7.29.7 + '@vue/shared': 3.5.39 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.39': + dependencies: + '@vue/compiler-core': 3.5.39 + '@vue/shared': 3.5.39 + + '@vue/compiler-sfc@3.5.39': + dependencies: + '@babel/parser': 7.29.7 + '@vue/compiler-core': 3.5.39 + '@vue/compiler-dom': 3.5.39 + '@vue/compiler-ssr': 3.5.39 + '@vue/shared': 3.5.39 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.16 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.39': + dependencies: + '@vue/compiler-dom': 3.5.39 + '@vue/shared': 3.5.39 + + '@vue/language-core@3.3.6': + dependencies: + '@volar/language-core': 2.4.28 + '@vue/compiler-dom': 3.5.39 + '@vue/shared': 3.5.39 + alien-signals: 3.2.1 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + picomatch: 4.0.4 + + '@vue/reactivity@3.5.39': + dependencies: + '@vue/shared': 3.5.39 + + '@vue/runtime-core@3.5.39': + dependencies: + '@vue/reactivity': 3.5.39 + '@vue/shared': 3.5.39 + + '@vue/runtime-dom@3.5.39': + dependencies: + '@vue/reactivity': 3.5.39 + '@vue/runtime-core': 3.5.39 + '@vue/shared': 3.5.39 + csstype: 3.2.3 + + '@vue/server-renderer@3.5.39(vue@3.5.39(typescript@6.0.3))': + dependencies: + '@vue/compiler-ssr': 3.5.39 + '@vue/shared': 3.5.39 + vue: 3.5.39(typescript@6.0.3) + + '@vue/shared@3.5.39': {} + + '@vue/tsconfig@0.9.1(typescript@6.0.3)(vue@3.5.39(typescript@6.0.3))': + optionalDependencies: + typescript: 6.0.3 + vue: 3.5.39(typescript@6.0.3) + + alien-signals@3.2.1: {} + + csstype@3.2.3: {} + + daisyui@5.6.6: {} + + detect-libc@2.1.2: {} + + enhanced-resolve@5.21.6: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + entities@7.0.1: {} + + estree-walker@2.0.2: {} + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + fsevents@2.3.3: + optional: true + + graceful-fs@4.2.11: {} + + jiti@2.7.0: {} + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + muggle-string@0.4.1: {} + + nanoid@3.3.15: {} + + oxfmt@0.57.0: + dependencies: + tinypool: 2.1.0 + optionalDependencies: + '@oxfmt/binding-android-arm-eabi': 0.57.0 + '@oxfmt/binding-android-arm64': 0.57.0 + '@oxfmt/binding-darwin-arm64': 0.57.0 + '@oxfmt/binding-darwin-x64': 0.57.0 + '@oxfmt/binding-freebsd-x64': 0.57.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.57.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.57.0 + '@oxfmt/binding-linux-arm64-gnu': 0.57.0 + '@oxfmt/binding-linux-arm64-musl': 0.57.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.57.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.57.0 + '@oxfmt/binding-linux-riscv64-musl': 0.57.0 + '@oxfmt/binding-linux-s390x-gnu': 0.57.0 + '@oxfmt/binding-linux-x64-gnu': 0.57.0 + '@oxfmt/binding-linux-x64-musl': 0.57.0 + '@oxfmt/binding-openharmony-arm64': 0.57.0 + '@oxfmt/binding-win32-arm64-msvc': 0.57.0 + '@oxfmt/binding-win32-ia32-msvc': 0.57.0 + '@oxfmt/binding-win32-x64-msvc': 0.57.0 + + oxlint@1.72.0: + optionalDependencies: + '@oxlint/binding-android-arm-eabi': 1.72.0 + '@oxlint/binding-android-arm64': 1.72.0 + '@oxlint/binding-darwin-arm64': 1.72.0 + '@oxlint/binding-darwin-x64': 1.72.0 + '@oxlint/binding-freebsd-x64': 1.72.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.72.0 + '@oxlint/binding-linux-arm-musleabihf': 1.72.0 + '@oxlint/binding-linux-arm64-gnu': 1.72.0 + '@oxlint/binding-linux-arm64-musl': 1.72.0 + '@oxlint/binding-linux-ppc64-gnu': 1.72.0 + '@oxlint/binding-linux-riscv64-gnu': 1.72.0 + '@oxlint/binding-linux-riscv64-musl': 1.72.0 + '@oxlint/binding-linux-s390x-gnu': 1.72.0 + '@oxlint/binding-linux-x64-gnu': 1.72.0 + '@oxlint/binding-linux-x64-musl': 1.72.0 + '@oxlint/binding-openharmony-arm64': 1.72.0 + '@oxlint/binding-win32-arm64-msvc': 1.72.0 + '@oxlint/binding-win32-ia32-msvc': 1.72.0 + '@oxlint/binding-win32-x64-msvc': 1.72.0 + + path-browserify@1.0.1: {} + + picocolors@1.1.1: {} + + picomatch@4.0.4: {} + + postcss@8.5.16: + dependencies: + nanoid: 3.3.15 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + rolldown@1.1.4: + dependencies: + '@oxc-project/types': 0.138.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.1.4 + '@rolldown/binding-darwin-arm64': 1.1.4 + '@rolldown/binding-darwin-x64': 1.1.4 + '@rolldown/binding-freebsd-x64': 1.1.4 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.4 + '@rolldown/binding-linux-arm64-gnu': 1.1.4 + '@rolldown/binding-linux-arm64-musl': 1.1.4 + '@rolldown/binding-linux-ppc64-gnu': 1.1.4 + '@rolldown/binding-linux-s390x-gnu': 1.1.4 + '@rolldown/binding-linux-x64-gnu': 1.1.4 + '@rolldown/binding-linux-x64-musl': 1.1.4 + '@rolldown/binding-openharmony-arm64': 1.1.4 + '@rolldown/binding-wasm32-wasi': 1.1.4 + '@rolldown/binding-win32-arm64-msvc': 1.1.4 + '@rolldown/binding-win32-x64-msvc': 1.1.4 + + source-map-js@1.2.1: {} + + tailwindcss@4.3.2: {} + + tapable@2.3.3: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tinypool@2.1.0: {} + + tslib@2.8.1: + optional: true + + typescript@6.0.3: {} + + undici-types@7.18.2: {} + + vite@8.1.2(@types/node@24.13.2)(jiti@2.7.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.16 + rolldown: 1.1.4 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 24.13.2 + fsevents: 2.3.3 + jiti: 2.7.0 + + vscode-uri@3.1.0: {} + + vue-tsc@3.3.6(typescript@6.0.3): + dependencies: + '@volar/typescript': 2.4.28 + '@vue/language-core': 3.3.6 + typescript: 6.0.3 + + vue@3.5.39(typescript@6.0.3): + dependencies: + '@vue/compiler-dom': 3.5.39 + '@vue/compiler-sfc': 3.5.39 + '@vue/runtime-dom': 3.5.39 + '@vue/server-renderer': 3.5.39(vue@3.5.39(typescript@6.0.3)) + '@vue/shared': 3.5.39 + optionalDependencies: + typescript: 6.0.3 diff --git a/public/favicon.svg b/public/favicon.svg new file mode 100644 index 0000000..3dfaa94 --- /dev/null +++ b/public/favicon.svg @@ -0,0 +1,23 @@ + + + + + + + + diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..da19907 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,446 @@ + + + + + diff --git a/src/assets/icons/README.md b/src/assets/icons/README.md new file mode 100644 index 0000000..fbac4b8 --- /dev/null +++ b/src/assets/icons/README.md @@ -0,0 +1,37 @@ +# Icons + +Reusable in-app icons. Source: https://tabler.io/icons (outline variant by default). + +## Add an icon + +1. Find the icon on https://tabler.io/icons, click it, copy the SVG (or download). +2. Save it here as `.svg` — same slug Tabler uses (`bolt.svg`, `qrcode.svg`). +3. Keep `stroke="currentColor"` in the SVG so colour follows Tailwind classes. + +## Use an icon + +Static colour (cheapest, no extra component): + +```vue + +``` + +Dynamic colour (needs `currentColor` to flow through — paste the SVG inline as a component): + +```vue + +``` + +The favicon at `public/favicon.svg` was generated from this same icon set with `currentColor` replaced by the app's primary hex at scaffold time. diff --git a/src/components/CompositionMap.vue b/src/components/CompositionMap.vue new file mode 100644 index 0000000..f12660f --- /dev/null +++ b/src/components/CompositionMap.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/src/components/FunctionReadout.vue b/src/components/FunctionReadout.vue new file mode 100644 index 0000000..35b7122 --- /dev/null +++ b/src/components/FunctionReadout.vue @@ -0,0 +1,124 @@ + + + + + diff --git a/src/components/ListSpecimen.vue b/src/components/ListSpecimen.vue new file mode 100644 index 0000000..1846e97 --- /dev/null +++ b/src/components/ListSpecimen.vue @@ -0,0 +1,579 @@ + + + + + diff --git a/src/components/StateMachine.vue b/src/components/StateMachine.vue new file mode 100644 index 0000000..9334669 --- /dev/null +++ b/src/components/StateMachine.vue @@ -0,0 +1,165 @@ + + + + + diff --git a/src/data/listBlueprint.ts b/src/data/listBlueprint.ts new file mode 100644 index 0000000..90922cd --- /dev/null +++ b/src/data/listBlueprint.ts @@ -0,0 +1,318 @@ +// The List blueprint, as data. Lifted verbatim from the blueprint-ontology +// `list` README: signature, behaviors, invariants, failure modes, performance. +// Rendered by the components under src/components as an interactive schematic. + +export interface SampleItem { + n: string + s: string +} + +export const SAMPLE: SampleItem[] = [ + { n: "Item A", s: "#a1f3 · ready" }, + { n: "Item B", s: "#b2e8 · ready" }, + { n: "Item C", s: "#c7d1 · ready" }, + { n: "Item D", s: "#d0a4 · ready" }, + { n: "Item E", s: "#e5b9 · ready" }, + { n: "Item F", s: "#f3c2 · ready" }, + { n: "Item G", s: "#01d7 · ready" }, + { n: "Item H", s: "#12e0 · ready" }, +] + +export interface SigField { + name: string + type: string + note: string +} + +export const COMPOSED_SIG: { + header: string + fields: SigField[] + types: string[] +} = { + header: "List + Async + Paginated + Pullable + Selectable + Filterable", + fields: [ + { name: "items", type: "seq Item", note: "List: ordered, loaded subset" }, + { name: "loadState", type: "LoadState", note: "Async · Paginated · Pullable" }, + { name: "totalCount", type: "Int", note: "Paginated" }, + { name: "selectionMode", type: "SelectionMode", note: "Selectable" }, + { name: "selected", type: "set Item", note: "Selectable" }, + { name: "visible", type: "set Item", note: "Filterable" }, + ], + types: [ + "LoadState = Idle | Loading | Refreshing | LoadingMore | Error", + "SelectionMode = None | Single | Multi", + ], +} + +export interface Behavior { + sig: string + pre: string + eff: string +} + +export interface BlueprintFunction { + id: string + name: string + fig: string + caps: string[] + verb: string + state: [string, string][] + behaviors: Behavior[] + invariants: string[] + failures: string[] + perf: string[] + notes: string[] +} + +export const FUNCTIONS: BlueprintFunction[] = [ + { + id: "display", + name: "Display", + fig: "01", + caps: ["List", "Async"], + verb: "Render items in order; render skeleton placeholders during initial load; handle empty, loading, and error states distinctly.", + state: [ + ["items", "seq Item"], + ["loadState", "LoadState"], + ], + behaviors: [], + invariants: ["#1 items = ∅ is a valid state (empty list, not an error)"], + failures: [ + "empty vs error conflation — network returns 0 items with 4xx; empty state treated as error, user sees wrong UI", + "skeleton / content mismatch — skeleton row dimensions differ from real item; layout shift on Loading → Idle", + ], + perf: [ + "skeleton placeholders render within 100 ms of navigation", + "real items replace the skeleton within 300 ms", + "skeleton dimensions must match real items to prevent layout shift", + ], + notes: [], + }, + { + id: "scroll", + name: "Scroll", + fig: "02", + caps: ["List"], + verb: "Allow the user to navigate the full item sequence; virtualize off-screen items.", + state: [["items", "seq Item"]], + behaviors: [], + invariants: ["items form a well-formed sequence (no duplicate indices) — l.items.isSeq"], + failures: [], + perf: [ + "60 fps minimum — off-screen items must not be rendered (virtualization required)", + "items outside the render window must release their view references (memory)", + ], + notes: [ + "Scroll is navigation, not a mutating behavior — it moves the render window over items, it does not change them.", + ], + }, + { + id: "load", + name: "Load", + fig: "03", + caps: ["Async", "Paginated", "Pullable"], + verb: "Fetch the initial page; support refresh (restart) and pagination (append).", + state: [ + ["loadState", "LoadState"], + ["totalCount", "Int"], + ], + behaviors: [ + { + sig: "refresh()", + pre: "loadState = idle", + eff: "loadState ← refreshing, reload items from page 1, selected ← ∅", + }, + { + sig: "loadMore()", + pre: "#items < totalCount, loadState = idle", + eff: "loadState ← loadingMore, append next page to items", + }, + ], + invariants: ["#6 #items ≤ totalCount", "#7 loadState = loadingMore → #items < totalCount"], + failures: [ + "duplicate load — loadMore() called while loadState = loadingMore; duplicate items appended, items loses uniqueness", + "unknown total — streaming source, totalCount never known; use CursorPaginated with a hasMore sentinel instead", + ], + perf: ["loadMore appends new items without layout shift or scroll-position jump"], + notes: [], + }, + { + id: "filter", + name: "Filter", + fig: "04", + caps: ["Filterable"], + verb: "Restrict the visible set without mutating the underlying sequence.", + state: [["visible", "set Item"]], + behaviors: [{ sig: "filter(pred)", pre: "—", eff: "visible ← { x ∈ items | pred(x) }" }], + invariants: ["#8 visible ⊆ items — filter never introduces new items"], + failures: [ + "filter after reload — predicate references old item shape; visible silently empties without error", + ], + perf: ["result updates within one frame (≤ 16 ms) for in-memory data"], + notes: [ + "Ephemeral: derives visible from items but does not mutate the sequence. Persisting a filter is a consumer concern.", + ], + }, + { + id: "sort", + name: "Sort", + fig: "05", + caps: ["Sortable"], + verb: "Reorder the sequence by a comparator without changing identity.", + state: [["items", "seq Item"]], + behaviors: [{ sig: "sort(cmp)", pre: "—", eff: "reorder items by comparator" }], + invariants: ["identity is preserved — sorting changes order, never membership"], + failures: [ + "sort invalidates cursor (CursorPaginated) — cursor is stale; must reset to NoCursor and reload from page 1", + ], + perf: [], + notes: [ + "Ephemeral alongside filter: reorders the displayed sequence without persisting the change.", + ], + }, + { + id: "select", + name: "Select", + fig: "06", + caps: ["Selectable"], + verb: "Track user intent over a subset of items (none / single / multi).", + state: [ + ["selectionMode", "SelectionMode"], + ["selected", "set Item"], + ], + behaviors: [ + { + sig: "select(x)", + pre: "x ∈ visible, selectionMode ≠ none", + eff: "selected ← selected ∪ {x}", + }, + { sig: "deselect(x)", pre: "x ∈ selected", eff: "selected ← selected \\ {x}" }, + { sig: "selectAll()", pre: "selectionMode = multi", eff: "selected ← visible" }, + { sig: "clearSelection()", pre: "—", eff: "selected ← ∅" }, + ], + invariants: [ + "#3 selected ⊆ items", + "#4 selectionMode = none → selected = ∅", + "#5 selectionMode = single → #selected ≤ 1", + ], + failures: [ + "stale selection — refresh() clears items but not selected; selected ⊄ items, invariant #3 violated", + ], + perf: [], + notes: [], + }, + { + id: "act", + name: "Act", + fig: "07", + caps: ["Swipeable", "Reorderable"], + verb: "Expose per-item contextual actions (swipe, long-press) to the consumer.", + state: [], + behaviors: [ + { + sig: "swipeAction(x, dir)", + pre: "x ∈ visible", + eff: "trigger consumer-defined contextual action", + }, + { + sig: "reorder(from, to)", + pre: "capability: reorderable = true", + eff: "swap positions in items", + }, + ], + invariants: [], + failures: [ + "reorder on filtered view — reorder operates on visible, not items; position mismatch between displayed and stored order", + ], + perf: [], + notes: ["Open question: swipe direction — left | right only, or also up | down?"], + }, +] + +export const CORE_INVARIANTS: string[] = [ + "items = ∅ is a valid state (empty list, not an error)", + "items are identity-unique — no duplicates by key", + "elems[items] = members — ordered form stays in sync with the set", +] + +// ── Composition map model ────────────────────────────────────────────────── +export interface CapNode { + id: string + label: string + sub: string + core?: boolean +} + +export const COMP_CAPS: CapNode[] = [ + { id: "core", label: "List : Set", sub: "items : seq Item", core: true }, + { id: "async", label: "Async", sub: "loadState" }, + { id: "paginated", label: "Paginated", sub: "totalCount" }, + { id: "pullable", label: "Pullable", sub: "refresh" }, + { id: "filterable", label: "Filterable", sub: "visible" }, + { id: "selectable", label: "Selectable", sub: "selected" }, + { id: "sortable", label: "Sortable", sub: "cmp" }, + { id: "swipeable", label: "Swipeable", sub: "+ Reorderable" }, +] + +export const COMP_FUNCS: string[] = ["Display", "Scroll", "Load", "Filter", "Sort", "Select", "Act"] + +export const COMP_LINKS: [string, string][] = [ + ["core", "Display"], + ["core", "Scroll"], + ["async", "Display"], + ["async", "Load"], + ["paginated", "Load"], + ["pullable", "Load"], + ["filterable", "Filter"], + ["selectable", "Select"], + ["sortable", "Sort"], + ["swipeable", "Act"], +] + +// ── LoadState machine model ──────────────────────────────────────────────── +export interface SmNode { + id: string + x: number + y: number + w: number + h: number + label: string +} + +export type SmKind = "succeed" | "fail" | "refresh" | "loadMore" + +export interface SmEdge { + from: string + to: string + label: string + kind: SmKind + off: number +} + +export const SM_NODES: SmNode[] = [ + { id: "loading", x: 70, y: 150, w: 110, h: 40, label: "Loading" }, + { id: "idle", x: 300, y: 150, w: 96, h: 40, label: "Idle" }, + { id: "refreshing", x: 520, y: 56, w: 130, h: 40, label: "Refreshing" }, + { id: "loadingmore", x: 520, y: 250, w: 140, h: 40, label: "LoadingMore" }, + { id: "error", x: 770, y: 150, w: 96, h: 40, label: "Error" }, +] + +export const SM_EDGES: SmEdge[] = [ + { from: "loading", to: "idle", label: "succeed()", kind: "succeed", off: 0 }, + { from: "loading", to: "error", label: "fail()", kind: "fail", off: 150 }, + { from: "idle", to: "refreshing", label: "refresh()", kind: "refresh", off: -16 }, + { from: "refreshing", to: "idle", label: "succeed()", kind: "succeed", off: -16 }, + { from: "idle", to: "loadingmore", label: "loadMore()", kind: "loadMore", off: 16 }, + { from: "loadingmore", to: "idle", label: "succeed()", kind: "succeed", off: 16 }, + { from: "refreshing", to: "error", label: "fail()", kind: "fail", off: 14 }, + { from: "loadingmore", to: "error", label: "fail()", kind: "fail", off: -14 }, + { from: "error", to: "refreshing", label: "refresh()", kind: "refresh", off: 70 }, +] + +export const SM_COLORS: Record = { + succeed: "#7fdca0", + fail: "#ff8f8f", + refresh: "#ffb84d", + loadMore: "#8fd0ff", + init: "#4f7099", +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..8a1724e --- /dev/null +++ b/src/main.ts @@ -0,0 +1,5 @@ +import { createApp } from "vue" +import "./style.css" +import App from "./App.vue" + +createApp(App).mount("#app") diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000..cd90865 --- /dev/null +++ b/src/style.css @@ -0,0 +1,76 @@ +/* The font @import MUST come first — before @import "tailwindcss" — because + Tailwind inlines its import into real CSS rules, and the CSS spec requires + @import to precede all other rules. If it comes second, the production build + warns ("@import must precede all rules…") and browsers silently DROP the + font import, so the custom font never loads. */ +@import url("https://api.fonts.coollabs.io/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap"); +@import "tailwindcss"; +@plugin "daisyui"; + +/* Custom cyanotype "blueprint" theme — deep blueprint-navy paper, light ink, + classic blueprint-blue primary, amber highlight accent. */ +@plugin "daisyui/theme" { + name: "blueprint"; + default: true; + prefersdark: true; + color-scheme: dark; + + --color-base-100: #0a2645; /* blueprint-navy paper */ + --color-base-200: #0d2f54; /* panel */ + --color-base-300: #123f6d; /* raised / hairlines */ + --color-base-content: #dbe9f7; + + --color-primary: #1b4f91; /* classic blueprint blue */ + --color-primary-content: #eaf3ff; + --color-secondary: #8fd0ff; /* cyan ink */ + --color-secondary-content: #061a30; + --color-accent: #ffb84d; /* amber highlight */ + --color-accent-content: #241500; + --color-neutral: #123f6d; + --color-neutral-content: #dbe9f7; + + --color-info: #8fd0ff; + --color-info-content: #061a30; + --color-success: #7fdca0; + --color-success-content: #06210f; + --color-warning: #ffb84d; + --color-warning-content: #241500; + --color-error: #ff8f8f; + --color-error-content: #2a0606; + + /* crisp, technical geometry */ + --radius-selector: 0.125rem; + --radius-field: 0.125rem; + --radius-box: 0.25rem; + --size-selector: 0.25rem; + --size-field: 0.25rem; + --border: 1px; + --depth: 0; + --noise: 0; +} + +@theme { + --font-sans: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace; + --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace; +} + +/* Blueprint grid paper, applied globally. */ +@layer base { + body { + min-height: 100svh; + background-color: var(--color-base-100); + background-image: + linear-gradient(rgba(200, 226, 255, 0.14) 1px, transparent 1px), + linear-gradient(90deg, rgba(200, 226, 255, 0.14) 1px, transparent 1px), + linear-gradient(rgba(200, 226, 255, 0.05) 1px, transparent 1px), + linear-gradient(90deg, rgba(200, 226, 255, 0.05) 1px, transparent 1px); + background-size: + 120px 120px, + 120px 120px, + 24px 24px, + 24px 24px; + background-position: -1px -1px; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } +} diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..6251a79 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "allowArbitraryExtensions": true, + "paths": { "@/*": ["./src/*"] }, + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..d32ff68 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,4 @@ +{ + "files": [], + "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..8455dcb --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "es2023", + "lib": ["ES2023"], + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "module": "nodenext", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..6736782 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,14 @@ +import { fileURLToPath, URL } from "node:url" +import { defineConfig } from "vite" +import vue from "@vitejs/plugin-vue" +import tailwindcss from "@tailwindcss/vite" + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], + resolve: { + alias: { + "@": fileURLToPath(new URL("./src", import.meta.url)), + }, + }, +})