From bac56d4755c32d7534bc6b76a809c9ffb2cace84 Mon Sep 17 00:00:00 2001 From: maamokun Date: Mon, 27 Oct 2025 08:43:09 +0900 Subject: [PATCH 01/10] WIP: solutions page --- .idea/.gitignore | 8 ++++++++ .idea/copilot.data.migration.agent.xml | 6 ++++++ .idea/copilot.data.migration.ask.xml | 6 ++++++ .idea/copilot.data.migration.ask2agent.xml | 6 ++++++ .idea/copilot.data.migration.edit.xml | 6 ++++++ .idea/misc.xml | 6 ++++++ .idea/vcs.xml | 6 ++++++ 7 files changed, 44 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/copilot.data.migration.agent.xml create mode 100644 .idea/copilot.data.migration.ask.xml create mode 100644 .idea/copilot.data.migration.ask2agent.xml create mode 100644 .idea/copilot.data.migration.edit.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/copilot.data.migration.agent.xml b/.idea/copilot.data.migration.agent.xml new file mode 100644 index 0000000..4ea72a9 --- /dev/null +++ b/.idea/copilot.data.migration.agent.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.ask.xml b/.idea/copilot.data.migration.ask.xml new file mode 100644 index 0000000..7ef04e2 --- /dev/null +++ b/.idea/copilot.data.migration.ask.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.ask2agent.xml b/.idea/copilot.data.migration.ask2agent.xml new file mode 100644 index 0000000..1f2ea11 --- /dev/null +++ b/.idea/copilot.data.migration.ask2agent.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.edit.xml b/.idea/copilot.data.migration.edit.xml new file mode 100644 index 0000000..8648f94 --- /dev/null +++ b/.idea/copilot.data.migration.edit.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..639900d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 7abd5fc2e91f00f15c0b815a12ff92475c76d9d7 Mon Sep 17 00:00:00 2001 From: maamokun Date: Mon, 27 Oct 2025 22:20:28 +0900 Subject: [PATCH 02/10] WIP: ready for full refactor --- .dockerignore | 35 - biome.json | 62 +- bun.lock | 1124 +++++++++++++++++++++++++ bun.lockb | Bin 333793 -> 0 bytes bunfig.toml | 2 - components.json | 22 + next.config.mjs | 4 +- open-next.config.ts | 8 - package.json | 107 +-- postcss.config.mjs | 6 +- renovate.json | 4 +- src/app/[locale]/about/page.tsx | 9 - src/app/[locale]/contact/page.tsx | 95 --- src/app/[locale]/cost/page.tsx | 9 - src/app/[locale]/layout.tsx | 60 +- src/app/[locale]/page.tsx | 312 +------ src/app/[locale]/solutions/page.tsx | 9 - src/app/[locale]/tech/page.tsx | 9 - src/app/[locale]/template.tsx | 201 +---- src/app/consent-manager.client.tsx | 55 ++ src/app/consent-manager.tsx | 20 + src/app/globals.css | 202 ++++- src/app/layout.tsx | 11 +- src/app/not-found.tsx | 38 +- src/components/cn.ts | 2 +- src/components/codecomp-v3v4.tsx | 67 -- src/components/fancy/NumberTicker.tsx | 88 +- src/components/fancy/code-comp.tsx | 172 ++-- src/components/fancy/icon-cloud.tsx | 642 +++++++------- src/components/fancy/marqee.tsx | 132 ++- src/components/fancy/typewriter.tsx | 231 +++-- src/components/nUI/Footer.tsx | 156 ++-- src/components/nUI/Header.tsx | 597 +++++++------ src/components/nUI/MenuToggle.tsx | 64 +- src/components/nUI/hooks.tsx | 14 +- src/components/ui/button.tsx | 57 ++ src/components/vrm.tsx | 359 ++++---- src/i18n/request.ts | 50 +- src/i18n/routing.ts | 10 +- src/imgLoader.ts | 32 +- src/lib/utils.ts | 6 + src/messages/en.json | 126 +-- src/messages/ja.json | 126 +-- src/middleware.ts | 10 - tailwind.config.ts | 63 +- tsconfig.json | 69 +- wrangler.jsonc | 45 - 47 files changed, 3081 insertions(+), 2441 deletions(-) delete mode 100644 .dockerignore create mode 100644 bun.lock delete mode 100755 bun.lockb delete mode 100644 bunfig.toml create mode 100644 components.json delete mode 100644 open-next.config.ts delete mode 100644 src/app/[locale]/about/page.tsx delete mode 100644 src/app/[locale]/contact/page.tsx delete mode 100644 src/app/[locale]/cost/page.tsx delete mode 100644 src/app/[locale]/solutions/page.tsx delete mode 100644 src/app/[locale]/tech/page.tsx create mode 100644 src/app/consent-manager.client.tsx create mode 100644 src/app/consent-manager.tsx delete mode 100644 src/components/codecomp-v3v4.tsx create mode 100644 src/components/ui/button.tsx create mode 100644 src/lib/utils.ts delete mode 100644 src/middleware.ts delete mode 100644 wrangler.jsonc diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 8f322f0..0000000 --- a/.dockerignore +++ /dev/null @@ -1,35 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env*.local - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/biome.json b/biome.json index 828ca02..5b99e54 100644 --- a/biome.json +++ b/biome.json @@ -1,24 +1,42 @@ { - "$schema": "https://biomejs.dev/schemas/1.5.1/schema.json", - "organizeImports": { - "enabled": true - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true - }, - "ignore": [".next/", "out/", ".wrangler/", ".open-next/"] - }, - "formatter": { - "enabled": true, - "indentWidth": 4, - "indentStyle": "tab", - "ignore": [".next/", "out/", ".wrangler/", ".open-next/"], - }, - "javascript": { - "formatter": { - "bracketSpacing": true - } - } + "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": true, + "includes": ["**", "!node_modules", "!.next", "!dist", "!build"] + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2 + }, + "css": { + "parser": { + "tailwindDirectives": true + } + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "suspicious": { + "noUnknownAtRules": "off" + } + }, + "domains": { + "next": "recommended", + "react": "recommended" + } + }, + "assist": { + "actions": { + "source": { + "organizeImports": "on" + } + } + } } diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..622a670 --- /dev/null +++ b/bun.lock @@ -0,0 +1,1124 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "mikn-dev", + "dependencies": { + "@c15t/nextjs": "^1.7.1", + "@c15t/scripts": "^1.0.0", + "@pixiv/three-vrm": "^3.3.4", + "@pixiv/three-vrm-animation": "^3.3.4", + "@radix-ui/react-slot": "^1.2.3", + "@react-three/fiber": "^9.1.2", + "@swetrix/nextjs": "^1.0.1", + "@tailwindcss/postcss": "^4.1.7", + "@types/three": "^0.176.0", + "caniuse-lite": "^1.0.30001664", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "daisyui": "^5.0.0", + "lucide-react": "^0.548.0", + "motion": "^11.15.0", + "next": "^16.0.0", + "next-intl": "^4.4.0", + "next-themes": "^0.4.4", + "postcss": "^8.5.3", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-icons": "^5.2.1", + "react-use": "^17.6.0", + "sharp": "^0.33.5", + "shiki": "^1.24.4", + "sonner": "^1.7.1", + "tailwind-merge": "^3.3.1", + "tailwind-variants": "^0.3.0", + "tailwindcss-animate": "^1.0.7", + "three": "^0.176.0", + "tw-animate-css": "^1.4.0", + }, + "devDependencies": { + "@biomejs/biome": "^2.3.1", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "tailwindcss": "^4.1.7", + "typescript": "^5", + }, + }, + }, + "packages": { + "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + + "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], + + "@biomejs/biome": ["@biomejs/biome@2.3.1", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.1", "@biomejs/cli-darwin-x64": "2.3.1", "@biomejs/cli-linux-arm64": "2.3.1", "@biomejs/cli-linux-arm64-musl": "2.3.1", "@biomejs/cli-linux-x64": "2.3.1", "@biomejs/cli-linux-x64-musl": "2.3.1", "@biomejs/cli-win32-arm64": "2.3.1", "@biomejs/cli-win32-x64": "2.3.1" }, "bin": { "biome": "bin/biome" } }, "sha512-A29evf1R72V5bo4o2EPxYMm5mtyGvzp2g+biZvRFx29nWebGyyeOSsDWGx3tuNNMFRepGwxmA9ZQ15mzfabK2w=="], + + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ombSf3MnTUueiYGN1SeI9tBCsDUhpWzOwS63Dove42osNh0PfE1cUtHFx6eZ1+MYCCLwXzlFlYFdrJ+U7h6LcA=="], + + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-pcOfwyoQkrkbGvXxRvZNe5qgD797IowpJPovPX5biPk2FwMEV+INZqfCaz4G5bVq9hYnjwhRMamg11U4QsRXrQ=="], + + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-td5O8pFIgLs8H1sAZsD6v+5quODihyEw4nv2R8z7swUfIK1FKk+15e4eiYVLcAE4jUqngvh4j3JCNgg0Y4o4IQ=="], + + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-+DZYv8l7FlUtTrWs1Tdt1KcNCAmRO87PyOnxKGunbWm5HKg1oZBSbIIPkjrCtDZaeqSG1DiGx7qF+CPsquQRcg=="], + + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-PYWgEO7up7XYwSAArOpzsVCiqxBCXy53gsReAb1kKYIyXaoAlhBaBMvxR/k2Rm9aTuZ662locXUmPk/Aj+Xu+Q=="], + + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-Y3Ob4nqgv38Mh+6EGHltuN+Cq8aj/gyMTJYzkFZV2AEj+9XzoXB9VNljz9pjfFNHUxvLEV4b55VWyxozQTBaUQ=="], + + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RHIG/zgo+69idUqVvV3n8+j58dKYABRpMyDmfWu2TITC+jwGPiEaT0Q3RKD+kQHiS80mpBrST0iUGeEXT0bU9A=="], + + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.1", "", { "os": "win32", "cpu": "x64" }, "sha512-izl30JJ5Dp10mi90Eko47zhxE6pYyWPcnX1NQxKpL/yMhXxf95oLTzfpu4q+MDBh/gemNqyJEwjBpe0MT5iWPA=="], + + "@c15t/backend": ["@c15t/backend@1.7.1", "", { "dependencies": { "@c15t/logger": "1.0.0", "@c15t/translations": "1.7.0", "@opentelemetry/api": "1.9.0", "@opentelemetry/resources": "^2.0.1", "@opentelemetry/sdk-node": "^0.203.0", "@opentelemetry/sdk-trace-base": "^2.0.1", "@orpc/contract": "1.8.1", "@orpc/openapi": "1.8.1", "@orpc/otel": "^1.8.1", "@orpc/server": "1.8.1", "@orpc/zod": "1.8.1", "base-x": "^5.0.1", "defu": "^6.1.4", "drizzle-orm": "^0.44.6", "fumadb": "^0.1.1", "kysely": "^0.27.6", "neverthrow": "^8.2.0", "superjson": "^2.2.2", "zod": "^4.0.17" } }, "sha512-oO+UM7fI93qb1KC+r02FCPeva+cUEySZ0S3MPbUWM5OG5vc/tz6JaPeAK9wEc1TTXszvv5zuNKrK1FYgYNcNdQ=="], + + "@c15t/logger": ["@c15t/logger@1.0.0", "", { "dependencies": { "chalk": "^5.4.1", "neverthrow": "^8.2.0", "picocolors": "^1.1.1" } }, "sha512-z2RrUnvO5bbEg/qd9iD/TqdBi04vfvALf2uovDVLJiQTNfOVUb7FM/GkPH5mugiDwErlrtVhAW8hW/2VmBXbUA=="], + + "@c15t/nextjs": ["@c15t/nextjs@1.7.1", "", { "dependencies": { "@c15t/react": "1.7.1", "@c15t/translations": "1.7.0" }, "peerDependencies": { "next": "^15.0.0 || ^14.0.0 || ^13.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-TNs9x5eKQ+vkJ9LY0h54DyGZqa4GeUMqnTSS5PC7hczA/QkyoUJkyj7agRUzZsPVBeQEVw7xXbJEhuwr8p+C5Q=="], + + "@c15t/react": ["@c15t/react@1.7.1", "", { "dependencies": { "@radix-ui/react-accordion": "1.2.4", "@radix-ui/react-slot": "1.2.0", "@radix-ui/react-switch": "1.1.4", "c15t": "1.7.1", "clsx": "2.1.1", "zustand": "^5.0.3" }, "peerDependencies": { "react": "^19.0.0 || ^19.0.0-rc || ^18.0.0 || ^17.0.0 || ^16.8.0", "react-dom": "^19.0.0 || ^19.0.0-rc || ^18.0.0 || ^17.0.0 || ^16.8.0" } }, "sha512-Ey6SUOxhf3nEiomYhRR9Axiy4Ku47zrSIDIvJ+amhHEhCS8jyJNQBdclUAggUFzvB8xVJQfGuniU6X6IzjL39Q=="], + + "@c15t/scripts": ["@c15t/scripts@1.0.0", "", {}, "sha512-mMV9BC5HqRvMm1sLzMk3B7XOfaihTfPg1eZr6XJNml5XsKtyrQgbTPHNK5bFH0HBK4jAZYKLGI87qaCJtuQURQ=="], + + "@c15t/translations": ["@c15t/translations@1.7.0", "", {}, "sha512-irrJAni2Cei56wHLmGoIoPHoXk/ygXllWs4dBF9LL0D/Ns7bvcBi/CAPCnCD1hw4FnoJ9amPqYtVKQ3sT++JaQ=="], + + "@clack/core": ["@clack/core@0.5.0", "", { "dependencies": { "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow=="], + + "@clack/prompts": ["@clack/prompts@0.11.0", "", { "dependencies": { "@clack/core": "0.5.0", "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw=="], + + "@dimforge/rapier3d-compat": ["@dimforge/rapier3d-compat@0.12.0", "", {}, "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.6.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA=="], + + "@formatjs/ecma402-abstract": ["@formatjs/ecma402-abstract@2.3.6", "", { "dependencies": { "@formatjs/fast-memoize": "2.2.7", "@formatjs/intl-localematcher": "0.6.2", "decimal.js": "^10.4.3", "tslib": "^2.8.0" } }, "sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw=="], + + "@formatjs/fast-memoize": ["@formatjs/fast-memoize@2.2.7", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ=="], + + "@formatjs/icu-messageformat-parser": ["@formatjs/icu-messageformat-parser@2.11.4", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.6", "@formatjs/icu-skeleton-parser": "1.8.16", "tslib": "^2.8.0" } }, "sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw=="], + + "@formatjs/icu-skeleton-parser": ["@formatjs/icu-skeleton-parser@1.8.16", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.6", "tslib": "^2.8.0" } }, "sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ=="], + + "@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.5.10", "", { "dependencies": { "tslib": "2" } }, "sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q=="], + + "@grpc/grpc-js": ["@grpc/grpc-js@1.14.0", "", { "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-N8Jx6PaYzcTRNzirReJCtADVoq4z7+1KQ4E70jTg/koQiMoUSN1kbNjPOqpPbhMFhfU1/l7ixspPl8dNY+FoUg=="], + + "@grpc/proto-loader": ["@grpc/proto-loader@0.8.0", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.3", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ=="], + + "@img/colour": ["@img/colour@1.0.0", "", {}, "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw=="], + + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.0.5", "", { "os": "linux", "cpu": "arm" }, "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g=="], + + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA=="], + + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg=="], + + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.0.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA=="], + + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw=="], + + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA=="], + + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw=="], + + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.0.5" }, "os": "linux", "cpu": "arm" }, "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ=="], + + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA=="], + + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.3" }, "os": "linux", "cpu": "ppc64" }, "sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ=="], + + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.0.4" }, "os": "linux", "cpu": "s390x" }, "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q=="], + + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA=="], + + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g=="], + + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw=="], + + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.33.5", "", { "dependencies": { "@emnapi/runtime": "^1.2.0" }, "cpu": "none" }, "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg=="], + + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA=="], + + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.33.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="], + + "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], + + "@next/env": ["@next/env@16.0.0", "", {}, "sha512-s5j2iFGp38QsG1LWRQaE2iUY3h1jc014/melHFfLdrsMJPqxqDQwWNwyQTcNoUSGZlCVZuM7t7JDMmSyRilsnA=="], + + "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.0.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/CntqDCnk5w2qIwMiF0a9r6+9qunZzFmU0cBX4T82LOflE72zzH6gnOjCwUXYKOBlQi8OpP/rMj8cBIr18x4TA=="], + + "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.0.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-hB4GZnJGKa8m4efvTGNyii6qs76vTNl+3dKHTCAUaksN6KjYy4iEO3Q5ira405NW2PKb3EcqWiRaL9DrYJfMHg=="], + + "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.0.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-E2IHMdE+C1k+nUgndM13/BY/iJY9KGCphCftMh7SXWcaQqExq/pJU/1Hgn8n/tFwSoLoYC/yUghOv97tAsIxqg=="], + + "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.0.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-xzgl7c7BVk4+7PDWldU+On2nlwnGgFqJ1siWp3/8S0KBBLCjonB6zwJYPtl4MUY7YZJrzzumdUpUoquu5zk8vg=="], + + "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.0.0", "", { "os": "linux", "cpu": "x64" }, "sha512-sdyOg4cbiCw7YUr0F/7ya42oiVBXLD21EYkSwN+PhE4csJH4MSXUsYyslliiiBwkM+KsuQH/y9wuxVz6s7Nstg=="], + + "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.0.0", "", { "os": "linux", "cpu": "x64" }, "sha512-IAXv3OBYqVaNOgyd3kxR4L3msuhmSy1bcchPHxDOjypG33i2yDWvGBwFD94OuuTjjTt/7cuIKtAmoOOml6kfbg=="], + + "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.0.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-bmo3ncIJKUS9PWK1JD9pEVv0yuvp1KPuOsyJTHXTv8KDrEmgV/K+U0C75rl9rhIaODcS7JEb6/7eJhdwXI0XmA=="], + + "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.0.0", "", { "os": "win32", "cpu": "x64" }, "sha512-O1cJbT+lZp+cTjYyZGiDwsOjO3UHHzSqobkPNipdlnnuPb1swfcuY6r3p8dsKU4hAIEO4cO67ZCfVVH/M1ETXA=="], + + "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + + "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], + + "@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.203.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-9B9RU0H7Ya1Dx/Rkyc4stuBZSGVQF27WigitInx2QQoj6KUpEFYPKoWjdFTunJYxmXmh17HeBvbMa1EhGyPmqQ=="], + + "@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@2.0.1", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-XuY23lSI3d4PEqKA+7SLtAgwqIfc6E/E9eAQWLN1vlpC53ybO3o6jW4BsXo1xvz9lYyyWItfQDDLzezER01mCw=="], + + "@opentelemetry/core": ["@opentelemetry/core@2.2.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw=="], + + "@opentelemetry/exporter-logs-otlp-grpc": ["@opentelemetry/exporter-logs-otlp-grpc@0.203.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-exporter-base": "0.203.0", "@opentelemetry/otlp-grpc-exporter-base": "0.203.0", "@opentelemetry/otlp-transformer": "0.203.0", "@opentelemetry/sdk-logs": "0.203.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-g/2Y2noc/l96zmM+g0LdeuyYKINyBwN6FJySoU15LHPLcMN/1a0wNk2SegwKcxrRdE7Xsm7fkIR5n6XFe3QpPw=="], + + "@opentelemetry/exporter-logs-otlp-http": ["@opentelemetry/exporter-logs-otlp-http@0.203.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.203.0", "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-exporter-base": "0.203.0", "@opentelemetry/otlp-transformer": "0.203.0", "@opentelemetry/sdk-logs": "0.203.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-s0hys1ljqlMTbXx2XiplmMJg9wG570Z5lH7wMvrZX6lcODI56sG4HL03jklF63tBeyNwK2RV1/ntXGo3HgG4Qw=="], + + "@opentelemetry/exporter-logs-otlp-proto": ["@opentelemetry/exporter-logs-otlp-proto@0.203.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.203.0", "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-exporter-base": "0.203.0", "@opentelemetry/otlp-transformer": "0.203.0", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-logs": "0.203.0", "@opentelemetry/sdk-trace-base": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-nl/7S91MXn5R1aIzoWtMKGvqxgJgepB/sH9qW0rZvZtabnsjbf8OQ1uSx3yogtvLr0GzwD596nQKz2fV7q2RBw=="], + + "@opentelemetry/exporter-metrics-otlp-grpc": ["@opentelemetry/exporter-metrics-otlp-grpc@0.203.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.1", "@opentelemetry/exporter-metrics-otlp-http": "0.203.0", "@opentelemetry/otlp-exporter-base": "0.203.0", "@opentelemetry/otlp-grpc-exporter-base": "0.203.0", "@opentelemetry/otlp-transformer": "0.203.0", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-metrics": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-FCCj9nVZpumPQSEI57jRAA89hQQgONuoC35Lt+rayWY/mzCAc6BQT7RFyFaZKJ2B7IQ8kYjOCPsF/HGFWjdQkQ=="], + + "@opentelemetry/exporter-metrics-otlp-http": ["@opentelemetry/exporter-metrics-otlp-http@0.203.0", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-exporter-base": "0.203.0", "@opentelemetry/otlp-transformer": "0.203.0", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-metrics": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-HFSW10y8lY6BTZecGNpV3GpoSy7eaO0Z6GATwZasnT4bEsILp8UJXNG5OmEsz4SdwCSYvyCbTJdNbZP3/8LGCQ=="], + + "@opentelemetry/exporter-metrics-otlp-proto": ["@opentelemetry/exporter-metrics-otlp-proto@0.203.0", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/exporter-metrics-otlp-http": "0.203.0", "@opentelemetry/otlp-exporter-base": "0.203.0", "@opentelemetry/otlp-transformer": "0.203.0", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-metrics": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-OZnhyd9npU7QbyuHXFEPVm3LnjZYifuKpT3kTnF84mXeEQ84pJJZgyLBpU4FSkSwUkt/zbMyNAI7y5+jYTWGIg=="], + + "@opentelemetry/exporter-prometheus": ["@opentelemetry/exporter-prometheus@0.203.0", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-metrics": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-2jLuNuw5m4sUj/SncDf/mFPabUxMZmmYetx5RKIMIQyPnl6G6ooFzfeE8aXNRf8YD1ZXNlCnRPcISxjveGJHNg=="], + + "@opentelemetry/exporter-trace-otlp-grpc": ["@opentelemetry/exporter-trace-otlp-grpc@0.203.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-exporter-base": "0.203.0", "@opentelemetry/otlp-grpc-exporter-base": "0.203.0", "@opentelemetry/otlp-transformer": "0.203.0", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-trace-base": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-322coOTf81bm6cAA8+ML6A+m4r2xTCdmAZzGNTboPXRzhwPt4JEmovsFAs+grpdarObd68msOJ9FfH3jxM6wqA=="], + + "@opentelemetry/exporter-trace-otlp-http": ["@opentelemetry/exporter-trace-otlp-http@0.203.0", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-exporter-base": "0.203.0", "@opentelemetry/otlp-transformer": "0.203.0", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-trace-base": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-ZDiaswNYo0yq/cy1bBLJFe691izEJ6IgNmkjm4C6kE9ub/OMQqDXORx2D2j8fzTBTxONyzusbaZlqtfmyqURPw=="], + + "@opentelemetry/exporter-trace-otlp-proto": ["@opentelemetry/exporter-trace-otlp-proto@0.203.0", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-exporter-base": "0.203.0", "@opentelemetry/otlp-transformer": "0.203.0", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-trace-base": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-1xwNTJ86L0aJmWRwENCJlH4LULMG2sOXWIVw+Szta4fkqKVY50Eo4HoVKKq6U9QEytrWCr8+zjw0q/ZOeXpcAQ=="], + + "@opentelemetry/exporter-zipkin": ["@opentelemetry/exporter-zipkin@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-trace-base": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0" } }, "sha512-a9eeyHIipfdxzCfc2XPrE+/TI3wmrZUDFtG2RRXHSbZZULAny7SyybSvaDvS77a7iib5MPiAvluwVvbGTsHxsw=="], + + "@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.203.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.203.0", "import-in-the-middle": "^1.8.1", "require-in-the-middle": "^7.1.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-ke1qyM+3AK2zPuBPb6Hk/GCsc5ewbLvPNkEuELx/JmANeEp6ZjnZ+wypPAJSucTw0wvCGrUaibDSdcrGFoWxKQ=="], + + "@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.203.0", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-transformer": "0.203.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Wbxf7k+87KyvxFr5D7uOiSq/vHXWommvdnNE7vECO3tAhsA2GfOlpWINCMWUEPdHZ7tCXxw6Epp3vgx3jU7llQ=="], + + "@opentelemetry/otlp-grpc-exporter-base": ["@opentelemetry/otlp-grpc-exporter-base@0.203.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-exporter-base": "0.203.0", "@opentelemetry/otlp-transformer": "0.203.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-te0Ze1ueJF+N/UOFl5jElJW4U0pZXQ8QklgSfJ2linHN0JJsuaHG8IabEUi2iqxY8ZBDlSiz1Trfv5JcjWWWwQ=="], + + "@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.203.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.203.0", "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-logs": "0.203.0", "@opentelemetry/sdk-metrics": "2.0.1", "@opentelemetry/sdk-trace-base": "2.0.1", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Y8I6GgoCna0qDQ2W6GCRtaF24SnvqvA8OfeTi7fqigD23u8Jpb4R5KFv/pRvrlGagcCLICMIyh9wiejp4TXu/A=="], + + "@opentelemetry/propagator-b3": ["@opentelemetry/propagator-b3@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-Hc09CaQ8Tf5AGLmf449H726uRoBNGPBL4bjr7AnnUpzWMvhdn61F78z9qb6IqB737TffBsokGAK1XykFEZ1igw=="], + + "@opentelemetry/propagator-jaeger": ["@opentelemetry/propagator-jaeger@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-7PMdPBmGVH2eQNb/AtSJizQNgeNTfh6jQFqys6lfhd6P4r+m/nTh3gKPPpaCXVdRQ+z93vfKk+4UGty390283w=="], + + "@opentelemetry/resources": ["@opentelemetry/resources@2.2.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A=="], + + "@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.203.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.203.0", "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-vM2+rPq0Vi3nYA5akQD2f3QwossDnTDLvKbea6u/A2NZ3XDkPxMfo/PNrDoXhDUD/0pPo2CdH5ce/thn9K0kLw=="], + + "@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g=="], + + "@opentelemetry/sdk-node": ["@opentelemetry/sdk-node@0.203.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.203.0", "@opentelemetry/core": "2.0.1", "@opentelemetry/exporter-logs-otlp-grpc": "0.203.0", "@opentelemetry/exporter-logs-otlp-http": "0.203.0", "@opentelemetry/exporter-logs-otlp-proto": "0.203.0", "@opentelemetry/exporter-metrics-otlp-grpc": "0.203.0", "@opentelemetry/exporter-metrics-otlp-http": "0.203.0", "@opentelemetry/exporter-metrics-otlp-proto": "0.203.0", "@opentelemetry/exporter-prometheus": "0.203.0", "@opentelemetry/exporter-trace-otlp-grpc": "0.203.0", "@opentelemetry/exporter-trace-otlp-http": "0.203.0", "@opentelemetry/exporter-trace-otlp-proto": "0.203.0", "@opentelemetry/exporter-zipkin": "2.0.1", "@opentelemetry/instrumentation": "0.203.0", "@opentelemetry/propagator-b3": "2.0.1", "@opentelemetry/propagator-jaeger": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-logs": "0.203.0", "@opentelemetry/sdk-metrics": "2.0.1", "@opentelemetry/sdk-trace-base": "2.0.1", "@opentelemetry/sdk-trace-node": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-zRMvrZGhGVMvAbbjiNQW3eKzW/073dlrSiAKPVWmkoQzah9wfynpVPeL55f9fVIm0GaBxTLcPeukWGy0/Wj7KQ=="], + + "@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.2.0", "", { "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw=="], + + "@opentelemetry/sdk-trace-node": ["@opentelemetry/sdk-trace-node@2.0.1", "", { "dependencies": { "@opentelemetry/context-async-hooks": "2.0.1", "@opentelemetry/core": "2.0.1", "@opentelemetry/sdk-trace-base": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-UhdbPF19pMpBtCWYP5lHbTogLWx9N0EBxtdagvkn5YtsAnCBZzL7SjktG+ZmupRgifsHMjwUaCCaVmqGfSADmA=="], + + "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.37.0", "", {}, "sha512-JD6DerIKdJGmRp4jQyX5FlrQjA4tjOw1cvfsPAZXfOOEErMUHjPcPSICS+6WnM0nB0efSFARh0KAZss+bvExOA=="], + + "@orpc/client": ["@orpc/client@1.8.1", "", { "dependencies": { "@orpc/shared": "1.8.1", "@orpc/standard-server": "1.8.1", "@orpc/standard-server-fetch": "1.8.1", "@orpc/standard-server-peer": "1.8.1" } }, "sha512-ewofUqn46yHQxnAOFLwZspQD1k3DPTUCnkqP6aFO1alUMHgLFNb03BKd1rgwUXSWaxWltKD8Db07HNxgltdk4A=="], + + "@orpc/contract": ["@orpc/contract@1.8.1", "", { "dependencies": { "@orpc/client": "1.8.1", "@orpc/shared": "1.8.1", "@standard-schema/spec": "^1.0.0", "openapi-types": "^12.1.3" } }, "sha512-zw0xgRxOyR/otX+4UeGEm0VjuMH/AeVbEuWvPNRJC8xxvQpaPJFo8Nr8eaywqSUZo1DnIS+pkwsdipa7GgFl7A=="], + + "@orpc/interop": ["@orpc/interop@1.8.1", "", {}, "sha512-TA2AQREo3tKQheHPvVs5PY1PqDnNUFGO3c8eb6lrX53npOD6lMi6IPedzeEHaZCqb17bRZ9Skc9Fg1FZ30ckug=="], + + "@orpc/json-schema": ["@orpc/json-schema@1.8.1", "", { "dependencies": { "@orpc/contract": "1.8.1", "@orpc/interop": "1.8.1", "@orpc/openapi": "1.8.1", "@orpc/server": "1.8.1", "@orpc/shared": "1.8.1" } }, "sha512-i3qaaW0iKreD8tgRCqQbqn69LZT2f3f80+idLUeq7zHmHtbhoYlPEmtCfz29+casM719gWkI6QDRtMhDpfQlgw=="], + + "@orpc/openapi": ["@orpc/openapi@1.8.1", "", { "dependencies": { "@orpc/client": "1.8.1", "@orpc/contract": "1.8.1", "@orpc/interop": "1.8.1", "@orpc/openapi-client": "1.8.1", "@orpc/server": "1.8.1", "@orpc/shared": "1.8.1", "@orpc/standard-server": "1.8.1", "rou3": "^0.7.3" } }, "sha512-G1qMCjpVGxJYrU0vMdYOr2WxSiX9C6ZhvafgKN7vOGqC7O5s1D+Ph/cSUe1R9OPZZPouhw75MNjTtKYP5lOrcA=="], + + "@orpc/openapi-client": ["@orpc/openapi-client@1.8.1", "", { "dependencies": { "@orpc/client": "1.8.1", "@orpc/contract": "1.8.1", "@orpc/shared": "1.8.1", "@orpc/standard-server": "1.8.1" } }, "sha512-DlBdRcn0lz2lzBis+d6zfVD8tZ7hM5S0uCjL3jNLNp/3T7RMSbhz/6egBCQW1vRh+kXhBjVyGs1mYEYd7ZWEZw=="], + + "@orpc/otel": ["@orpc/otel@1.10.2", "", { "dependencies": { "@orpc/shared": "1.10.2" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0", "@opentelemetry/instrumentation": ">=0.203.0" } }, "sha512-0FQ14GTRAaVRdGml2xFqHBcgPR2SH61H/f8RQ0Bo+xGIvKlZIKCzti0KQKwYwfUP3SqxzuuhZJXecpmSm/jhrw=="], + + "@orpc/server": ["@orpc/server@1.8.1", "", { "dependencies": { "@orpc/client": "1.8.1", "@orpc/contract": "1.8.1", "@orpc/interop": "1.8.1", "@orpc/shared": "1.8.1", "@orpc/standard-server": "1.8.1", "@orpc/standard-server-aws-lambda": "1.8.1", "@orpc/standard-server-fetch": "1.8.1", "@orpc/standard-server-node": "1.8.1", "@orpc/standard-server-peer": "1.8.1", "cookie": "^1.0.2" }, "peerDependencies": { "crossws": ">=0.3.4", "ws": ">=8.18.1" }, "optionalPeers": ["crossws", "ws"] }, "sha512-Aei7KJSMG9daNdubREeDYKCnmSRTnZT7V1Cx0NFLYDYqx8Bdil2J2InJghsio6AZdJUWLNq/zMm6QDu3NN2E6g=="], + + "@orpc/shared": ["@orpc/shared@1.8.1", "", { "dependencies": { "radash": "^12.1.1", "type-fest": "^4.39.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0" }, "optionalPeers": ["@opentelemetry/api"] }, "sha512-tlKvjSpqV54tG7tWwBjBcg/RziszZhWNp4Md2ERpLn+hnzgp8XyD0TEFLjWRm1RBAsZptqe/OlYIVEqNa3rg2g=="], + + "@orpc/standard-server": ["@orpc/standard-server@1.8.1", "", { "dependencies": { "@orpc/shared": "1.8.1" } }, "sha512-SgVoxnmRAhrF0usZcz72F8FcneM4Rp+UYMhggwwnCEtjKtKXddg89J/to2bkpH/P5x8JMVI/uE2YXRG8CtU6Cg=="], + + "@orpc/standard-server-aws-lambda": ["@orpc/standard-server-aws-lambda@1.8.1", "", { "dependencies": { "@orpc/shared": "1.8.1", "@orpc/standard-server": "1.8.1", "@orpc/standard-server-fetch": "1.8.1", "@orpc/standard-server-node": "1.8.1" } }, "sha512-5db2k1nhdySkYXMMXCxMuZIXDgo04rrZ6qqIEr1cvKnW5OHadcvxysfMa60WMA4Mzm3pypl2WJKGy36mdm6R8Q=="], + + "@orpc/standard-server-fetch": ["@orpc/standard-server-fetch@1.8.1", "", { "dependencies": { "@orpc/shared": "1.8.1", "@orpc/standard-server": "1.8.1" } }, "sha512-HZNTuLitB6X2nVPBfpbKvHRPNL7LV4J9+mQxr+Xi/hU2I6Fr2KWjNmAxcH1Fn6cOsJ09q9RFIaikUC88CQMnlA=="], + + "@orpc/standard-server-node": ["@orpc/standard-server-node@1.8.1", "", { "dependencies": { "@orpc/shared": "1.8.1", "@orpc/standard-server": "1.8.1", "@orpc/standard-server-fetch": "1.8.1" } }, "sha512-+hKShhdAM2ljCbfvFjZQVhcpZjVXCgrz3ysTNKRsIR+E3aiYXffylL6RDOjLAjfvQyRy7wsPVxPjyqUHGXX4vg=="], + + "@orpc/standard-server-peer": ["@orpc/standard-server-peer@1.8.1", "", { "dependencies": { "@orpc/shared": "1.8.1", "@orpc/standard-server": "1.8.1" } }, "sha512-QDGfi/P0HKxFQCoDUOsIaIfO1KK10qoXDmd6ZfZF9DwFKrnqE6AEpMgz/TVDqLb6mFUzMtvdjrPga8uO9QdnbQ=="], + + "@orpc/zod": ["@orpc/zod@1.8.1", "", { "dependencies": { "@orpc/json-schema": "1.8.1", "@orpc/openapi": "1.8.1", "@orpc/shared": "1.8.1", "escape-string-regexp": "^5.0.0", "wildcard-match": "^5.1.3" }, "peerDependencies": { "@orpc/contract": "1.8.1", "@orpc/server": "1.8.1", "zod": ">=3.25.0" } }, "sha512-2tVvLnPx5xxb2H93FYWfAGFA9N7IrVf8/Bv5aUEg11LiHaYBzDEBwyssiOXQL7/57RJ8RQbpvKYmr19hVrmj8g=="], + + "@paralleldrive/cuid2": ["@paralleldrive/cuid2@2.3.1", "", { "dependencies": { "@noble/hashes": "^1.1.5" } }, "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw=="], + + "@pixiv/three-vrm": ["@pixiv/three-vrm@3.4.3", "", { "dependencies": { "@pixiv/three-vrm-core": "3.4.3", "@pixiv/three-vrm-materials-hdr-emissive-multiplier": "3.4.3", "@pixiv/three-vrm-materials-mtoon": "3.4.3", "@pixiv/three-vrm-materials-v0compat": "3.4.3", "@pixiv/three-vrm-node-constraint": "3.4.3", "@pixiv/three-vrm-springbone": "3.4.3" }, "peerDependencies": { "three": ">=0.137" } }, "sha512-meTTL5WRIsuoVsdbfHcMVUcgnTF/T0C7bPCuWnV6mImHGkImdOS/1+w79arOfabdBQLuKZjvGHtCtdAheLpnKg=="], + + "@pixiv/three-vrm-animation": ["@pixiv/three-vrm-animation@3.4.3", "", { "dependencies": { "@pixiv/three-vrm-core": "3.4.3", "@pixiv/types-vrmc-vrm-1.0": "3.4.3", "@pixiv/types-vrmc-vrm-animation-1.0": "3.4.3" }, "peerDependencies": { "three": ">=0.137" } }, "sha512-gT9WQe/N4J4SL2NQrl7RMfFJ2u1LNKVbG0GCVSCC1V0aUM/vpg6pB+BU99VAjF7btZZBjGaliQUnrs3TVasRjA=="], + + "@pixiv/three-vrm-core": ["@pixiv/three-vrm-core@3.4.3", "", { "dependencies": { "@pixiv/types-vrm-0.0": "3.4.3", "@pixiv/types-vrmc-vrm-1.0": "3.4.3" }, "peerDependencies": { "three": ">=0.137" } }, "sha512-GS6Q0k+rSoOz/v2j79IReVdy95w+cO1WTGXwN4zMk1qH2KyLWLVfWD0eIZ7sF3ZpNjxOAQ/ibr4Oj8Zl+mrBcw=="], + + "@pixiv/three-vrm-materials-hdr-emissive-multiplier": ["@pixiv/three-vrm-materials-hdr-emissive-multiplier@3.4.3", "", { "dependencies": { "@pixiv/types-vrmc-materials-hdr-emissive-multiplier-1.0": "3.4.3" }, "peerDependencies": { "three": ">=0.137" } }, "sha512-HtQJ9Qy+VvdaBDZuNdQVGxi/59H88LHOGYhs7gUJCbf/U69rNkDx4sXBaqIvrF+r2GLphbl51sVSe6M+FBEqMw=="], + + "@pixiv/three-vrm-materials-mtoon": ["@pixiv/three-vrm-materials-mtoon@3.4.3", "", { "dependencies": { "@pixiv/types-vrm-0.0": "3.4.3", "@pixiv/types-vrmc-materials-mtoon-1.0": "3.4.3" }, "peerDependencies": { "three": ">=0.137" } }, "sha512-DvC3Vq+Xud6ipFlMQeXbL9pWXEythEjszOeJTgDmhuzd5ACdMvny9ClWe7sy9T5dtsjVGF36kuNQNXTsXz6UPw=="], + + "@pixiv/three-vrm-materials-v0compat": ["@pixiv/three-vrm-materials-v0compat@3.4.3", "", { "dependencies": { "@pixiv/types-vrm-0.0": "3.4.3", "@pixiv/types-vrmc-materials-mtoon-1.0": "3.4.3" }, "peerDependencies": { "three": ">=0.137" } }, "sha512-xtGSnatekG+1kfe2OG8w58+0MDsjj590qg2M0Yys+KXgSDyGDYX2kR+aS0oIFRfyuHy6wjSmYI04FGbPAEPi9Q=="], + + "@pixiv/three-vrm-node-constraint": ["@pixiv/three-vrm-node-constraint@3.4.3", "", { "dependencies": { "@pixiv/types-vrmc-node-constraint-1.0": "3.4.3" }, "peerDependencies": { "three": ">=0.137" } }, "sha512-YuxIhyCMGqvn78jh87SLDANF0nkBZrSUzCEJEy5iK3QMyxGXjMGiKAcNkWtLAONsG8ivHGSd5Wt5QhiafN55MQ=="], + + "@pixiv/three-vrm-springbone": ["@pixiv/three-vrm-springbone@3.4.3", "", { "dependencies": { "@pixiv/types-vrm-0.0": "3.4.3", "@pixiv/types-vrmc-springbone-1.0": "3.4.3", "@pixiv/types-vrmc-springbone-extended-collider-1.0": "3.4.3" }, "peerDependencies": { "three": ">=0.137" } }, "sha512-p68HDhKhdR55C53k4YSKIUs3OFthDMPsk87f8INOiRBXC7YBfvMFqmjyafNPildJ+G4VWWjurkLaPdNts41iFg=="], + + "@pixiv/types-vrm-0.0": ["@pixiv/types-vrm-0.0@3.4.3", "", {}, "sha512-7px2JNCc4SQvLMOzUaeZbvPYY+WV9AKNVEVg5VwcA6VmL95knkrSRwKpOr2D+WhfI0pjELXfv6r/6BBDOQ6fjQ=="], + + "@pixiv/types-vrmc-materials-hdr-emissive-multiplier-1.0": ["@pixiv/types-vrmc-materials-hdr-emissive-multiplier-1.0@3.4.3", "", {}, "sha512-EGlyBeQEipAuD+ITNIbVwmI/poAkF57tA2Vq8P0JIFIa3Uo7zQuIBLtoeMHWWJZA1zFqDu/J3pSYnlFC4POSeA=="], + + "@pixiv/types-vrmc-materials-mtoon-1.0": ["@pixiv/types-vrmc-materials-mtoon-1.0@3.4.3", "", {}, "sha512-BWIuCyz0pznwZRiUrVs/hcXDHVnLi8tsQyoyamo4GzthLXOjKmxE/De9vZULVlTl+5Iy/COlLkUBixqDONWlYg=="], + + "@pixiv/types-vrmc-node-constraint-1.0": ["@pixiv/types-vrmc-node-constraint-1.0@3.4.3", "", {}, "sha512-VrJ6V+gLjZSu1B1UKNI0kl+0GHTvcNgSiZFhkd/AC70HOp/wTSGf6oIVE5e0g8unXXMczUgED/BAPk5ppTPKbQ=="], + + "@pixiv/types-vrmc-springbone-1.0": ["@pixiv/types-vrmc-springbone-1.0@3.4.3", "", {}, "sha512-RLnZnV/0frGE9XaYsO5rFtqQ0q69vWvdJot/V3E7EXgU5tSUPsqA8hPPpKXafYDJ7KyqYREMoiAc8SGMOENV1w=="], + + "@pixiv/types-vrmc-springbone-extended-collider-1.0": ["@pixiv/types-vrmc-springbone-extended-collider-1.0@3.4.3", "", {}, "sha512-BTOLufH42uj8dyRsUVY10XLYhwVVoXH9TqasELyqy5aFzL0ELe9mbzvWdfqva3gsgZNkrqfvTkAwwlLzz48VJg=="], + + "@pixiv/types-vrmc-vrm-1.0": ["@pixiv/types-vrmc-vrm-1.0@3.4.3", "", {}, "sha512-6ucxefth1KW+0nkSV5b2DRIR3RIZRNa+g4RBsOCwwill/tLaNKxqsfAdvbvIi7OsxnwSMDWB53relBdIlsoW0w=="], + + "@pixiv/types-vrmc-vrm-animation-1.0": ["@pixiv/types-vrmc-vrm-animation-1.0@3.4.3", "", { "dependencies": { "@pixiv/types-vrmc-vrm-1.0": "2.0.3" } }, "sha512-NuYgMxmA5JI+yWXSlUBHLWsbdQFV9mJC3rr0jDUxF0n+vdN3b8KlVALp8OlYC/rTrW0cflePAVlxzl3teah62w=="], + + "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + + "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="], + + "@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="], + + "@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="], + + "@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="], + + "@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="], + + "@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="], + + "@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="], + + "@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="], + + "@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="], + + "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], + + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="], + + "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.4", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collapsible": "1.1.4", "@radix-ui/react-collection": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.0.3", "@radix-ui/react-use-controllable-state": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-SGCxlSBaMvEzDROzyZjsVNzu9XY5E28B3k8jOENyrz6csOv/pG1eHyYfLJai1n9tRjwG61coXDhfpgtxKxUv5g=="], + + "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.4", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.3", "@radix-ui/react-primitive": "2.0.3", "@radix-ui/react-use-controllable-state": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-u7LCw1EYInQtBNLGjm9nZ89S/4GcvX1UR5XbekEgnQae2Hkpq39ycJ1OhdeN1/JDfVNG91kWaWoest127TaEKQ=="], + + "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.0.3", "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-mM2pxoQw5HJ49rkzwOs7Y6J4oYH22wS8BfK2/bBxROlI4xuR0c4jEenQP63LlTlDkO6Buj2Vt+QYAYcOgqtrXA=="], + + "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="], + + "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], + + "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="], + + "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], + + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IrVLIhskYhH3nLvtcBLQFZr61tBG7wx7O3kEmdzcYwRGAEBmBicGGL7ATzNgruYJ3xBTbuzEEq9OXJM3PAX3tA=="], + + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Pf/t/GkndH7CQ8wE2hbkXA+WyZ83fhQQn5DDmwDiDo6AwN/fhaH8oqZ0jRjMrO2iaMhDi6P1HRx6AZwyMinY1g=="], + + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@radix-ui/react-switch": ["@radix-ui/react-switch@1.1.4", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.0.3", "@radix-ui/react-use-controllable-state": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zGP6W8plLeogoeGMiTHJ/uvf+TE1C2chVsEwfP8YlvpQKJHktG+iCkUtCLGPAuDV8/qDSmIRPm4NggaTxFMVBQ=="], + + "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], + + "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-YnEXIy8/ga01Y1PN0VfaNH//MhA91JlEGVBDxDzROqwrAtG5Yr2QGEPz8A/rJA3C7ZAHryOYGaUv8fLSW2H/mg=="], + + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], + + "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="], + + "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="], + + "@react-three/fiber": ["@react-three/fiber@9.4.0", "", { "dependencies": { "@babel/runtime": "^7.17.8", "@types/react-reconciler": "^0.32.0", "@types/webxr": "*", "base64-js": "^1.5.1", "buffer": "^6.0.3", "its-fine": "^2.0.0", "react-reconciler": "^0.31.0", "react-use-measure": "^2.1.7", "scheduler": "^0.25.0", "suspend-react": "^0.1.3", "use-sync-external-store": "^1.4.0", "zustand": "^5.0.3" }, "peerDependencies": { "expo": ">=43.0", "expo-asset": ">=8.4", "expo-file-system": ">=11.0", "expo-gl": ">=11.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-native": ">=0.78", "three": ">=0.156" }, "optionalPeers": ["expo", "expo-asset", "expo-file-system", "expo-gl", "react-dom", "react-native"] }, "sha512-k4iu1R6e5D54918V4sqmISUkI5OgTw3v7/sDRKEC632Wd5g2WBtUS5gyG63X0GJO/HZUj1tsjSXfyzwrUHZl1g=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.52.5", "", { "os": "linux", "cpu": "x64" }, "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q=="], + + "@schummar/icu-type-parser": ["@schummar/icu-type-parser@1.21.5", "", {}, "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw=="], + + "@shikijs/core": ["@shikijs/core@1.29.2", "", { "dependencies": { "@shikijs/engine-javascript": "1.29.2", "@shikijs/engine-oniguruma": "1.29.2", "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.4" } }, "sha512-vju0lY9r27jJfOY4Z7+Rt/nIOjzJpZ3y+nYpqtUZInVoXQ/TJZcfGnNOGnKjFdVZb8qexiCuSlZRKcGfhhTTZQ=="], + + "@shikijs/engine-javascript": ["@shikijs/engine-javascript@1.29.2", "", { "dependencies": { "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1", "oniguruma-to-es": "^2.2.0" } }, "sha512-iNEZv4IrLYPv64Q6k7EPpOCE/nuvGiKl7zxdq0WFuRPF5PAE9PRo2JGq/d8crLusM59BRemJ4eOqrFrC4wiQ+A=="], + + "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@1.29.2", "", { "dependencies": { "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1" } }, "sha512-7iiOx3SG8+g1MnlzZVDYiaeHe7Ez2Kf2HrJzdmGwkRisT7r4rak0e655AcM/tF9JG/kg5fMNYlLLKglbN7gBqA=="], + + "@shikijs/langs": ["@shikijs/langs@1.29.2", "", { "dependencies": { "@shikijs/types": "1.29.2" } }, "sha512-FIBA7N3LZ+223U7cJDUYd5shmciFQlYkFXlkKVaHsCPgfVLiO+e12FmQE6Tf9vuyEsFe3dIl8qGWKXgEHL9wmQ=="], + + "@shikijs/themes": ["@shikijs/themes@1.29.2", "", { "dependencies": { "@shikijs/types": "1.29.2" } }, "sha512-i9TNZlsq4uoyqSbluIcZkmPL9Bfi3djVxRnofUHwvx/h6SRW3cwgBC5SML7vsDcWyukY0eCzVN980rqP6qNl9g=="], + + "@shikijs/types": ["@shikijs/types@1.29.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw=="], + + "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], + + "@sqltools/formatter": ["@sqltools/formatter@1.2.5", "", {}, "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw=="], + + "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], + + "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], + + "@swetrix/nextjs": ["@swetrix/nextjs@1.0.1", "", { "dependencies": { "swetrix": "^1.3.1" }, "peerDependencies": { "next": "^10 || ^11 || ^12", "react": "^16 || ^17 || ^18" } }, "sha512-GmqFWPHJuSz4POD427KHBE/Zw/9cimEg5Tq1Q5vMYx9ribT9bn1sW32tjoMhSpOyO9xep3lBmO5uMrYnziDfGQ=="], + + "@tailwindcss/node": ["@tailwindcss/node@4.1.16", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.19", "source-map-js": "^1.2.1", "tailwindcss": "4.1.16" } }, "sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw=="], + + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.16", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.16", "@tailwindcss/oxide-darwin-arm64": "4.1.16", "@tailwindcss/oxide-darwin-x64": "4.1.16", "@tailwindcss/oxide-freebsd-x64": "4.1.16", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.16", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.16", "@tailwindcss/oxide-linux-arm64-musl": "4.1.16", "@tailwindcss/oxide-linux-x64-gnu": "4.1.16", "@tailwindcss/oxide-linux-x64-musl": "4.1.16", "@tailwindcss/oxide-wasm32-wasi": "4.1.16", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.16", "@tailwindcss/oxide-win32-x64-msvc": "4.1.16" } }, "sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg=="], + + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.16", "", { "os": "android", "cpu": "arm64" }, "sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA=="], + + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.16", "", { "os": "darwin", "cpu": "arm64" }, "sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA=="], + + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.16", "", { "os": "darwin", "cpu": "x64" }, "sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg=="], + + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.16", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg=="], + + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.16", "", { "os": "linux", "cpu": "arm" }, "sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw=="], + + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w=="], + + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ=="], + + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.16", "", { "os": "linux", "cpu": "x64" }, "sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew=="], + + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.16", "", { "os": "linux", "cpu": "x64" }, "sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw=="], + + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.16", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.0.7", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q=="], + + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.16", "", { "os": "win32", "cpu": "arm64" }, "sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A=="], + + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.16", "", { "os": "win32", "cpu": "x64" }, "sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg=="], + + "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.16", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.16", "@tailwindcss/oxide": "4.1.16", "postcss": "^8.4.41", "tailwindcss": "4.1.16" } }, "sha512-Qn3SFGPXYQMKR/UtqS+dqvPrzEeBZHrFA92maT4zijCVggdsXnDBMsPFJo1eArX3J+O+Gi+8pV4PkqjLCNBk3A=="], + + "@tweenjs/tween.js": ["@tweenjs/tween.js@23.1.3", "", {}, "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA=="], + + "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], + + "@types/js-cookie": ["@types/js-cookie@2.2.7", "", {}, "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA=="], + + "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], + + "@types/node": ["@types/node@20.19.23", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-yIdlVVVHXpmqRhtyovZAcSy0MiPcYWGkoO4CGe/+jpP0hmNuihm4XhHbADpK++MsiLHP5MVlv+bcgdF99kSiFQ=="], + + "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="], + + "@types/react": ["@types/react@18.3.26", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA=="], + + "@types/react-dom": ["@types/react-dom@18.3.7", "", { "peerDependencies": { "@types/react": "^18.0.0" } }, "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ=="], + + "@types/react-reconciler": ["@types/react-reconciler@0.32.2", "", { "peerDependencies": { "@types/react": "*" } }, "sha512-gjcm6O0aUknhYaogEl8t5pecPfiOTD8VQkbjOhgbZas/E6qGY+veW9iuJU/7p4Y1E0EuQ0mArga7VEOUWSlVRA=="], + + "@types/stats.js": ["@types/stats.js@0.17.4", "", {}, "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA=="], + + "@types/three": ["@types/three@0.176.0", "", { "dependencies": { "@dimforge/rapier3d-compat": "^0.12.0", "@tweenjs/tween.js": "~23.1.3", "@types/stats.js": "*", "@types/webxr": "*", "@webgpu/types": "*", "fflate": "~0.8.2", "meshoptimizer": "~0.18.1" } }, "sha512-FwfPXxCqOtP7EdYMagCFePNKoG1AGBDUEVKtluv2BTVRpSt7b+X27xNsirPCTCqY1pGYsPUzaM3jgWP7dXSxlw=="], + + "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], + + "@types/webxr": ["@types/webxr@0.5.24", "", {}, "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg=="], + + "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], + + "@webgpu/types": ["@webgpu/types@0.1.66", "", {}, "sha512-YA2hLrwLpDsRueNDXIMqN9NTzD6bCDkuXbOSe0heS+f8YE8usA6Gbv1prj81pzVHrbaAma7zObnIC+I6/sXJgA=="], + + "@xobotyi/scrollbar-width": ["@xobotyi/scrollbar-width@1.9.5", "", {}, "sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ=="], + + "acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], + + "acorn-import-attributes": ["acorn-import-attributes@1.9.5", "", { "peerDependencies": { "acorn": "^8" } }, "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ=="], + + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "ansis": ["ansis@3.17.0", "", {}, "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg=="], + + "app-root-path": ["app-root-path@3.1.0", "", {}, "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA=="], + + "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "base-x": ["base-x@5.0.1", "", {}, "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + + "c15t": ["c15t@1.7.1", "", { "dependencies": { "@c15t/backend": "1.7.1", "@c15t/translations": "1.7.0", "@orpc/client": "1.8.1", "@orpc/server": "1.8.1", "zustand": "^5.0.3" } }, "sha512-MXQt0zsqTRbUs+9dNc9PivauJWc9232akbotS3NmUXnkMLBxYsCduSvqe560HDVVj0uhIQmYx0Yp0JbvHp/5yw=="], + + "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001751", "", {}, "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw=="], + + "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], + + "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + + "character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="], + + "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], + + "cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q=="], + + "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], + + "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], + + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + + "color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="], + + "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], + + "commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="], + + "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], + + "copy-anything": ["copy-anything@4.0.5", "", { "dependencies": { "is-what": "^5.2.0" } }, "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA=="], + + "copy-to-clipboard": ["copy-to-clipboard@3.3.3", "", { "dependencies": { "toggle-selection": "^1.0.6" } }, "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "css-in-js-utils": ["css-in-js-utils@3.1.0", "", { "dependencies": { "hyphenate-style-name": "^1.0.3" } }, "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A=="], + + "css-tree": ["css-tree@1.1.3", "", { "dependencies": { "mdn-data": "2.0.14", "source-map": "^0.6.1" } }, "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q=="], + + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + + "daisyui": ["daisyui@5.3.10", "", {}, "sha512-vmjyPmm0hvFhA95KB6uiGmWakziB2pBv6CUcs5Ka/3iMBMn9S+C3SZYx9G9l2JrgTZ1EFn61F/HrPcwaUm2kLQ=="], + + "dayjs": ["dayjs@1.11.18", "", {}, "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="], + + "dedent": ["dedent@1.7.0", "", { "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, "optionalPeers": ["babel-plugin-macros"] }, "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ=="], + + "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], + + "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], + + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], + + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], + + "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], + + "drizzle-orm": ["drizzle-orm@0.44.7", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-quIpnYznjU9lHshEOAYLoZ9s3jweleHlZIAWR/jX9gAWNg/JhQ1wj0KGRf7/Zm+obRrYd9GjPVJg790QY9N5AQ=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "emoji-regex-xs": ["emoji-regex-xs@1.0.0", "", {}, "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg=="], + + "enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="], + + "error-stack-parser": ["error-stack-parser@2.1.4", "", { "dependencies": { "stackframe": "^1.3.4" } }, "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-shallow-equal": ["fast-shallow-equal@1.0.0", "", {}, "sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw=="], + + "fastest-stable-stringify": ["fastest-stable-stringify@2.0.2", "", {}, "sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q=="], + + "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], + + "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], + + "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "framer-motion": ["framer-motion@11.18.2", "", { "dependencies": { "motion-dom": "^11.18.1", "motion-utils": "^11.18.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w=="], + + "fumadb": ["fumadb@0.1.1", "", { "dependencies": { "@clack/prompts": "^0.11.0", "@paralleldrive/cuid2": "^2.2.2", "commander": "^14.0.0", "kysely": "^0.28.3", "kysely-typeorm": "^0.3.0", "semver": "^7.7.2", "zod": "^4.0.5" }, "peerDependencies": { "convex": "^1.25.0", "drizzle-orm": "^0.44.0", "mongodb": "6.x.x", "prisma": "6.x.x", "typeorm": "0.x.x" }, "optionalPeers": ["convex", "drizzle-orm", "mongodb", "prisma", "typeorm"] }, "sha512-p2+qTHEP+8J+hyCmDXQIib1eXNvr3pIIqRcbKkbYEgN/upBOPr6/kfgYCLipdXie73ryYWubom+kWgL010zwkQ=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "hast-util-to-html": ["hast-util-to-html@9.0.5", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "stringify-entities": "^4.0.0", "zwitch": "^2.0.4" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="], + + "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="], + + "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="], + + "hyphenate-style-name": ["hyphenate-style-name@1.1.0", "", {}, "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw=="], + + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "import-in-the-middle": ["import-in-the-middle@1.15.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^1.2.2", "module-details-from-path": "^1.0.3" } }, "sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "inline-style-prefixer": ["inline-style-prefixer@7.0.1", "", { "dependencies": { "css-in-js-utils": "^3.1.0" } }, "sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw=="], + + "intl-messageformat": ["intl-messageformat@10.7.18", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.6", "@formatjs/fast-memoize": "2.2.7", "@formatjs/icu-messageformat-parser": "2.11.4", "tslib": "^2.8.0" } }, "sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g=="], + + "is-arrayish": ["is-arrayish@0.3.4", "", {}, "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="], + + "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], + + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], + + "is-what": ["is-what@5.5.0", "", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="], + + "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "its-fine": ["its-fine@2.0.0", "", { "dependencies": { "@types/react-reconciler": "^0.28.9" }, "peerDependencies": { "react": "^19.0.0" } }, "sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng=="], + + "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + + "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + + "js-cookie": ["js-cookie@2.2.1", "", {}, "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="], + + "kysely": ["kysely@0.27.6", "", {}, "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ=="], + + "kysely-typeorm": ["kysely-typeorm@0.3.0", "", { "peerDependencies": { "kysely": ">= 0.24.0 < 1", "typeorm": ">= 0.3.0 < 0.4.0" } }, "sha512-xQDx6+HagVmtXeuYd3Sz2CPYc/jOo7JO1ALldYPdwRrbiwSs9GFyNPp5JbElkfZB+T4DRb+A53pKWKYjlgSFeA=="], + + "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], + + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="], + + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="], + + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="], + + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="], + + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="], + + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="], + + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="], + + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="], + + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="], + + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="], + + "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], + + "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], + + "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "lucide-react": ["lucide-react@0.548.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-63b16z63jM9yc1MwxajHeuu0FRZFsDtljtDjYm26Kd86UQ5HQzu9ksEtoUUw4RBuewodw/tGFmvipePvRsKeDA=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "mdast-util-to-hast": ["mdast-util-to-hast@13.2.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA=="], + + "mdn-data": ["mdn-data@2.0.14", "", {}, "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="], + + "meshoptimizer": ["meshoptimizer@0.18.1", "", {}, "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw=="], + + "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="], + + "micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="], + + "micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="], + + "micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="], + + "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="], + + "minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + + "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + + "module-details-from-path": ["module-details-from-path@1.0.4", "", {}, "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w=="], + + "motion": ["motion@11.18.2", "", { "dependencies": { "framer-motion": "^11.18.2", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-JLjvFDuFr42NFtcVoMAyC2sEjnpA8xpy6qWPyzQvCloznAyQ8FIXioxWfHiLtgYhoVpfUqSWpn1h9++skj9+Wg=="], + + "motion-dom": ["motion-dom@11.18.1", "", { "dependencies": { "motion-utils": "^11.18.1" } }, "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw=="], + + "motion-utils": ["motion-utils@11.18.1", "", {}, "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "nano-css": ["nano-css@5.6.2", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15", "css-tree": "^1.1.2", "csstype": "^3.1.2", "fastest-stable-stringify": "^2.0.2", "inline-style-prefixer": "^7.0.1", "rtl-css-js": "^1.16.1", "stacktrace-js": "^2.0.2", "stylis": "^4.3.0" }, "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-+6bHaC8dSDGALM1HJjOHVXpuastdu2xFoZlC77Jh4cg+33Zcgm+Gxd+1xsnpZK14eyHObSp82+ll5y3SX75liw=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "neverthrow": ["neverthrow@8.2.0", "", { "optionalDependencies": { "@rollup/rollup-linux-x64-gnu": "^4.24.0" } }, "sha512-kOCT/1MCPAxY5iUV3wytNFUMUolzuwd/VF/1KCx7kf6CutrOsTie+84zTGTpgQycjvfLdBBdvBvFLqFD2c0wkQ=="], + + "next": ["next@16.0.0", "", { "dependencies": { "@next/env": "16.0.0", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.0.0", "@next/swc-darwin-x64": "16.0.0", "@next/swc-linux-arm64-gnu": "16.0.0", "@next/swc-linux-arm64-musl": "16.0.0", "@next/swc-linux-x64-gnu": "16.0.0", "@next/swc-linux-x64-musl": "16.0.0", "@next/swc-win32-arm64-msvc": "16.0.0", "@next/swc-win32-x64-msvc": "16.0.0", "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-nYohiNdxGu4OmBzggxy9rczmjIGI+TpR5vbKTsE1HqYwNm1B+YSiugSrFguX6omMOKnDHAmBPY4+8TNJk0Idyg=="], + + "next-intl": ["next-intl@4.4.0", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.5.4", "negotiator": "^1.0.0", "use-intl": "^4.4.0" }, "peerDependencies": { "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0", "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-QHqnP9V9Pe7Tn0PdVQ7u1Z8k9yCkW5SJKeRy2g5gxzhSt/C01y3B9qNxuj3Fsmup/yreIHe6osxU6sFa+9WIkQ=="], + + "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], + + "oniguruma-to-es": ["oniguruma-to-es@2.3.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="], + + "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], + + "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + + "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], + + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + + "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], + + "protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="], + + "radash": ["radash@12.1.1", "", {}, "sha512-h36JMxKRqrAxVD8201FrCpyeNuUY9Y5zZwujr20fFO77tpUtGa6EZzfKw/3WaiBX95fq7+MpsuMLNdSnORAwSA=="], + + "react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="], + + "react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="], + + "react-icons": ["react-icons@5.5.0", "", { "peerDependencies": { "react": "*" } }, "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw=="], + + "react-reconciler": ["react-reconciler@0.31.0", "", { "dependencies": { "scheduler": "^0.25.0" }, "peerDependencies": { "react": "^19.0.0" } }, "sha512-7Ob7Z+URmesIsIVRjnLoDGwBEG/tVitidU0nMsqX/eeJaLY89RISO/10ERe0MqmzuKUUB1rmY+h1itMbUHg9BQ=="], + + "react-universal-interface": ["react-universal-interface@0.6.2", "", { "peerDependencies": { "react": "*", "tslib": "*" } }, "sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw=="], + + "react-use": ["react-use@17.6.0", "", { "dependencies": { "@types/js-cookie": "^2.2.6", "@xobotyi/scrollbar-width": "^1.9.5", "copy-to-clipboard": "^3.3.1", "fast-deep-equal": "^3.1.3", "fast-shallow-equal": "^1.0.0", "js-cookie": "^2.2.1", "nano-css": "^5.6.2", "react-universal-interface": "^0.6.2", "resize-observer-polyfill": "^1.5.1", "screenfull": "^5.1.0", "set-harmonic-interval": "^1.0.1", "throttle-debounce": "^3.0.1", "ts-easing": "^0.2.0", "tslib": "^2.1.0" }, "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-OmedEScUMKFfzn1Ir8dBxiLLSOzhKe/dPZwVxcujweSj45aNM7BEGPb9BEVIgVEqEXx6f3/TsXzwIktNgUR02g=="], + + "react-use-measure": ["react-use-measure@2.1.7", "", { "peerDependencies": { "react": ">=16.13", "react-dom": ">=16.13" }, "optionalPeers": ["react-dom"] }, "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg=="], + + "reflect-metadata": ["reflect-metadata@0.2.2", "", {}, "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q=="], + + "regex": ["regex@5.1.1", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-dN5I359AVGPnwzJm2jN1k0W9LPZ+ePvoOeVMMfqIMFz53sSwXkxaJoxr50ptnsC771lK95BnTrVSZxq0b9yCGw=="], + + "regex-recursion": ["regex-recursion@5.1.1", "", { "dependencies": { "regex": "^5.1.1", "regex-utilities": "^2.3.0" } }, "sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w=="], + + "regex-utilities": ["regex-utilities@2.3.0", "", {}, "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "require-in-the-middle": ["require-in-the-middle@7.5.2", "", { "dependencies": { "debug": "^4.3.5", "module-details-from-path": "^1.0.3", "resolve": "^1.22.8" } }, "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ=="], + + "resize-observer-polyfill": ["resize-observer-polyfill@1.5.1", "", {}, "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="], + + "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], + + "rou3": ["rou3@0.7.9", "", {}, "sha512-+JM7c8swGkoXkWRkIz7qpYN9Bls7Rj/vuSGaxtoKHIe8Ba1ci+mXnqzqtJFrXSbvEazNL9v83P2RiXae9NSbfQ=="], + + "rtl-css-js": ["rtl-css-js@1.16.1", "", { "dependencies": { "@babel/runtime": "^7.1.2" } }, "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "scheduler": ["scheduler@0.25.0", "", {}, "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA=="], + + "screenfull": ["screenfull@5.2.0", "", {}, "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA=="], + + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], + + "set-harmonic-interval": ["set-harmonic-interval@1.0.1", "", {}, "sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g=="], + + "sha.js": ["sha.js@2.4.12", "", { "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1", "to-buffer": "^1.2.0" }, "bin": { "sha.js": "bin.js" } }, "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w=="], + + "sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "shiki": ["shiki@1.29.2", "", { "dependencies": { "@shikijs/core": "1.29.2", "@shikijs/engine-javascript": "1.29.2", "@shikijs/engine-oniguruma": "1.29.2", "@shikijs/langs": "1.29.2", "@shikijs/themes": "1.29.2", "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-njXuliz/cP+67jU2hukkxCNuH1yUi4QfdZZY+sMr5PPrIyXSu5iTb/qYC4BiWWB0vZ+7TbdvYUCeL23zpwCfbg=="], + + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + + "simple-swizzle": ["simple-swizzle@0.2.4", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw=="], + + "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], + + "sonner": ["sonner@1.7.4", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw=="], + + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], + + "sql-highlight": ["sql-highlight@6.1.0", "", {}, "sha512-ed7OK4e9ywpE7pgRMkMQmZDPKSVdm0oX5IEtZiKnFucSF0zu6c80GZBe38UqHuVhTWJ9xsKgSMjCG2bml86KvA=="], + + "stack-generator": ["stack-generator@2.0.10", "", { "dependencies": { "stackframe": "^1.3.4" } }, "sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ=="], + + "stackframe": ["stackframe@1.3.4", "", {}, "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="], + + "stacktrace-gps": ["stacktrace-gps@3.1.2", "", { "dependencies": { "source-map": "0.5.6", "stackframe": "^1.3.4" } }, "sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ=="], + + "stacktrace-js": ["stacktrace-js@2.0.2", "", { "dependencies": { "error-stack-parser": "^2.0.6", "stack-generator": "^2.0.5", "stacktrace-gps": "^3.0.4" } }, "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg=="], + + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], + + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="], + + "stylis": ["stylis@4.3.6", "", {}, "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ=="], + + "superjson": ["superjson@2.2.3", "", { "dependencies": { "copy-anything": "^4" } }, "sha512-ay3d+LW/S6yppKoTz3Bq4mG0xrS5bFwfWEBmQfbC7lt5wmtk+Obq0TxVuA9eYRirBTQb1K3eEpBRHMQEo0WyVw=="], + + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + + "suspend-react": ["suspend-react@0.1.3", "", { "peerDependencies": { "react": ">=17.0" } }, "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ=="], + + "swetrix": ["swetrix@1.3.2", "", { "dependencies": { "@types/node": "^14.18.0" } }, "sha512-vbUPo4Tc/YjUiNO96PiwIznMs1rlHGZE6RKwMGVt8TtJiZEJblNgjjnJ2/+hKQRvp6CMoPkOXILrihdig8Np3g=="], + + "tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="], + + "tailwind-merge": ["tailwind-merge@3.3.1", "", {}, "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g=="], + + "tailwind-variants": ["tailwind-variants@0.3.1", "", { "dependencies": { "tailwind-merge": "2.5.4" }, "peerDependencies": { "tailwindcss": "*" } }, "sha512-krn67M3FpPwElg4FsZrOQd0U26o7UDH/QOkK8RNaiCCrr052f6YJPBUfNKnPo/s/xRzNPtv1Mldlxsg8Tb46BQ=="], + + "tailwindcss": ["tailwindcss@4.1.16", "", {}, "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA=="], + + "tailwindcss-animate": ["tailwindcss-animate@1.0.7", "", { "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders" } }, "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA=="], + + "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], + + "three": ["three@0.176.0", "", {}, "sha512-PWRKYWQo23ojf9oZSlRGH8K09q7nRSWx6LY/HF/UUrMdYgN9i1e2OwJYHoQjwc6HF/4lvvYLC5YC1X8UJL2ZpA=="], + + "throttle-debounce": ["throttle-debounce@3.0.1", "", {}, "sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg=="], + + "to-buffer": ["to-buffer@1.2.2", "", { "dependencies": { "isarray": "^2.0.5", "safe-buffer": "^5.2.1", "typed-array-buffer": "^1.0.3" } }, "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw=="], + + "toggle-selection": ["toggle-selection@1.0.6", "", {}, "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="], + + "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], + + "ts-easing": ["ts-easing@0.2.0", "", {}, "sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="], + + "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], + + "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], + + "typeorm": ["typeorm@0.3.27", "", { "dependencies": { "@sqltools/formatter": "^1.2.5", "ansis": "^3.17.0", "app-root-path": "^3.1.0", "buffer": "^6.0.3", "dayjs": "^1.11.13", "debug": "^4.4.0", "dedent": "^1.6.0", "dotenv": "^16.4.7", "glob": "^10.4.5", "sha.js": "^2.4.12", "sql-highlight": "^6.0.0", "tslib": "^2.8.1", "uuid": "^11.1.0", "yargs": "^17.7.2" }, "peerDependencies": { "@google-cloud/spanner": "^5.18.0 || ^6.0.0 || ^7.0.0", "@sap/hana-client": "^2.14.22", "better-sqlite3": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0", "ioredis": "^5.0.4", "mongodb": "^5.8.0 || ^6.0.0", "mssql": "^9.1.1 || ^10.0.1 || ^11.0.1", "mysql2": "^2.2.5 || ^3.0.1", "oracledb": "^6.3.0", "pg": "^8.5.1", "pg-native": "^3.0.0", "pg-query-stream": "^4.0.0", "redis": "^3.1.1 || ^4.0.0 || ^5.0.14", "reflect-metadata": "^0.1.14 || ^0.2.0", "sql.js": "^1.4.0", "sqlite3": "^5.0.3", "ts-node": "^10.7.0", "typeorm-aurora-data-api-driver": "^2.0.0 || ^3.0.0" }, "optionalPeers": ["@google-cloud/spanner", "@sap/hana-client", "better-sqlite3", "ioredis", "mongodb", "mssql", "mysql2", "oracledb", "pg", "pg-native", "pg-query-stream", "redis", "sql.js", "sqlite3", "ts-node", "typeorm-aurora-data-api-driver"], "bin": { "typeorm": "cli.js", "typeorm-ts-node-esm": "cli-ts-node-esm.js", "typeorm-ts-node-commonjs": "cli-ts-node-commonjs.js" } }, "sha512-pNV1bn+1n8qEe8tUNsNdD8ejuPcMAg47u2lUGnbsajiNUr3p2Js1XLKQjBMH0yMRMDfdX8T+fIRejFmIwy9x4A=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + + "unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="], + + "unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="], + + "unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="], + + "unist-util-visit": ["unist-util-visit@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg=="], + + "unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="], + + "use-intl": ["use-intl@4.4.0", "", { "dependencies": { "@formatjs/fast-memoize": "^2.2.0", "@schummar/icu-type-parser": "1.21.5", "intl-messageformat": "^10.5.14" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" } }, "sha512-smFekJWtokDRBLC5/ZumlBREzdXOkw06+56Ifj2uRe9266Mk+yWQm2PcJO+EwlOE5sHIXHixOTzN6V8E0RGUbw=="], + + "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="], + + "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], + + "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], + + "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], + + "wildcard-match": ["wildcard-match@5.1.4", "", {}, "sha512-wldeCaczs8XXq7hj+5d/F38JE2r7EXgb6WQDM84RVwxy81T/sxB5e9+uZLK9Q9oNz1mlvjut+QtvgaOQFPVq/g=="], + + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], + + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + + "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "zod": ["zod@4.1.12", "", {}, "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ=="], + + "zustand": ["zustand@5.0.8", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw=="], + + "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], + + "@c15t/react/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@formatjs/ecma402-abstract/@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.6.2", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA=="], + + "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/exporter-logs-otlp-http/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/exporter-logs-otlp-proto/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/exporter-logs-otlp-proto/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="], + + "@opentelemetry/exporter-logs-otlp-proto/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ=="], + + "@opentelemetry/exporter-metrics-otlp-grpc/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/exporter-metrics-otlp-grpc/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="], + + "@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="], + + "@opentelemetry/exporter-metrics-otlp-proto/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/exporter-metrics-otlp-proto/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="], + + "@opentelemetry/exporter-prometheus/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/exporter-prometheus/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="], + + "@opentelemetry/exporter-trace-otlp-grpc/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/exporter-trace-otlp-grpc/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="], + + "@opentelemetry/exporter-trace-otlp-grpc/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ=="], + + "@opentelemetry/exporter-trace-otlp-http/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/exporter-trace-otlp-http/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="], + + "@opentelemetry/exporter-trace-otlp-http/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ=="], + + "@opentelemetry/exporter-trace-otlp-proto/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/exporter-trace-otlp-proto/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="], + + "@opentelemetry/exporter-trace-otlp-proto/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ=="], + + "@opentelemetry/exporter-zipkin/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/exporter-zipkin/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="], + + "@opentelemetry/exporter-zipkin/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ=="], + + "@opentelemetry/otlp-exporter-base/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/otlp-grpc-exporter-base/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/otlp-transformer/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/otlp-transformer/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="], + + "@opentelemetry/otlp-transformer/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ=="], + + "@opentelemetry/propagator-b3/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/propagator-jaeger/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/sdk-logs/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/sdk-logs/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="], + + "@opentelemetry/sdk-metrics/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/sdk-metrics/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="], + + "@opentelemetry/sdk-node/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/sdk-node/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="], + + "@opentelemetry/sdk-node/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ=="], + + "@opentelemetry/sdk-trace-node/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="], + + "@opentelemetry/sdk-trace-node/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ=="], + + "@orpc/otel/@orpc/shared": ["@orpc/shared@1.10.2", "", { "dependencies": { "radash": "^12.1.1", "type-fest": "^5.1.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0" }, "optionalPeers": ["@opentelemetry/api"] }, "sha512-TIH4sohjVJQ9UOSHrqJm+psCX3P6DVnzzB6ltohBMUwPXWvZgk8TTh4K3cMw2HhofvLylUtGe61uf5ReUiECLA=="], + + "@pixiv/types-vrmc-vrm-animation-1.0/@pixiv/types-vrmc-vrm-1.0": ["@pixiv/types-vrmc-vrm-1.0@2.0.3", "", {}, "sha512-RMP34Bk1qLFQv/CRB1Zqvn2qMFfWQfP2Hms5QrrfoBsW9XroZdEe0zPLNbGmUPYh4F7VtBb+B7+RCuymRtpehA=="], + + "@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.6.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-zq/ay+9fNIJJtJiZxdTnXS20PllcYMX3OE23ESc4HK/bdYu3cOWYVhsOhVnXALfU/uqJIxn5NBPd9z4v+SfoSg=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.6.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], + + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.7", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw=="], + + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + + "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "fumadb/kysely": ["kysely@0.28.8", "", {}, "sha512-QUOgl5ZrS9IRuhq5FvOKFSsD/3+IA6MLE81/bOOTRA/YQpKDza2sFdN5g6JCB9BOpqMJDGefLCQ9F12hRS13TA=="], + + "its-fine/@types/react-reconciler": ["@types/react-reconciler@0.28.9", "", { "peerDependencies": { "@types/react": "*" } }, "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg=="], + + "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], + + "next/sharp": ["sharp@0.34.4", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.0", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.4", "@img/sharp-darwin-x64": "0.34.4", "@img/sharp-libvips-darwin-arm64": "1.2.3", "@img/sharp-libvips-darwin-x64": "1.2.3", "@img/sharp-libvips-linux-arm": "1.2.3", "@img/sharp-libvips-linux-arm64": "1.2.3", "@img/sharp-libvips-linux-ppc64": "1.2.3", "@img/sharp-libvips-linux-s390x": "1.2.3", "@img/sharp-libvips-linux-x64": "1.2.3", "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", "@img/sharp-libvips-linuxmusl-x64": "1.2.3", "@img/sharp-linux-arm": "0.34.4", "@img/sharp-linux-arm64": "0.34.4", "@img/sharp-linux-ppc64": "0.34.4", "@img/sharp-linux-s390x": "0.34.4", "@img/sharp-linux-x64": "0.34.4", "@img/sharp-linuxmusl-arm64": "0.34.4", "@img/sharp-linuxmusl-x64": "0.34.4", "@img/sharp-wasm32": "0.34.4", "@img/sharp-win32-arm64": "0.34.4", "@img/sharp-win32-ia32": "0.34.4", "@img/sharp-win32-x64": "0.34.4" } }, "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA=="], + + "react-dom/scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], + + "stacktrace-gps/source-map": ["source-map@0.5.6", "", {}, "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA=="], + + "swetrix/@types/node": ["@types/node@14.18.63", "", {}, "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ=="], + + "tailwind-variants/tailwind-merge": ["tailwind-merge@2.5.4", "", {}, "sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q=="], + + "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "@opentelemetry/sdk-trace-node/@opentelemetry/sdk-trace-base/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="], + + "@orpc/otel/@orpc/shared/type-fest": ["type-fest@5.1.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-wQ531tuWvB6oK+pchHIu5lHe5f5wpSCqB8Kf4dWQRbOYc9HTge7JL0G4Qd44bh6QuJCccIzL3bugb8GI0MwHrg=="], + + "next/sharp/@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.3" }, "os": "darwin", "cpu": "arm64" }, "sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA=="], + + "next/sharp/@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.3" }, "os": "darwin", "cpu": "x64" }, "sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg=="], + + "next/sharp/@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw=="], + + "next/sharp/@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA=="], + + "next/sharp/@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.3", "", { "os": "linux", "cpu": "arm" }, "sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA=="], + + "next/sharp/@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ=="], + + "next/sharp/@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w=="], + + "next/sharp/@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.3", "", { "os": "linux", "cpu": "x64" }, "sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg=="], + + "next/sharp/@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw=="], + + "next/sharp/@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.3", "", { "os": "linux", "cpu": "x64" }, "sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g=="], + + "next/sharp/@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.3" }, "os": "linux", "cpu": "arm" }, "sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA=="], + + "next/sharp/@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.3" }, "os": "linux", "cpu": "arm64" }, "sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ=="], + + "next/sharp/@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.3" }, "os": "linux", "cpu": "s390x" }, "sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw=="], + + "next/sharp/@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.3" }, "os": "linux", "cpu": "x64" }, "sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A=="], + + "next/sharp/@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.3" }, "os": "linux", "cpu": "arm64" }, "sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA=="], + + "next/sharp/@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.3" }, "os": "linux", "cpu": "x64" }, "sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg=="], + + "next/sharp/@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.4", "", { "dependencies": { "@emnapi/runtime": "^1.5.0" }, "cpu": "none" }, "sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA=="], + + "next/sharp/@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw=="], + + "next/sharp/@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.4", "", { "os": "win32", "cpu": "x64" }, "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig=="], + } +} diff --git a/bun.lockb b/bun.lockb deleted file mode 100755 index 82c326b74ceb5f4381d2bc284665d3485ee5e0fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 333793 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%0Aszy=saK0Ta5P4!)Azf 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 diff --git a/bunfig.toml b/bunfig.toml deleted file mode 100644 index d350d26..0000000 --- a/bunfig.toml +++ /dev/null @@ -1,2 +0,0 @@ -[install.scopes] -neodyland = { token = "$GH_NPM_TOKEN", url = "https://npm.pkg.github.com/" } \ No newline at end of file diff --git a/components.json b/components.json new file mode 100644 index 0000000..f826c54 --- /dev/null +++ b/components.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "src/app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": {} +} diff --git a/next.config.mjs b/next.config.mjs index b9a3ffd..5cdd0b4 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -4,6 +4,8 @@ import createNextIntlPlugin from "next-intl/plugin"; const withNextIntl = createNextIntlPlugin(); -const nextConfig = {}; +const nextConfig = { + output: "export", +}; export default withNextIntl(nextConfig); diff --git a/open-next.config.ts b/open-next.config.ts deleted file mode 100644 index 609ed7c..0000000 --- a/open-next.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineCloudflareConfig } from "@opennextjs/cloudflare"; -import kvIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/kv-incremental-cache"; -import doQueue from "@opennextjs/cloudflare/overrides/queue/do-queue"; - -export default defineCloudflareConfig({ - incrementalCache: kvIncrementalCache, - queue: doQueue, -}); diff --git a/package.json b/package.json index fd7ed51..ef4a9f3 100644 --- a/package.json +++ b/package.json @@ -1,54 +1,57 @@ { - "name": "mikn-dev", - "version": "0.1.0", - "private": true, - "scripts": { - "build": "next build", - "dev": "NODE_OPTIONS='--inspect' next dev --turbo", - "format": "biome format --write .", - "lint": "next lint", - "start": "next start", - "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview", - "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy", - "upload": "opennextjs-cloudflare build && opennextjs-cloudflare upload", - "cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts" - }, - "dependencies": { - "@opennextjs/cloudflare": "^1.0.4", - "@pixiv/three-vrm": "^3.3.4", - "@pixiv/three-vrm-animation": "^3.3.4", - "@react-three/fiber": "^9.1.2", - "@swetrix/nextjs": "^1.0.1", - "@tailwindcss/postcss": "^4.1.7", - "@types/three": "^0.176.0", - "caniuse-lite": "^1.0.30001664", - "clsx": "^2.1.1", - "daisyui": "^5.0.0", - "motion": "^11.15.0", - "next": "^15.3.2", - "next-intl": "^4.1.0", - "next-themes": "^0.4.4", - "postcss": "^8.5.3", - "react": "^19.1.0", - "react-cookie-consent": "^9.0.0", - "react-dom": "^19.1.0", - "react-icons": "^5.2.1", - "react-use": "^17.6.0", - "sharp": "^0.33.5", - "shiki": "^1.24.4", - "sonner": "^1.7.1", - "tailwind-merge": "^2.6.0", - "tailwind-variants": "^0.3.0", - "three": "^0.176.0" - }, - "devDependencies": { - "@biomejs/biome": "^1.5.1", - "@opennextjs/aws": "^3.6.4", - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - "tailwindcss": "^4.1.7", - "typescript": "^5", - "wrangler": "^4.16.1" - } + "name": "mikn-dev", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "next build", + "dev": "NODE_OPTIONS='--inspect' next dev --turbo", + "format": "biome format --write .", + "lint": "next lint", + "start": "next start", + "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview", + "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy", + "upload": "opennextjs-cloudflare build && opennextjs-cloudflare upload", + "cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts" + }, + "dependencies": { + "@c15t/nextjs": "^1.7.1", + "@c15t/scripts": "^1.0.0", + "@pixiv/three-vrm": "^3.3.4", + "@pixiv/three-vrm-animation": "^3.3.4", + "@radix-ui/react-slot": "^1.2.3", + "@react-three/fiber": "^9.1.2", + "@swetrix/nextjs": "^1.0.1", + "@tailwindcss/postcss": "^4.1.7", + "@types/three": "^0.176.0", + "caniuse-lite": "^1.0.30001664", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "daisyui": "^5.0.0", + "lucide-react": "^0.548.0", + "motion": "^11.15.0", + "next": "^16.0.0", + "next-intl": "^4.4.0", + "next-themes": "^0.4.4", + "postcss": "^8.5.3", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-icons": "^5.2.1", + "react-use": "^17.6.0", + "sharp": "^0.33.5", + "shiki": "^1.24.4", + "sonner": "^1.7.1", + "tailwind-merge": "^3.3.1", + "tailwind-variants": "^0.3.0", + "tailwindcss-animate": "^1.0.7", + "three": "^0.176.0", + "tw-animate-css": "^1.4.0" + }, + "devDependencies": { + "@biomejs/biome": "^2.3.1", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "tailwindcss": "^4.1.7", + "typescript": "^5" + } } diff --git a/postcss.config.mjs b/postcss.config.mjs index 2a0059f..7059fe9 100644 --- a/postcss.config.mjs +++ b/postcss.config.mjs @@ -1,6 +1,6 @@ const config = { - plugins: { - "@tailwindcss/postcss": {}, - }, + plugins: { + "@tailwindcss/postcss": {}, + }, }; export default config; diff --git a/renovate.json b/renovate.json index ac08426..22a9943 100644 --- a/renovate.json +++ b/renovate.json @@ -1,4 +1,4 @@ { - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": ["config:recommended"] + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:recommended"] } diff --git a/src/app/[locale]/about/page.tsx b/src/app/[locale]/about/page.tsx deleted file mode 100644 index c967216..0000000 --- a/src/app/[locale]/about/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { AiOutlineLoading3Quarters } from "react-icons/ai"; - -export default async function Home() { - return ( -
- -
- ); -} diff --git a/src/app/[locale]/contact/page.tsx b/src/app/[locale]/contact/page.tsx deleted file mode 100644 index 541504c..0000000 --- a/src/app/[locale]/contact/page.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import Link from "next/link"; - -import { useTranslations } from "next-intl"; - -import { IoMdMail } from "react-icons/io"; -import { - MdPhone, - MdSupportAgent, - MdMonetizationOn, - MdWarning, -} from "react-icons/md"; -import { FaDiscord } from "react-icons/fa"; - -export default function Home() { - const t = useTranslations("contact"); - return ( -
-
-

- {t("title")} -

-
-
-
- -

{t("mail")}

-
-
-
- -

hello@mikn.dev

-
-
- -

billing@mikn.dev

-
-
- -

abuse@mikn.dev

-
-
-
-
-
-
-
- -

- {t("phone")} -

-
-
-

+81 090-9276-3628

-
-
-
-
-
-
- -

- {t("discord")} -

-
-
- - - -
-
-
-

{t("phone-disclaimer")}

-
-
- ); -} diff --git a/src/app/[locale]/cost/page.tsx b/src/app/[locale]/cost/page.tsx deleted file mode 100644 index c967216..0000000 --- a/src/app/[locale]/cost/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { AiOutlineLoading3Quarters } from "react-icons/ai"; - -export default async function Home() { - return ( -
- -
- ); -} diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx index 42f2881..fd9a51f 100644 --- a/src/app/[locale]/layout.tsx +++ b/src/app/[locale]/layout.tsx @@ -11,45 +11,43 @@ import "../globals.css"; const hsr = localFont({ src: "../../assets/fonts/HSR.woff2" }); export const metadata: Metadata = { - title: "MikanDev", - description: "We make cool stuff to make life easier 🍊", - openGraph: { - images: ["https://mikn.dev/img/og-homepage.png"], - }, + title: "MikanDev", + description: "We make cool stuff to make life easier 🍊", + openGraph: { + images: ["https://mikn.dev/img/og-homepage.png"], + }, }; interface LocaleLayoutProps { - children: ReactNode; - params: Promise<{ locale: string }>; + children: ReactNode; + params: Promise<{ locale: string }>; } export function generateStaticParams() { - return routing.locales.map((locale) => ({ locale })); + return routing.locales.map((locale) => ({ locale })); } export default async function LocaleLayout({ - children, - params, + children, + params, }: LocaleLayoutProps) { - const { locale } = await params; - - // Ensure that the incoming `locale` is valid - if (!routing.locales.includes(locale as any)) { - notFound(); - } - - setRequestLocale(locale); - // Providing all messages to the client - // side is the easiest way to get started - const messages = await getMessages(); - return ( - - - - {children} - - - - - ); + const { locale } = await params; + + if (!routing.locales.includes(locale as any)) { + notFound(); + } + + setRequestLocale(locale); + + const messages = await getMessages(); + return ( + + + + {children} + + + + + ); } diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx index a931df9..98d337c 100644 --- a/src/app/[locale]/page.tsx +++ b/src/app/[locale]/page.tsx @@ -1,305 +1,15 @@ -import Image from "next/image"; -import Link from "next/link"; -import { useTranslations } from "next-intl"; -import Typewriter from "@/components/fancy/typewriter"; -import { NumberTicker } from "@/components/fancy/NumberTicker"; -import { Marquee } from "@/components/fancy/marqee"; -import { VRM } from "@/components/vrm"; +import { Button } from "@/components/ui/button"; +import { setRequestLocale, getTranslations } from "next-intl/server"; -import { TbBrandOpenSource, TbWallet, TbPigMoney } from "react-icons/tb"; +export default async function IndexPage(params: Promise<{ locale: string }>) { + const { locale } = await params; -import mikan from "@/assets/img/mikan.png"; -import HeartMascot from "@/assets/img/MDHeart.png"; -import NeodyLogo from "@/assets/img/NeodyLogo.png"; -import RTLogo from "@/assets/img/rt.png"; -import KuronekoLogo from "@/assets/img/kuroneko.png"; -import TakasumiLogo from "@/assets/img/takasumi.png"; + setRequestLocale(locale); -export default function Home() { - const t = useTranslations("home"); - return ( -
-
-
- -
- -

- Backed by my own pocket money -

-
- -
-

- {t("creating-cool")} -

- -
-

- {t("makeLifeEasier")} -

-

- {t("mainBlurb1")} -

-

- {t("mainBlurb2")} -

-
- - - - - - -
-
-
- -
-
- -
-
-

- {t("infoTitle")} -

-

- {t("infoBlurb")} -

-
- -
-
- {"Mascot - -
-

- {t("OSSonOSS")} -

-

- {t("OSSonOSSBlurb")} -

-
-

- {t("partOfPage")} -

-
- - - - -
- - {"Mascot -
-

- {t("SimpleNCheap")} -

-

- {t("SimpleNCheapBlurb")} -

-
-
-
-
-

~$

- -
- {t("monthlyCost")} -
-
-
-
-
-

0

-
- {t("MAUBilled")} -
-
-
-

- {t("despite")} -

-
-
-
-
- -

- {" "} - +TB -

-
- {t("monthlyBandwidth")} -
-
-
-
-
- -

+

-
- {t("mainServices")} -
-
-
-
-
- -

%

-
- {t("monthlyUptime")} -
-
-
- - - - -
- {"Mikan"} -
-

- {t("SelfFunded")} -

-

- {t("SelfFundedBlurb")} -

- -
- {"Mascot -
-

- {t("WorkWithBest")} -

-

- {t("WorkWithBestBlurb")} -

- - - - {"Neody"} - - - {"RT"} - - - {"Kuroneko"} - - - {"Takasumi"} - - - - - - - -
- -

- {t("NoWait")} -

-

- {t("NoWaitBlurb")} -

- - - -
-
-
- ); + const t = await getTranslations("HomePage"); + return ( + <> + + + ); } diff --git a/src/app/[locale]/solutions/page.tsx b/src/app/[locale]/solutions/page.tsx deleted file mode 100644 index 9006478..0000000 --- a/src/app/[locale]/solutions/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { AiOutlineLoading3Quarters } from "react-icons/ai"; - -export default async function Home() { - return ( -
- -
- ); -} diff --git a/src/app/[locale]/tech/page.tsx b/src/app/[locale]/tech/page.tsx deleted file mode 100644 index c967216..0000000 --- a/src/app/[locale]/tech/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { AiOutlineLoading3Quarters } from "react-icons/ai"; - -export default async function Home() { - return ( -
- -
- ); -} diff --git a/src/app/[locale]/template.tsx b/src/app/[locale]/template.tsx index 234491f..19a4d82 100644 --- a/src/app/[locale]/template.tsx +++ b/src/app/[locale]/template.tsx @@ -1,197 +1,18 @@ "use client"; import { useTranslations } from "next-intl"; -import { Header } from "@/components/nUI/Header"; -import { Footer } from "@/components/nUI/Footer"; -import Image from "next/image"; -import mikanLogo from "@/assets/img/mikan.png"; -import MikanCat from "@/assets/img/mikan-cat.png"; -import KawaiiLogo from "@/assets/img/mikan-vtube.svg"; -import { useSwetrix } from '@swetrix/nextjs' +import { useSwetrix } from "@swetrix/nextjs"; import { useRouter, usePathname } from "next/navigation"; -import CookieConsent from "react-cookie-consent"; import { ReactNode } from "react"; -import { FaDiscord, FaGithub, FaTwitter } from "react-icons/fa"; -import { SiMisskey } from "react-icons/si"; - export default function PagesLayout({ children }: { children: ReactNode }) { - const router = useRouter(); - const pathname = usePathname(); - const t = useTranslations("nav"); - useSwetrix("XxNIMaHCaVG3", { apiURL: "https://analytics.mikandev.tech/log" }) - - const changeLanguage = () => { - //@ts-ignore - const pathSegments = pathname.split("/"); - if (pathSegments[1] === "en") { - pathSegments[1] = "ja"; - } else if (pathSegments[1] === "ja") { - pathSegments[1] = "en"; - } - const newPath = pathSegments.join("/"); - router.push(newPath); - }; - - const nav = [ - { - name: t("support"), - href: "/contact", - }, - { - name: t("docs"), - href: "https://docs.mikn.dev/", - }, - { - name: t("solutions"), - href: "/solutions", - }, - { - name: t("legal"), - href: "https://docs.mikn.dev/legal/", - }, - { - name: t("payments"), - href: "https://payments.mikandev.com/", - }, - ]; - - const social = [ - { - name: "GitHub", - href: "https://github.com/mikndotdev", - color: "hover:text-github hover:bg-github", - icon: FaGithub, - }, - { - name: "Twitter", - href: "https://twitter.com/kunkunmaamo", - color: "hover:text-twitter hover:bg-twitter", - icon: FaTwitter, - }, - { - name: "Discord", - href: "https://discord.gg/FZCN6fjPuG", - color: "hover:text-discord hover:bg-discord", - icon: FaDiscord, - }, - { - name: "Misskey Server", - href: "https://ekaki.art/", - color: "hover:text-misskey hover:bg-misskey", - icon: SiMisskey, - }, - ]; - - const links = [ - { - name: t("resources"), - children: [ - { - name: t("payments"), - href: "https://payments.mikandev.com/", - }, - { - name: t("solutions"), - href: "https:/mikn.dev/solutions", - }, - { - name: t("blog"), - href: "https://blog.mikn.dev/", - }, - ], - }, - { - name: t("support"), - children: [ - { - name: t("discord"), - href: "https://discord.gg/FZCN6fjPuG", - }, - { - name: t("contact"), - href: "https://mikn.dev/contact", - }, - ], - }, - { - name: t("legal"), - children: [ - { - name: t("terms"), - href: "https://docs.mikn.dev/legal/terms", - }, - { - name: t("privacy"), - href: "https://docs.mikn.dev/legal/privacy", - }, - { - name: t("jp-payments"), - href: "https://docs.mikn.dev/legal/jp-payments", - }, - ], - }, - ]; - - const buttons = [ - { - href: "https://my.mikandev.com/init?url=https://mikn.dev", - title: t("myAccount"), - }, - { - title: "🌎", - onClick: () => { - changeLanguage(); - }, - }, - ]; - - return ( - <> -
-
- {children} - {}} - > - {t("cookieConsent")} - -
-
-
-
- MikanDev Tech -
-
-
- - ); + const router = useRouter(); + const pathname = usePathname(); + const t = useTranslations("nav"); + useSwetrix("XxNIMaHCaVG3", { apiURL: "https://analytics.mikandev.tech/log" }); + + return ( + <> +
{children}
+ + ); } diff --git a/src/app/consent-manager.client.tsx b/src/app/consent-manager.client.tsx new file mode 100644 index 0000000..7c0a6f3 --- /dev/null +++ b/src/app/consent-manager.client.tsx @@ -0,0 +1,55 @@ +"use client"; + +import type { ReactNode } from "react"; +import { ClientSideOptionsProvider } from "@c15t/nextjs/client"; + +/** + * Client-side consent manager wrapper for handling scripts and callbacks + * + * This component is rendered on the client and provides the ability to: + * - Load integration scripts (Google Tag Manager, Meta Pixel, TikTok Pixel, etc.) + * - Handle client-side callbacks (onConsentSet, onError, onBannerFetched) + * - Manage script lifecycle (onLoad, onDelete) + * + * @param props - Component properties + * @param props.children - Child components to render within the client-side context + * + * @returns The client-side options provider with children + * + * @see https://c15t.com/docs/frameworks/next/callbacks + * @see https://c15t.com/docs/frameworks/next/script-loader + */ +export function ConsentManagerClient({ children }: { children: ReactNode }) { + return ( + console.log('GTM loaded'), + // }, + // }), + ] + } + // 📝 Add your callbacks here + // Callbacks allow you to react to consent events + callbacks={ + { + // Example: + // onConsentSet(response) { + // console.log('Consent updated:', response); + // }, + // onError(error) { + // console.error('Consent error:', error); + // }, + } + } + > + {children} + + ); +} diff --git a/src/app/consent-manager.tsx b/src/app/consent-manager.tsx new file mode 100644 index 0000000..e7fa8f1 --- /dev/null +++ b/src/app/consent-manager.tsx @@ -0,0 +1,20 @@ +import type { ReactNode } from "react"; +import { + ConsentManagerDialog, + ConsentManagerProvider, + CookieBanner, +} from "@c15t/nextjs/client"; + +export function ConsentManager({ children }: { children: ReactNode }) { + return ( + + + + {children} + + ); +} diff --git a/src/app/globals.css b/src/app/globals.css index 96a77d7..4e354cd 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,26 +1,188 @@ -@import 'tailwindcss'; +@import "tailwindcss"; -@config '../.././tailwind.config.ts'; +@plugin "tailwindcss-animate"; +@import "tw-animate-css"; -@layer base { - *, - ::after, - ::before, - ::backdrop, - ::file-selector-button { - border-color: var(--color-gray-200, currentColor); - } +@custom-variant dark (&:is(.dark *)); + +:root { + --background: #2d1800; + --foreground: #ffffff; + --card: #663d00; + --card-foreground: #fafafa; + --popover: #262626; + --popover-foreground: #fafafa; + --primary: #ff9900; + --primary-foreground: #ffffff; + --secondary: #ff7700; + --secondary-foreground: #ffffff; + --muted: #663d00; + --muted-foreground: #ffffff; + --accent: #ff7700; + --accent-foreground: #ffffff; + --destructive: #ff6467; + --destructive-foreground: #fafafa; + --border: #ff9900; + --input: #ff9900; + --ring: #ffffff; + --chart-1: #ff7700; + --chart-2: #2d1800; + --chart-3: #995c00; + --chart-4: #ff0000; + --chart-5: #1f3fad; + --sidebar: #2d1800; + --sidebar-foreground: #fafafa; + --sidebar-primary: #1447e6; + --sidebar-primary-foreground: #fafafa; + --sidebar-accent: #ff7700; + --sidebar-accent-foreground: #fafafa; + --sidebar-border: #ff9900; + --sidebar-ring: #525252; + --font-sans: + ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; + --font-mono: + ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", + "Courier New", monospace; + --radius: 0.625rem; + --shadow-x: 0; + --shadow-y: 1px; + --shadow-blur: 3px; + --shadow-spread: 0px; + --shadow-opacity: 0.1; + --shadow-color: oklch(0 0 0); + --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-sm: + 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1); + --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1); + --shadow-md: + 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 2px 4px -1px hsl(0 0% 0% / 0.1); + --shadow-lg: + 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 4px 6px -1px hsl(0 0% 0% / 0.1); + --shadow-xl: + 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 8px 10px -1px hsl(0 0% 0% / 0.1); + --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); } -body { - color: #2d1800; - background: #2d1800 +.dark { + --background: #2d1800; + --foreground: #ffffff; + --card: #663d00; + --card-foreground: #fafafa; + --popover: #262626; + --popover-foreground: #fafafa; + --primary: #ff9900; + --primary-foreground: #ffffff; + --secondary: #ff7700; + --secondary-foreground: #ffffff; + --muted: #663d00; + --muted-foreground: #ffffff; + --accent: #ff7700; + --accent-foreground: #ffffff; + --destructive: #ff6467; + --destructive-foreground: #fafafa; + --border: #ff9900; + --input: #ff9900; + --ring: #ffffff; + --chart-1: #ff7700; + --chart-2: #2d1800; + --chart-3: #995c00; + --chart-4: #ff0000; + --chart-5: #1f3fad; + --sidebar: #2d1800; + --sidebar-foreground: #fafafa; + --sidebar-primary: #1447e6; + --sidebar-primary-foreground: #fafafa; + --sidebar-accent: #ff7700; + --sidebar-accent-foreground: #fafafa; + --sidebar-border: #ff9900; + --sidebar-ring: #525252; + --font-sans: + ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; + --font-mono: + ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", + "Courier New", monospace; + --radius: 0.625rem; + --shadow-x: 0; + --shadow-y: 1px; + --shadow-blur: 3px; + --shadow-spread: 0px; + --shadow-opacity: 0.1; + --shadow-color: oklch(0 0 0); + --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-sm: + 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1); + --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1); + --shadow-md: + 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 2px 4px -1px hsl(0 0% 0% / 0.1); + --shadow-lg: + 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 4px 6px -1px hsl(0 0% 0% / 0.1); + --shadow-xl: + 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 8px 10px -1px hsl(0 0% 0% / 0.1); + --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-destructive-foreground: var(--destructive-foreground); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); + + --font-sans: var(--font-sans); + --font-mono: var(--font-mono); + --font-serif: var(--font-serif); + + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + + --shadow-2xs: var(--shadow-2xs); + --shadow-xs: var(--shadow-xs); + --shadow-sm: var(--shadow-sm); + --shadow: var(--shadow); + --shadow-md: var(--shadow-md); + --shadow-lg: var(--shadow-lg); + --shadow-xl: var(--shadow-xl); + --shadow-2xl: var(--shadow-2xl); } -@plugin "daisyui"; -@plugin "daisyui/theme" { - name: "mikn"; - default: true; /* set as default */ - --color-primary: #ff9900; - --color-secondary: #ff7700; -} \ No newline at end of file +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index b1c9b6a..95763b1 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,11 +1,16 @@ import { ReactNode } from "react"; import type { Metadata } from "next"; +import { ConsentManager } from "./consent-manager"; export const metadata: Metadata = { - title: "MikanDev", - description: "We make cool stuff to make life easier 🍊", + title: "MikanDev", + description: "We make cool stuff to make life easier 🍊", }; export default function RootLayout({ children }: { children: ReactNode }) { - return <>{children}; + return ( + + <>{children} + + ); } diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx index e378cef..c7934ff 100644 --- a/src/app/not-found.tsx +++ b/src/app/not-found.tsx @@ -5,24 +5,22 @@ import "./globals.css"; const hsr = localFont({ src: ".././assets/fonts/HSR.woff2" }); export default function NotFound() { - return ( - <> - - -
-

- 404 - Page Not Found -

- - - -
- - - - ); + return ( + <> + + +
+

+ 404 - Page Not Found +

+ + + +
+ + + + ); } diff --git a/src/components/cn.ts b/src/components/cn.ts index 3200be2..a5ef193 100644 --- a/src/components/cn.ts +++ b/src/components/cn.ts @@ -2,5 +2,5 @@ import { clsx, type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); + return twMerge(clsx(inputs)); } diff --git a/src/components/codecomp-v3v4.tsx b/src/components/codecomp-v3v4.tsx deleted file mode 100644 index 3abcfb3..0000000 --- a/src/components/codecomp-v3v4.tsx +++ /dev/null @@ -1,67 +0,0 @@ -export const beforeCode = ` -
- MikanDev -
- - {t("below-main-heading")} - -
- - -
-
`; - -export const afterCode = `
-
- -

- Backed by my own pocket money -

-
-
-

- {t("creating-cool")} -

- -`; diff --git a/src/components/fancy/NumberTicker.tsx b/src/components/fancy/NumberTicker.tsx index feacd0b..bab26dd 100644 --- a/src/components/fancy/NumberTicker.tsx +++ b/src/components/fancy/NumberTicker.tsx @@ -6,53 +6,53 @@ import { useInView, useMotionValue, useSpring } from "motion/react"; import { cn } from "../cn"; export function NumberTicker({ - value, - direction = "up", - delay = 0, - className, - decimalPlaces = 0, + value, + direction = "up", + delay = 0, + className, + decimalPlaces = 0, }: { - value: number; - direction?: "up" | "down"; - className?: string; - delay?: number; // delay in s - decimalPlaces?: number; + value: number; + direction?: "up" | "down"; + className?: string; + delay?: number; // delay in s + decimalPlaces?: number; }) { - const ref = useRef(null); - const motionValue = useMotionValue(direction === "down" ? value : 0); - const springValue = useSpring(motionValue, { - damping: 60, - stiffness: 100, - }); - const isInView = useInView(ref, { once: true, margin: "0px" }); + const ref = useRef(null); + const motionValue = useMotionValue(direction === "down" ? value : 0); + const springValue = useSpring(motionValue, { + damping: 60, + stiffness: 100, + }); + const isInView = useInView(ref, { once: true, margin: "0px" }); - useEffect(() => { - isInView && - setTimeout(() => { - motionValue.set(direction === "down" ? 0 : value); - }, delay * 1000); - }, [motionValue, isInView, delay, value, direction]); + useEffect(() => { + isInView && + setTimeout(() => { + motionValue.set(direction === "down" ? 0 : value); + }, delay * 1000); + }, [motionValue, isInView, delay, value, direction]); - useEffect( - () => - springValue.on("change", (latest) => { - if (ref.current) { - ref.current.textContent = Intl.NumberFormat("en-US", { - minimumFractionDigits: decimalPlaces, - maximumFractionDigits: decimalPlaces, - }).format(Number(latest.toFixed(decimalPlaces))); - } - }), - [springValue, decimalPlaces], - ); + useEffect( + () => + springValue.on("change", (latest) => { + if (ref.current) { + ref.current.textContent = Intl.NumberFormat("en-US", { + minimumFractionDigits: decimalPlaces, + maximumFractionDigits: decimalPlaces, + }).format(Number(latest.toFixed(decimalPlaces))); + } + }), + [springValue, decimalPlaces], + ); - return ( - - ); + return ( + + ); } diff --git a/src/components/fancy/code-comp.tsx b/src/components/fancy/code-comp.tsx index b18db7e..d5a55aa 100644 --- a/src/components/fancy/code-comp.tsx +++ b/src/components/fancy/code-comp.tsx @@ -6,100 +6,96 @@ import { useEffect, useState } from "react"; import { codeToHtml } from "shiki"; interface CodeComparisonProps { - beforeCode: string; - afterCode: string; - language: string; - filename: string; - lightTheme: string; - darkTheme: string; - beforeTitle: string; - afterTitle: string; + beforeCode: string; + afterCode: string; + language: string; + filename: string; + lightTheme: string; + darkTheme: string; + beforeTitle: string; + afterTitle: string; } export function CodeComparison({ - beforeCode, - afterCode, - language, - filename, - lightTheme, - darkTheme, - beforeTitle, - afterTitle, + beforeCode, + afterCode, + language, + filename, + lightTheme, + darkTheme, + beforeTitle, + afterTitle, }: CodeComparisonProps) { - const { theme, systemTheme } = useTheme(); - const [highlightedBefore, setHighlightedBefore] = useState(""); - const [highlightedAfter, setHighlightedAfter] = useState(""); + const { theme, systemTheme } = useTheme(); + const [highlightedBefore, setHighlightedBefore] = useState(""); + const [highlightedAfter, setHighlightedAfter] = useState(""); - useEffect(() => { - const currentTheme = theme === "system" ? systemTheme : theme; - const selectedTheme = currentTheme === "dark" ? darkTheme : lightTheme; + useEffect(() => { + const currentTheme = theme === "system" ? systemTheme : theme; + const selectedTheme = currentTheme === "dark" ? darkTheme : lightTheme; - async function highlightCode() { - const before = await codeToHtml(beforeCode, { - lang: language, - theme: selectedTheme, - }); - const after = await codeToHtml(afterCode, { - lang: language, - theme: selectedTheme, - }); - setHighlightedBefore(before); - setHighlightedAfter(after); - } + async function highlightCode() { + const before = await codeToHtml(beforeCode, { + lang: language, + theme: selectedTheme, + }); + const after = await codeToHtml(afterCode, { + lang: language, + theme: selectedTheme, + }); + setHighlightedBefore(before); + setHighlightedAfter(after); + } - highlightCode(); - }, [ - theme, - systemTheme, - beforeCode, - afterCode, - language, - lightTheme, - darkTheme, - ]); + highlightCode(); + }, [ + theme, + systemTheme, + beforeCode, + afterCode, + language, + lightTheme, + darkTheme, + ]); - const renderCode = (code: string, highlighted: string) => { - if (highlighted) { - return ( -
- ); - } else { - return ( -
-					{code}
-				
- ); - } - }; - return ( -
-
-
-
-
- - {filename} - - {beforeTitle} - -
- {renderCode(beforeCode, highlightedBefore)} -
-
-
- - {filename} - - {afterTitle} - -
- {renderCode(afterCode, highlightedAfter)} -
-
-
-
- ); + const renderCode = (code: string, highlighted: string) => { + if (highlighted) { + return ( +
+ ); + } else { + return ( +
+          {code}
+        
+ ); + } + }; + return ( +
+
+
+
+
+ + {filename} + {beforeTitle} +
+ {renderCode(beforeCode, highlightedBefore)} +
+
+
+ + {filename} + {afterTitle} +
+ {renderCode(afterCode, highlightedAfter)} +
+
+
+
+ ); } diff --git a/src/components/fancy/icon-cloud.tsx b/src/components/fancy/icon-cloud.tsx index 6e19714..1e9ffc2 100644 --- a/src/components/fancy/icon-cloud.tsx +++ b/src/components/fancy/icon-cloud.tsx @@ -4,347 +4,321 @@ import React, { useEffect, useRef, useState } from "react"; import { renderToString } from "react-dom/server"; interface Icon { - x: number; - y: number; - z: number; - scale: number; - opacity: number; - id: number; + x: number; + y: number; + z: number; + scale: number; + opacity: number; + id: number; } interface IconCloudProps { - icons?: React.ReactNode[]; - images?: string[]; + icons?: React.ReactNode[]; + images?: string[]; } function easeOutCubic(t: number): number { - return 1 - Math.pow(1 - t, 3); + return 1 - Math.pow(1 - t, 3); } export function IconCloud({ icons, images }: IconCloudProps) { - const canvasRef = useRef(null); - const [iconPositions, setIconPositions] = useState([]); - const [rotation, setRotation] = useState({ x: 0, y: 0 }); - const [isDragging, setIsDragging] = useState(false); - const [lastMousePos, setLastMousePos] = useState({ x: 0, y: 0 }); - const [mousePos, setMousePos] = useState({ x: 0, y: 0 }); - const [targetRotation, setTargetRotation] = useState<{ - x: number; - y: number; - startX: number; - startY: number; - distance: number; - startTime: number; - duration: number; - } | null>(null); - const animationFrameRef = useRef(); - const rotationRef = useRef(rotation); - const iconCanvasesRef = useRef([]); - const imagesLoadedRef = useRef([]); - - // Create icon canvases once when icons/images change - useEffect(() => { - if (!icons && !images) return; - - const items = icons || images || []; - imagesLoadedRef.current = new Array(items.length).fill(false); - - const newIconCanvases = items.map((item, index) => { - const offscreen = document.createElement("canvas"); - offscreen.width = 40; - offscreen.height = 40; - const offCtx = offscreen.getContext("2d"); - - if (offCtx) { - if (images) { - // Handle image URLs directly - const img = new Image(); - img.crossOrigin = "anonymous"; - img.src = items[index] as string; - img.onload = () => { - offCtx.clearRect( - 0, - 0, - offscreen.width, - offscreen.height, - ); - - // Create circular clipping path - offCtx.beginPath(); - offCtx.arc(20, 20, 20, 0, Math.PI * 2); - offCtx.closePath(); - offCtx.clip(); - - // Draw the image - offCtx.drawImage(img, 0, 0, 40, 40); - - imagesLoadedRef.current[index] = true; - }; - } else { - // Handle SVG icons - offCtx.scale(0.4, 0.4); - const svgString = renderToString( - item as React.ReactElement, - ); - const img = new Image(); - img.src = "data:image/svg+xml;base64," + btoa(svgString); - img.onload = () => { - offCtx.clearRect( - 0, - 0, - offscreen.width, - offscreen.height, - ); - offCtx.drawImage(img, 0, 0); - imagesLoadedRef.current[index] = true; - }; - } - } - return offscreen; - }); - - iconCanvasesRef.current = newIconCanvases; - }, [icons, images]); - - // Generate initial icon positions on a sphere - useEffect(() => { - const items = icons || images || []; - const newIcons: Icon[] = []; - const numIcons = items.length || 20; - - // Fibonacci sphere parameters - const offset = 2 / numIcons; - const increment = Math.PI * (3 - Math.sqrt(5)); - - for (let i = 0; i < numIcons; i++) { - const y = i * offset - 1 + offset / 2; - const r = Math.sqrt(1 - y * y); - const phi = i * increment; - - const x = Math.cos(phi) * r; - const z = Math.sin(phi) * r; - - newIcons.push({ - x: x * 100, - y: y * 100, - z: z * 100, - scale: 1, - opacity: 1, - id: i, - }); - } - setIconPositions(newIcons); - }, [icons, images]); - - // Handle mouse events - const handleMouseDown = (e: React.MouseEvent) => { - const rect = canvasRef.current?.getBoundingClientRect(); - if (!rect || !canvasRef.current) return; - - const x = e.clientX - rect.left; - const y = e.clientY - rect.top; - - const ctx = canvasRef.current.getContext("2d"); - if (!ctx) return; - - iconPositions.forEach((icon) => { - const cosX = Math.cos(rotationRef.current.x); - const sinX = Math.sin(rotationRef.current.x); - const cosY = Math.cos(rotationRef.current.y); - const sinY = Math.sin(rotationRef.current.y); - - const rotatedX = icon.x * cosY - icon.z * sinY; - const rotatedZ = icon.x * sinY + icon.z * cosY; - const rotatedY = icon.y * cosX + rotatedZ * sinX; - - const screenX = canvasRef.current!.width / 2 + rotatedX; - const screenY = canvasRef.current!.height / 2 + rotatedY; - - const scale = (rotatedZ + 200) / 300; - const radius = 20 * scale; - const dx = x - screenX; - const dy = y - screenY; - - if (dx * dx + dy * dy < radius * radius) { - const targetX = -Math.atan2( - icon.y, - Math.sqrt(icon.x * icon.x + icon.z * icon.z), - ); - const targetY = Math.atan2(icon.x, icon.z); - - const currentX = rotationRef.current.x; - const currentY = rotationRef.current.y; - const distance = Math.sqrt( - Math.pow(targetX - currentX, 2) + - Math.pow(targetY - currentY, 2), - ); - - const duration = Math.min(2000, Math.max(800, distance * 1000)); - - setTargetRotation({ - x: targetX, - y: targetY, - startX: currentX, - startY: currentY, - distance, - startTime: performance.now(), - duration, - }); - return; - } - }); - - setIsDragging(true); - setLastMousePos({ x: e.clientX, y: e.clientY }); - }; - - const handleMouseMove = (e: React.MouseEvent) => { - const rect = canvasRef.current?.getBoundingClientRect(); - if (rect) { - const x = e.clientX - rect.left; - const y = e.clientY - rect.top; - setMousePos({ x, y }); - } - - if (isDragging) { - const deltaX = e.clientX - lastMousePos.x; - const deltaY = e.clientY - lastMousePos.y; - - rotationRef.current = { - x: rotationRef.current.x + deltaY * 0.002, - y: rotationRef.current.y + deltaX * 0.002, - }; - - setLastMousePos({ x: e.clientX, y: e.clientY }); - } - }; - - const handleMouseUp = () => { - setIsDragging(false); - }; - - // Animation and rendering - useEffect(() => { - const canvas = canvasRef.current; - const ctx = canvas?.getContext("2d"); - if (!canvas || !ctx) return; - - const animate = () => { - ctx.clearRect(0, 0, canvas.width, canvas.height); - - const centerX = canvas.width / 2; - const centerY = canvas.height / 2; - const maxDistance = Math.sqrt( - centerX * centerX + centerY * centerY, - ); - const dx = mousePos.x - centerX; - const dy = mousePos.y - centerY; - const distance = Math.sqrt(dx * dx + dy * dy); - const speed = 0.003 + (distance / maxDistance) * 0.01; - - if (targetRotation) { - const elapsed = performance.now() - targetRotation.startTime; - const progress = Math.min(1, elapsed / targetRotation.duration); - const easedProgress = easeOutCubic(progress); - - rotationRef.current = { - x: - targetRotation.startX + - (targetRotation.x - targetRotation.startX) * - easedProgress, - y: - targetRotation.startY + - (targetRotation.y - targetRotation.startY) * - easedProgress, - }; - - if (progress >= 1) { - setTargetRotation(null); - } - } else if (!isDragging) { - rotationRef.current = { - x: rotationRef.current.x + (dy / canvas.height) * speed, - y: rotationRef.current.y + (dx / canvas.width) * speed, - }; - } - - iconPositions.forEach((icon, index) => { - const cosX = Math.cos(rotationRef.current.x); - const sinX = Math.sin(rotationRef.current.x); - const cosY = Math.cos(rotationRef.current.y); - const sinY = Math.sin(rotationRef.current.y); - - const rotatedX = icon.x * cosY - icon.z * sinY; - const rotatedZ = icon.x * sinY + icon.z * cosY; - const rotatedY = icon.y * cosX + rotatedZ * sinX; - - const scale = (rotatedZ + 200) / 300; - const opacity = Math.max( - 0.2, - Math.min(1, (rotatedZ + 150) / 200), - ); - - ctx.save(); - ctx.translate( - canvas.width / 2 + rotatedX, - canvas.height / 2 + rotatedY, - ); - ctx.scale(scale, scale); - ctx.globalAlpha = opacity; - - if (icons || images) { - // Only try to render icons/images if they exist - if ( - iconCanvasesRef.current[index] && - imagesLoadedRef.current[index] - ) { - ctx.drawImage( - iconCanvasesRef.current[index], - -20, - -20, - 40, - 40, - ); - } - } else { - // Show numbered circles if no icons/images are provided - ctx.beginPath(); - ctx.arc(0, 0, 20, 0, Math.PI * 2); - ctx.fillStyle = "#4444ff"; - ctx.fill(); - ctx.fillStyle = "white"; - ctx.textAlign = "center"; - ctx.textBaseline = "middle"; - ctx.font = "16px Arial"; - ctx.fillText(`${icon.id + 1}`, 0, 0); - } - - ctx.restore(); - }); - animationFrameRef.current = requestAnimationFrame(animate); - }; - - animate(); - - return () => { - if (animationFrameRef.current) { - cancelAnimationFrame(animationFrameRef.current); - } - }; - }, [icons, images, iconPositions, isDragging, mousePos, targetRotation]); - - return ( - - ); + const canvasRef = useRef(null); + const [iconPositions, setIconPositions] = useState([]); + const [rotation, setRotation] = useState({ x: 0, y: 0 }); + const [isDragging, setIsDragging] = useState(false); + const [lastMousePos, setLastMousePos] = useState({ x: 0, y: 0 }); + const [mousePos, setMousePos] = useState({ x: 0, y: 0 }); + const [targetRotation, setTargetRotation] = useState<{ + x: number; + y: number; + startX: number; + startY: number; + distance: number; + startTime: number; + duration: number; + } | null>(null); + const animationFrameRef = useRef(); + const rotationRef = useRef(rotation); + const iconCanvasesRef = useRef([]); + const imagesLoadedRef = useRef([]); + + // Create icon canvases once when icons/images change + useEffect(() => { + if (!icons && !images) return; + + const items = icons || images || []; + imagesLoadedRef.current = new Array(items.length).fill(false); + + const newIconCanvases = items.map((item, index) => { + const offscreen = document.createElement("canvas"); + offscreen.width = 40; + offscreen.height = 40; + const offCtx = offscreen.getContext("2d"); + + if (offCtx) { + if (images) { + // Handle image URLs directly + const img = new Image(); + img.crossOrigin = "anonymous"; + img.src = items[index] as string; + img.onload = () => { + offCtx.clearRect(0, 0, offscreen.width, offscreen.height); + + // Create circular clipping path + offCtx.beginPath(); + offCtx.arc(20, 20, 20, 0, Math.PI * 2); + offCtx.closePath(); + offCtx.clip(); + + // Draw the image + offCtx.drawImage(img, 0, 0, 40, 40); + + imagesLoadedRef.current[index] = true; + }; + } else { + // Handle SVG icons + offCtx.scale(0.4, 0.4); + const svgString = renderToString(item as React.ReactElement); + const img = new Image(); + img.src = "data:image/svg+xml;base64," + btoa(svgString); + img.onload = () => { + offCtx.clearRect(0, 0, offscreen.width, offscreen.height); + offCtx.drawImage(img, 0, 0); + imagesLoadedRef.current[index] = true; + }; + } + } + return offscreen; + }); + + iconCanvasesRef.current = newIconCanvases; + }, [icons, images]); + + // Generate initial icon positions on a sphere + useEffect(() => { + const items = icons || images || []; + const newIcons: Icon[] = []; + const numIcons = items.length || 20; + + // Fibonacci sphere parameters + const offset = 2 / numIcons; + const increment = Math.PI * (3 - Math.sqrt(5)); + + for (let i = 0; i < numIcons; i++) { + const y = i * offset - 1 + offset / 2; + const r = Math.sqrt(1 - y * y); + const phi = i * increment; + + const x = Math.cos(phi) * r; + const z = Math.sin(phi) * r; + + newIcons.push({ + x: x * 100, + y: y * 100, + z: z * 100, + scale: 1, + opacity: 1, + id: i, + }); + } + setIconPositions(newIcons); + }, [icons, images]); + + // Handle mouse events + const handleMouseDown = (e: React.MouseEvent) => { + const rect = canvasRef.current?.getBoundingClientRect(); + if (!rect || !canvasRef.current) return; + + const x = e.clientX - rect.left; + const y = e.clientY - rect.top; + + const ctx = canvasRef.current.getContext("2d"); + if (!ctx) return; + + iconPositions.forEach((icon) => { + const cosX = Math.cos(rotationRef.current.x); + const sinX = Math.sin(rotationRef.current.x); + const cosY = Math.cos(rotationRef.current.y); + const sinY = Math.sin(rotationRef.current.y); + + const rotatedX = icon.x * cosY - icon.z * sinY; + const rotatedZ = icon.x * sinY + icon.z * cosY; + const rotatedY = icon.y * cosX + rotatedZ * sinX; + + const screenX = canvasRef.current!.width / 2 + rotatedX; + const screenY = canvasRef.current!.height / 2 + rotatedY; + + const scale = (rotatedZ + 200) / 300; + const radius = 20 * scale; + const dx = x - screenX; + const dy = y - screenY; + + if (dx * dx + dy * dy < radius * radius) { + const targetX = -Math.atan2( + icon.y, + Math.sqrt(icon.x * icon.x + icon.z * icon.z), + ); + const targetY = Math.atan2(icon.x, icon.z); + + const currentX = rotationRef.current.x; + const currentY = rotationRef.current.y; + const distance = Math.sqrt( + Math.pow(targetX - currentX, 2) + Math.pow(targetY - currentY, 2), + ); + + const duration = Math.min(2000, Math.max(800, distance * 1000)); + + setTargetRotation({ + x: targetX, + y: targetY, + startX: currentX, + startY: currentY, + distance, + startTime: performance.now(), + duration, + }); + return; + } + }); + + setIsDragging(true); + setLastMousePos({ x: e.clientX, y: e.clientY }); + }; + + const handleMouseMove = (e: React.MouseEvent) => { + const rect = canvasRef.current?.getBoundingClientRect(); + if (rect) { + const x = e.clientX - rect.left; + const y = e.clientY - rect.top; + setMousePos({ x, y }); + } + + if (isDragging) { + const deltaX = e.clientX - lastMousePos.x; + const deltaY = e.clientY - lastMousePos.y; + + rotationRef.current = { + x: rotationRef.current.x + deltaY * 0.002, + y: rotationRef.current.y + deltaX * 0.002, + }; + + setLastMousePos({ x: e.clientX, y: e.clientY }); + } + }; + + const handleMouseUp = () => { + setIsDragging(false); + }; + + // Animation and rendering + useEffect(() => { + const canvas = canvasRef.current; + const ctx = canvas?.getContext("2d"); + if (!canvas || !ctx) return; + + const animate = () => { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + const centerX = canvas.width / 2; + const centerY = canvas.height / 2; + const maxDistance = Math.sqrt(centerX * centerX + centerY * centerY); + const dx = mousePos.x - centerX; + const dy = mousePos.y - centerY; + const distance = Math.sqrt(dx * dx + dy * dy); + const speed = 0.003 + (distance / maxDistance) * 0.01; + + if (targetRotation) { + const elapsed = performance.now() - targetRotation.startTime; + const progress = Math.min(1, elapsed / targetRotation.duration); + const easedProgress = easeOutCubic(progress); + + rotationRef.current = { + x: + targetRotation.startX + + (targetRotation.x - targetRotation.startX) * easedProgress, + y: + targetRotation.startY + + (targetRotation.y - targetRotation.startY) * easedProgress, + }; + + if (progress >= 1) { + setTargetRotation(null); + } + } else if (!isDragging) { + rotationRef.current = { + x: rotationRef.current.x + (dy / canvas.height) * speed, + y: rotationRef.current.y + (dx / canvas.width) * speed, + }; + } + + iconPositions.forEach((icon, index) => { + const cosX = Math.cos(rotationRef.current.x); + const sinX = Math.sin(rotationRef.current.x); + const cosY = Math.cos(rotationRef.current.y); + const sinY = Math.sin(rotationRef.current.y); + + const rotatedX = icon.x * cosY - icon.z * sinY; + const rotatedZ = icon.x * sinY + icon.z * cosY; + const rotatedY = icon.y * cosX + rotatedZ * sinX; + + const scale = (rotatedZ + 200) / 300; + const opacity = Math.max(0.2, Math.min(1, (rotatedZ + 150) / 200)); + + ctx.save(); + ctx.translate( + canvas.width / 2 + rotatedX, + canvas.height / 2 + rotatedY, + ); + ctx.scale(scale, scale); + ctx.globalAlpha = opacity; + + if (icons || images) { + // Only try to render icons/images if they exist + if ( + iconCanvasesRef.current[index] && + imagesLoadedRef.current[index] + ) { + ctx.drawImage(iconCanvasesRef.current[index], -20, -20, 40, 40); + } + } else { + // Show numbered circles if no icons/images are provided + ctx.beginPath(); + ctx.arc(0, 0, 20, 0, Math.PI * 2); + ctx.fillStyle = "#4444ff"; + ctx.fill(); + ctx.fillStyle = "white"; + ctx.textAlign = "center"; + ctx.textBaseline = "middle"; + ctx.font = "16px Arial"; + ctx.fillText(`${icon.id + 1}`, 0, 0); + } + + ctx.restore(); + }); + animationFrameRef.current = requestAnimationFrame(animate); + }; + + animate(); + + return () => { + if (animationFrameRef.current) { + cancelAnimationFrame(animationFrameRef.current); + } + }; + }, [icons, images, iconPositions, isDragging, mousePos, targetRotation]); + + return ( + + ); } diff --git a/src/components/fancy/marqee.tsx b/src/components/fancy/marqee.tsx index fcbeeac..b7650de 100644 --- a/src/components/fancy/marqee.tsx +++ b/src/components/fancy/marqee.tsx @@ -2,76 +2,72 @@ import { cn } from "../cn"; import { ComponentPropsWithoutRef } from "react"; interface MarqueeProps extends ComponentPropsWithoutRef<"div"> { - /** - * Optional CSS class name to apply custom styles - */ - className?: string; - /** - * Whether to reverse the animation direction - * @default false - */ - reverse?: boolean; - /** - * Whether to pause the animation on hover - * @default false - */ - pauseOnHover?: boolean; - /** - * Content to be displayed in the marquee - */ - children: React.ReactNode; - /** - * Whether to animate vertically instead of horizontally - * @default false - */ - vertical?: boolean; - /** - * Number of times to repeat the content - * @default 4 - */ - repeat?: number; + /** + * Optional CSS class name to apply custom styles + */ + className?: string; + /** + * Whether to reverse the animation direction + * @default false + */ + reverse?: boolean; + /** + * Whether to pause the animation on hover + * @default false + */ + pauseOnHover?: boolean; + /** + * Content to be displayed in the marquee + */ + children: React.ReactNode; + /** + * Whether to animate vertically instead of horizontally + * @default false + */ + vertical?: boolean; + /** + * Number of times to repeat the content + * @default 4 + */ + repeat?: number; } export function Marquee({ - className, - reverse = false, - pauseOnHover = false, - children, - vertical = false, - repeat = 4, - ...props + className, + reverse = false, + pauseOnHover = false, + children, + vertical = false, + repeat = 4, + ...props }: MarqueeProps) { - return ( -
- {Array(repeat) - .fill(0) - .map((_, i) => ( -
- {children} -
- ))} -
- ); + return ( +
+ {Array(repeat) + .fill(0) + .map((_, i) => ( +
+ {children} +
+ ))} +
+ ); } diff --git a/src/components/fancy/typewriter.tsx b/src/components/fancy/typewriter.tsx index c7524aa..30e2652 100644 --- a/src/components/fancy/typewriter.tsx +++ b/src/components/fancy/typewriter.tsx @@ -4,135 +4,130 @@ import { motion, Variants } from "motion/react"; import { useEffect, useState } from "react"; interface TypewriterProps { - text: string | string[]; - speed?: number; - initialDelay?: number; - waitTime?: number; - deleteSpeed?: number; - loop?: boolean; - className?: string; - showCursor?: boolean; - hideCursorOnType?: boolean; - cursorChar?: string | React.ReactNode; - cursorAnimationVariants?: { - initial: Variants["initial"]; - animate: Variants["animate"]; - }; - cursorClassName?: string; + text: string | string[]; + speed?: number; + initialDelay?: number; + waitTime?: number; + deleteSpeed?: number; + loop?: boolean; + className?: string; + showCursor?: boolean; + hideCursorOnType?: boolean; + cursorChar?: string | React.ReactNode; + cursorAnimationVariants?: { + initial: Variants["initial"]; + animate: Variants["animate"]; + }; + cursorClassName?: string; } const Typewriter = ({ - text, - speed = 50, - initialDelay = 0, - waitTime = 2000, - deleteSpeed = 30, - loop = true, - className, - showCursor = true, - hideCursorOnType = false, - cursorChar = "|", - cursorClassName = "ml-1", - cursorAnimationVariants = { - initial: { opacity: 0 }, - animate: { - opacity: 1, - transition: { - duration: 0.01, - repeat: Infinity, - repeatDelay: 0.4, - repeatType: "reverse", - }, - }, - }, + text, + speed = 50, + initialDelay = 0, + waitTime = 2000, + deleteSpeed = 30, + loop = true, + className, + showCursor = true, + hideCursorOnType = false, + cursorChar = "|", + cursorClassName = "ml-1", + cursorAnimationVariants = { + initial: { opacity: 0 }, + animate: { + opacity: 1, + transition: { + duration: 0.01, + repeat: Infinity, + repeatDelay: 0.4, + repeatType: "reverse", + }, + }, + }, }: TypewriterProps) => { - const [displayText, setDisplayText] = useState(""); - const [currentIndex, setCurrentIndex] = useState(0); - const [isDeleting, setIsDeleting] = useState(false); - const [currentTextIndex, setCurrentTextIndex] = useState(0); + const [displayText, setDisplayText] = useState(""); + const [currentIndex, setCurrentIndex] = useState(0); + const [isDeleting, setIsDeleting] = useState(false); + const [currentTextIndex, setCurrentTextIndex] = useState(0); - const texts = Array.isArray(text) ? text : [text]; + const texts = Array.isArray(text) ? text : [text]; - useEffect(() => { - let timeout: NodeJS.Timeout; + useEffect(() => { + let timeout: NodeJS.Timeout; - const currentText = texts[currentTextIndex]; + const currentText = texts[currentTextIndex]; - const startTyping = () => { - if (isDeleting) { - if (displayText === "") { - setIsDeleting(false); - if (currentTextIndex === texts.length - 1 && !loop) { - return; - } - setCurrentTextIndex((prev) => (prev + 1) % texts.length); - setCurrentIndex(0); - timeout = setTimeout(() => {}, waitTime); - } else { - timeout = setTimeout(() => { - setDisplayText((prev) => prev.slice(0, -1)); - }, deleteSpeed); - } - } else { - if (currentIndex < currentText.length) { - timeout = setTimeout(() => { - setDisplayText( - (prev) => prev + currentText[currentIndex], - ); - setCurrentIndex((prev) => prev + 1); - }, speed); - } else if (texts.length > 1) { - timeout = setTimeout(() => { - setIsDeleting(true); - }, waitTime); - } - } - }; + const startTyping = () => { + if (isDeleting) { + if (displayText === "") { + setIsDeleting(false); + if (currentTextIndex === texts.length - 1 && !loop) { + return; + } + setCurrentTextIndex((prev) => (prev + 1) % texts.length); + setCurrentIndex(0); + timeout = setTimeout(() => {}, waitTime); + } else { + timeout = setTimeout(() => { + setDisplayText((prev) => prev.slice(0, -1)); + }, deleteSpeed); + } + } else { + if (currentIndex < currentText.length) { + timeout = setTimeout(() => { + setDisplayText((prev) => prev + currentText[currentIndex]); + setCurrentIndex((prev) => prev + 1); + }, speed); + } else if (texts.length > 1) { + timeout = setTimeout(() => { + setIsDeleting(true); + }, waitTime); + } + } + }; - // Apply initial delay only at the start - if (currentIndex === 0 && !isDeleting && displayText === "") { - timeout = setTimeout(startTyping, initialDelay); - } else { - startTyping(); - } + // Apply initial delay only at the start + if (currentIndex === 0 && !isDeleting && displayText === "") { + timeout = setTimeout(startTyping, initialDelay); + } else { + startTyping(); + } - return () => clearTimeout(timeout); - }, [ - currentIndex, - displayText, - isDeleting, - speed, - deleteSpeed, - waitTime, - texts, - currentTextIndex, - loop, - ]); + return () => clearTimeout(timeout); + }, [ + currentIndex, + displayText, + isDeleting, + speed, + deleteSpeed, + waitTime, + texts, + currentTextIndex, + loop, + ]); - return ( -
- {displayText} - {showCursor && ( - - {cursorChar} - - )} -
- ); + return ( +
+ {displayText} + {showCursor && ( + + {cursorChar} + + )} +
+ ); }; export default Typewriter; diff --git a/src/components/nUI/Footer.tsx b/src/components/nUI/Footer.tsx index e743842..14c3274 100644 --- a/src/components/nUI/Footer.tsx +++ b/src/components/nUI/Footer.tsx @@ -4,92 +4,90 @@ import { IconType } from "react-icons"; import { tv } from "tailwind-variants"; export const footerVariants = tv({ - base: "w-full bg-primary", + base: "w-full bg-primary", }); export interface FooterProps { - social: { - name: string; - href: string; - icon: IconType; - }[]; - links: { - name: string; - children: { - name: string; - href: string; - }[]; - }[]; - copylight?: string; - className?: string; - children?: React.ReactNode; + social: { + name: string; + href: string; + icon: IconType; + }[]; + links: { + name: string; + children: { + name: string; + href: string; + }[]; + }[]; + copylight?: string; + className?: string; + children?: React.ReactNode; } export const Footer: React.FC = ({ - social, - links, - children, - className, - copylight = " 2021- Neody. All rights reserved.", + social, + links, + children, + className, + copylight = " 2021- Neody. All rights reserved.", }) => { - const maxWidth = links.length < 4 ? "max-w-4xl" : "max-w-5xl"; + const maxWidth = links.length < 4 ? "max-w-4xl" : "max-w-5xl"; - return ( -
-
-
- {links.map((item) => ( -
-

- {item.name} -

- -
- ))} - {children} -
-
-
-
-

- © {copylight} -

-
- {social.map((item) => ( - - - - ))} -
-
-
-
-
-
- ); + return ( +
+
+
+ {links.map((item) => ( +
+

+ {item.name} +

+ +
+ ))} + {children} +
+
+
+
+

+ © {copylight} +

+
+ {social.map((item) => ( + + + + ))} +
+
+
+
+
+
+ ); }; Footer.displayName = "Footer"; diff --git a/src/components/nUI/Header.tsx b/src/components/nUI/Header.tsx index 69c9f4c..368a3d2 100644 --- a/src/components/nUI/Header.tsx +++ b/src/components/nUI/Header.tsx @@ -8,354 +8,341 @@ import { useIsWide } from "./hooks"; import Link from "next/link"; const headerVariants = tv({ - base: "fixed inset-x-0 top-0 z-50 py-2 transition-[padding-top,padding-bottom,box-shadow] ease-in-out lg:py-0 text-white", - variants: { - isScrolled: { - true: "border-b border-outline bg-primary border-primary backdrop-blur-sm lg:bg-opacity-70", - false: "bg-transparent lg:py-4", - }, - }, + base: "fixed inset-x-0 top-0 z-50 py-2 transition-[padding-top,padding-bottom,box-shadow] ease-in-out lg:py-0 text-white", + variants: { + isScrolled: { + true: "border-b border-outline bg-primary border-primary backdrop-blur-sm lg:bg-opacity-70", + false: "bg-transparent lg:py-4", + }, + }, }); const barVariants = { - rest: { opacity: 0, y: 5 }, - hover: { - opacity: 1, - y: 0, - transition: { - delay: 0.1, - type: "spring", - }, - }, + rest: { opacity: 0, y: 5 }, + hover: { + opacity: 1, + y: 0, + transition: { + delay: 0.1, + type: "spring", + }, + }, }; const mobileMenuContainerVariants = { - open: { - display: "block", - }, - closed: { - display: "none", - transition: { delay: 0.8 }, - }, + open: { + display: "block", + }, + closed: { + display: "none", + transition: { delay: 0.8 }, + }, }; const mobileMenuItemContainerVariants = { - open: { - opacity: 1, - transition: { - ease: "easeOut", - staggerChildren: 0.07, - delayChildren: 0.2, - }, - }, - closed: { - opacity: 0, - transition: { delay: 0.6, staggerChildren: 0.05, staggerDirection: -1 }, - }, + open: { + opacity: 1, + transition: { + ease: "easeOut", + staggerChildren: 0.07, + delayChildren: 0.2, + }, + }, + closed: { + opacity: 0, + transition: { delay: 0.6, staggerChildren: 0.05, staggerDirection: -1 }, + }, }; const mobileMenuItemVariants = { - open: { - y: 0, - opacity: 1, - transition: { - ease: "easeOut", - y: { stiffness: 1000, velocity: -100 }, - }, - }, - closed: { - y: 50, - opacity: 0, - transition: { - ease: "easeIn", - y: { stiffness: 1000 }, - }, - }, + open: { + y: 0, + opacity: 1, + transition: { + ease: "easeOut", + y: { stiffness: 1000, velocity: -100 }, + }, + }, + closed: { + y: 50, + opacity: 0, + transition: { + ease: "easeIn", + y: { stiffness: 1000 }, + }, + }, }; const mobileMenuButtonsVariants = { - open: { - opacity: 1, - transition: { delay: 0.4, duration: 0.4 }, - }, - closed: { - opacity: 0, - transition: { delay: 0 }, - }, + open: { + opacity: 1, + transition: { delay: 0.4, duration: 0.4 }, + }, + closed: { + opacity: 0, + transition: { delay: 0 }, + }, }; const headerAnimationVariants = { - show: { - top: 0, - transition: { ease: "easeOut", stiffness: 100 }, - }, - hide: { - top: -88, - }, + show: { + top: 0, + transition: { ease: "easeOut", stiffness: 100 }, + }, + hide: { + top: -88, + }, }; interface MobileMenuItemProps { - name: string; - href: string; - index: number; - isCurrent: boolean; - color: string; + name: string; + href: string; + index: number; + isCurrent: boolean; + color: string; } const MobileMenuItem: React.FC = ({ - name, - href, - color, - isCurrent, + name, + href, + color, + isCurrent, }) => { - return ( - - - {name} - {isCurrent && ( - - Current page - - - )} - - - ); + return ( + + + {name} + {isCurrent && ( + + Current page + + + )} + + + ); }; export interface HeaderButtonProps { - href?: string; - target?: "_blank" | "_self" | "_parent" | "_top"; - title: string; - onClick?: () => void; - disabled?: boolean; - className?: string; + href?: string; + target?: "_blank" | "_self" | "_parent" | "_top"; + title: string; + onClick?: () => void; + disabled?: boolean; + className?: string; } export interface HeaderProps extends ComponentPropsWithoutRef<"div"> { - brand?: { - name: string; - href: string; - logo: string; - showTitle?: boolean; - rounded?: boolean; - }; - navigation: { name: string; href: string }[]; - buttons?: HeaderButtonProps[]; - color?: string; - current?: string | number; + brand?: { + name: string; + href: string; + logo: string; + showTitle?: boolean; + rounded?: boolean; + }; + navigation: { name: string; href: string }[]; + buttons?: HeaderButtonProps[]; + color?: string; + current?: string | number; } export const Header = forwardRef( - ( - { - navigation, - brand = { - logo: "/", - href: "/", - name: "/", - }, - current, - color, - buttons, - }: HeaderProps, - ref, - ) => { - const [isScrolled, setIsScrolled] = useState(false); - const [lastYPosition, setLastYPosition] = useState(0); - const [isHeaderShown, setIsHeaderShown] = useState(true); - const isWide = useIsWide(); + ( + { + navigation, + brand = { + logo: "/", + href: "/", + name: "/", + }, + current, + color, + buttons, + }: HeaderProps, + ref, + ) => { + const [isScrolled, setIsScrolled] = useState(false); + const [lastYPosition, setLastYPosition] = useState(0); + const [isHeaderShown, setIsHeaderShown] = useState(true); + const isWide = useIsWide(); - const { scrollY } = useScroll(); - const [isMobileMenuOpen, toggleMobileMenuOpen] = useToggle(false); + const { scrollY } = useScroll(); + const [isMobileMenuOpen, toggleMobileMenuOpen] = useToggle(false); - const headerHeight = 88; + const headerHeight = 88; - useLockBodyScroll(isMobileMenuOpen); + useLockBodyScroll(isMobileMenuOpen); - useMotionValueEvent(scrollY, "change", (latest) => { - setIsScrolled(latest > 10); - if (!isMobileMenuOpen) { - setIsHeaderShown( - latest < headerHeight || latest < lastYPosition, - ); - setLastYPosition(latest); - } - }); + useMotionValueEvent(scrollY, "change", (latest) => { + setIsScrolled(latest > 10); + if (!isMobileMenuOpen) { + setIsHeaderShown(latest < headerHeight || latest < lastYPosition); + setLastYPosition(latest); + } + }); - return ( - - - toggleMobileMenuOpen()} /> + return ( + + + toggleMobileMenuOpen()} /> - - {brand.name} - {brand.showTitle && ( - - {brand.name} - - )} - + + {brand.name} + {brand.showTitle && ( + + {brand.name} + + )} + - - - {navigation.map((item, index) => { - const _color = color || ""; - const isCurrent = - (typeof current === "string" && - item.href === current) || - (typeof current === "number" && - index === current); - return ( - - ); - })} - {buttons?.length && ( - - {buttons?.map((buttonProps) => { - return buttonProps.href ? ( - - - - ) : ( - - ); - })} - - )} - - + + + {navigation.map((item, index) => { + const _color = color || ""; + const isCurrent = + (typeof current === "string" && item.href === current) || + (typeof current === "number" && index === current); + return ( + + ); + })} + {buttons?.length && ( + + {buttons?.map((buttonProps) => { + return buttonProps.href ? ( + + + + ) : ( + + ); + })} + + )} + + -
- {navigation.map((item, index) => { - const _color = color; - const isCurrent = - (typeof current === "string" && - item.href === current) || - (typeof current === "number" && - index === current); - return ( - - {item.name} - {isCurrent ? ( - - - - ) : ( - - - - )} - - ); - })} -
+
+ {navigation.map((item, index) => { + const _color = color; + const isCurrent = + (typeof current === "string" && item.href === current) || + (typeof current === "number" && index === current); + return ( + + {item.name} + {isCurrent ? ( + + + + ) : ( + + + + )} + + ); + })} +
-
- {buttons?.map((buttonProps) => { - return buttonProps.href ? ( - - - - ) : ( - - ); - })} -
+
+ {buttons?.map((buttonProps) => { + return buttonProps.href ? ( + + + + ) : ( + + ); + })} +
-
- - - ); - }, +
+ + + ); + }, ); Header.displayName = "Header"; diff --git a/src/components/nUI/MenuToggle.tsx b/src/components/nUI/MenuToggle.tsx index 9705685..a03953d 100644 --- a/src/components/nUI/MenuToggle.tsx +++ b/src/components/nUI/MenuToggle.tsx @@ -2,42 +2,42 @@ import * as React from "react"; import { SVGMotionProps, motion } from "motion/react"; const Path: React.FC> = (props) => ( - + ); export interface MenuToggleProps { - toggle: () => void; + toggle: () => void; } export const MenuToggle: React.FC = ({ toggle }) => ( - + ); diff --git a/src/components/nUI/hooks.tsx b/src/components/nUI/hooks.tsx index 79ed2eb..dd0d0f2 100644 --- a/src/components/nUI/hooks.tsx +++ b/src/components/nUI/hooks.tsx @@ -2,14 +2,14 @@ import { useEffect, useState } from "react"; import { useMedia } from "react-use"; export const useIsWide = () => { - const [isWide, setIsWide] = useState(false); + const [isWide, setIsWide] = useState(false); - const _isWide = useMedia("(min-width: 780px)", false); + const _isWide = useMedia("(min-width: 780px)", false); - useEffect(() => { - setIsWide(_isWide); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [_isWide]); + useEffect(() => { + setIsWide(_isWide); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [_isWide]); - return isWide; + return isWide; }; diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 0000000..d09a695 --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,57 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", + outline: + "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2", + sm: "h-8 rounded-md px-3 text-xs", + lg: "h-10 rounded-md px-8", + icon: "h-9 w-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + + ); + }, +); +Button.displayName = "Button"; + +export { Button, buttonVariants }; diff --git a/src/components/vrm.tsx b/src/components/vrm.tsx index 168fe9c..d977917 100644 --- a/src/components/vrm.tsx +++ b/src/components/vrm.tsx @@ -6,213 +6,200 @@ import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { AnimationAction } from "three"; import { VRMLoaderPlugin } from "@pixiv/three-vrm"; import { - VRMAnimationLoaderPlugin, - createVRMAnimationClip, + VRMAnimationLoaderPlugin, + createVRMAnimationClip, } from "@pixiv/three-vrm-animation"; import { AnimationMixer, LoopOnce, LoopRepeat } from "three"; import { PiPlayPause, PiRepeat } from "react-icons/pi"; const animations = [ - { - url: "https://cdn.mikn.dev/vroid/shikanoko.vrma", - loop: true, - percentage: 10, - }, - { url: "https://cdn.mikn.dev/vroid/hi.vrma", loop: false, percentage: 50 }, - { - url: "https://cdn.mikn.dev/vroid/uishig.vrma", - loop: false, - percentage: 10, - }, - { - url: "https://cdn.mikn.dev/vroid/tetoris.vrma", - loop: false, - percentage: 10, - }, - { - url: "https://cdn.mikn.dev/vroid/telepathy.vrma", - loop: false, - percentage: 10, - }, - { - url: "https://cdn.mikn.dev/vroid/soware.vrma", - loop: false, - percentage: 10, - }, + { + url: "https://cdn.mikn.dev/vroid/shikanoko.vrma", + loop: true, + percentage: 10, + }, + { url: "https://cdn.mikn.dev/vroid/hi.vrma", loop: false, percentage: 50 }, + { + url: "https://cdn.mikn.dev/vroid/uishig.vrma", + loop: false, + percentage: 10, + }, + { + url: "https://cdn.mikn.dev/vroid/tetoris.vrma", + loop: false, + percentage: 10, + }, + { + url: "https://cdn.mikn.dev/vroid/telepathy.vrma", + loop: false, + percentage: 10, + }, + { + url: "https://cdn.mikn.dev/vroid/soware.vrma", + loop: false, + percentage: 10, + }, ]; export const VRMModel: FC<{ - vrm: import("@pixiv/three-vrm").VRM | null; - mixer: AnimationMixer | null; + vrm: import("@pixiv/three-vrm").VRM | null; + mixer: AnimationMixer | null; }> = ({ vrm, mixer }) => { - useFrame(({ clock }, delta) => { - if (vrm) { - vrm.scene.position.set(0, -4.2, 0); - vrm.scene.scale.set(6.5, 5, 5); - vrm.scene.rotation.y = Math.PI; - vrm.expressionManager?.setValue("neutral", 1); + useFrame(({ clock }, delta) => { + if (vrm) { + vrm.scene.position.set(0, -4.2, 0); + vrm.scene.scale.set(6.5, 5, 5); + vrm.scene.rotation.y = Math.PI; + vrm.expressionManager?.setValue("neutral", 1); - vrm.update(delta); - } - if (mixer) { - mixer.update(delta); - } - }); + vrm.update(delta); + } + if (mixer) { + mixer.update(delta); + } + }); - return vrm ? : null; + return vrm ? : null; }; export function VRM() { - const [vrm, setVrm] = useState(null); - const [mixer, setMixer] = useState(null); - const [isLoaded, setIsLoaded] = useState(false); - const actionRef = useRef(null); + const [vrm, setVrm] = useState(null); + const [mixer, setMixer] = useState(null); + const [isLoaded, setIsLoaded] = useState(false); + const actionRef = useRef(null); - useEffect(() => { - const loader = new GLTFLoader(); - loader.register((parser: any) => new VRMLoaderPlugin(parser)); - loader.register((parser: any) => new VRMAnimationLoaderPlugin(parser)); + useEffect(() => { + const loader = new GLTFLoader(); + loader.register((parser: any) => new VRMLoaderPlugin(parser)); + loader.register((parser: any) => new VRMAnimationLoaderPlugin(parser)); - const loadModel = () => { - return new Promise( - (resolve, reject) => { - loader.load( - "https://cdn.mikn.dev/vroid/mikan.dev(kyonyu).vrm", - (gltf: GLTF) => { - const loadedVrm = gltf.userData.vrm; - setVrm(loadedVrm); - resolve(loadedVrm); - }, - undefined, - (error: Error) => { - console.error( - "An error occurred while loading the model:", - error, - ); - reject(error); - }, - ); - }, - ); - }; + const loadModel = () => { + return new Promise((resolve, reject) => { + loader.load( + "https://cdn.mikn.dev/vroid/mikan.dev(kyonyu).vrm", + (gltf: GLTF) => { + const loadedVrm = gltf.userData.vrm; + setVrm(loadedVrm); + resolve(loadedVrm); + }, + undefined, + (error: Error) => { + console.error("An error occurred while loading the model:", error); + reject(error); + }, + ); + }); + }; - function pickAnimation() { - const total = animations.reduce( - (sum, anim) => sum + anim.percentage, - 0, - ); - const rand = Math.random() * total; - let acc = 0; - for (const anim of animations) { - acc += anim.percentage; - if (rand < acc) return anim; - } - return animations[0]; // fallback - } + function pickAnimation() { + const total = animations.reduce((sum, anim) => sum + anim.percentage, 0); + const rand = Math.random() * total; + let acc = 0; + for (const anim of animations) { + acc += anim.percentage; + if (rand < acc) return anim; + } + return animations[0]; // fallback + } - const loadAnimation = (loadedVrm: import("@pixiv/three-vrm").VRM) => { - const { url, loop } = pickAnimation(); + const loadAnimation = (loadedVrm: import("@pixiv/three-vrm").VRM) => { + const { url, loop } = pickAnimation(); - loader.load( - url, - (gltf: GLTF) => { - const vrmAnimations = gltf.userData.vrmAnimations; - if (vrmAnimations && vrmAnimations.length > 0) { - if (loadedVrm && loadedVrm.humanoid) { - const animationClip = createVRMAnimationClip( - vrmAnimations[0], - loadedVrm, - ); - const animationMixer = new AnimationMixer( - loadedVrm.scene, - ); - const action = - animationMixer.clipAction(animationClip); + loader.load( + url, + (gltf: GLTF) => { + const vrmAnimations = gltf.userData.vrmAnimations; + if (vrmAnimations && vrmAnimations.length > 0) { + if (loadedVrm && loadedVrm.humanoid) { + const animationClip = createVRMAnimationClip( + vrmAnimations[0], + loadedVrm, + ); + const animationMixer = new AnimationMixer(loadedVrm.scene); + const action = animationMixer.clipAction(animationClip); - if (loop) { - action.setLoop(LoopRepeat, Infinity); - } else { - action.setLoop(LoopOnce, 1); - action.clampWhenFinished = true; - } + if (loop) { + action.setLoop(LoopRepeat, Infinity); + } else { + action.setLoop(LoopOnce, 1); + action.clampWhenFinished = true; + } - action.play(); - setMixer(animationMixer); - actionRef.current = action; - } else { - console.error( - "VRM model or humanoid is not loaded correctly.", - ); - } - } - }, - undefined, - (error: Error) => { - console.error( - "An error occurred while loading the animation:", - error, - ); - }, - ); - }; + action.play(); + setMixer(animationMixer); + actionRef.current = action; + } else { + console.error("VRM model or humanoid is not loaded correctly."); + } + } + }, + undefined, + (error: Error) => { + console.error( + "An error occurred while loading the animation:", + error, + ); + }, + ); + }; - loadModel() - .then((loadedVrm) => { - setIsLoaded(true); - loadAnimation(loadedVrm); - }) - .catch((error) => { - console.error("An error occurred:", error); - }); - }, []); + loadModel() + .then((loadedVrm) => { + setIsLoaded(true); + loadAnimation(loadedVrm); + }) + .catch((error) => { + console.error("An error occurred:", error); + }); + }, []); - return ( -
-
- {!isLoaded ? ( -
- -
- ) : ( - - - - - - - )} -
-
- { - if (!actionRef.current) return; - if (actionRef.current?.paused) { - actionRef.current.paused = false; - } else { - actionRef.current.paused = true; - } - }} - > - Pause - - { - if (actionRef.current) { - actionRef.current.reset(); - actionRef.current.paused = false; - actionRef.current.play(); - } - }} - > - Restart - -
-
- ); + return ( +
+
+ {!isLoaded ? ( +
+ +
+ ) : ( + + + + + + + )} +
+
+ { + if (!actionRef.current) return; + if (actionRef.current?.paused) { + actionRef.current.paused = false; + } else { + actionRef.current.paused = true; + } + }} + > + Pause + + { + if (actionRef.current) { + actionRef.current.reset(); + actionRef.current.paused = false; + actionRef.current.play(); + } + }} + > + Restart + +
+
+ ); } diff --git a/src/i18n/request.ts b/src/i18n/request.ts index 1d083d9..a8532f2 100644 --- a/src/i18n/request.ts +++ b/src/i18n/request.ts @@ -2,34 +2,34 @@ import { getRequestConfig } from "next-intl/server"; import { routing } from "./routing"; export default getRequestConfig(async ({ requestLocale }) => { - let locale = await requestLocale; + let locale = await requestLocale; - if (!locale || !routing.locales.includes(locale as any)) { - locale = routing.defaultLocale; - } + if (!locale || !routing.locales.includes(locale as any)) { + locale = routing.defaultLocale; + } - if (process.env.NODE_ENV === "development") { - const res = await fetch( - `${process.env.TOLGEE_API_URL}/v2/projects/${process.env.TOLGEE_PROJECT_ID}/translations/${locale}`, - { - headers: { - "x-api-key": `${process.env.TOLGEE_API_KEY}`, - }, - }, - ); - const data = await res.json(); - const messages = data[locale]; + if (process.env.NODE_ENV === "development") { + const res = await fetch( + `${process.env.TOLGEE_API_URL}/v2/projects/${process.env.TOLGEE_PROJECT_ID}/translations/${locale}`, + { + headers: { + "x-api-key": `${process.env.TOLGEE_API_KEY}`, + }, + }, + ); + const data = await res.json(); + const messages = data[locale]; - return { - locale, - messages, - }; - } + return { + locale, + messages, + }; + } - const res = await fetch(`${process.env.I18N_PUBLIC_URL}/${locale}.json`); + const res = await fetch(`${process.env.I18N_PUBLIC_URL}/${locale}.json`); - return { - locale, - messages: await res.json(), - }; + return { + locale, + messages: await res.json(), + }; }); diff --git a/src/i18n/routing.ts b/src/i18n/routing.ts index 63c0b5a..502a7ed 100644 --- a/src/i18n/routing.ts +++ b/src/i18n/routing.ts @@ -2,14 +2,14 @@ import { defineRouting } from "next-intl/routing"; import { createNavigation } from "next-intl/navigation"; export const routing = defineRouting({ - // A list of all locales that are supported - locales: ["en", "ja"], + // A list of all locales that are supported + locales: ["en", "ja"], - // Used when no locale matches - defaultLocale: "en", + // Used when no locale matches + defaultLocale: "en", }); // Lightweight wrappers around Next.js' navigation APIs // that will consider the routing configuration export const { Link, redirect, usePathname, useRouter, getPathname } = - createNavigation(routing); + createNavigation(routing); diff --git a/src/imgLoader.ts b/src/imgLoader.ts index e17bf20..daa6c34 100644 --- a/src/imgLoader.ts +++ b/src/imgLoader.ts @@ -1,19 +1,23 @@ const normalizeSrc = (src: string) => { - return src.startsWith("/") ? src.slice(1) : src; + return src.startsWith("/") ? src.slice(1) : src; }; export default function cloudflareLoader({ - src, - width, - quality, -}: { src: string; width: number; quality?: number }) { - if (process.env.NODE_ENV === "development") { - return src; - } - const params = [`width=${width}`]; - if (quality) { - params.push(`quality=${quality}`); - } - const paramsString = params.join(","); - return `/cdn-cgi/image/${paramsString}/${normalizeSrc(src)}`; + src, + width, + quality, +}: { + src: string; + width: number; + quality?: number; +}) { + if (process.env.NODE_ENV === "development") { + return src; + } + const params = [`width=${width}`]; + if (quality) { + params.push(`quality=${quality}`); + } + const paramsString = params.join(","); + return `/cdn-cgi/image/${paramsString}/${normalizeSrc(src)}`; } diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000..a5ef193 --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/src/messages/en.json b/src/messages/en.json index c6034c3..cdb8f8a 100644 --- a/src/messages/en.json +++ b/src/messages/en.json @@ -1,65 +1,65 @@ { - "home": { - "creating-cool": "Creating cool", - "makeLifeEasier": "to make life easier.", - "stuff": "stuff", - "apps": "Apps", - "tools": "Tools", - "bots": "Bots", - "mainBlurb1": "We create open-source solutions for those itches in life that need scratching.", - "mainBlurb2": "Enrich your life without breaking the bank.", - "takeLook": "Take a look", - "learnMore": "Learn More", - "infoTitle": "what makes us special", - "infoBlurb": "The MikanDev Difference", - "OSSonOSS": "Open Source with Open Source", - "OSSonOSSBlurb": "We believe in the power of open source. All of our projects are free to self-host, modify and contribute to. Any third-party services we use are also open source.", - "partOfPage": "the very page you're reading is open source!", - "viewOnGH": "View on GitHub", - "SimpleNCheap": "Designed with simplicity for ultimate cost-effectiveness", - "SimpleNCheapBlurb": "We don't believe in overcomplicating things. Our projects are designed to be simple to use, and aren't held up by expensive third-party services. The savings are passed on to you!", - "monthlyCost": "Avg. Monthly running cost", - "MAUBilled": "MAU billed services used", - "despite": "Despite...", - "monthlyBandwidth": "Avg. Monthly bandwidth usage", - "mainServices": "Main services", - "monthlyUptime": "Avg. Monthly uptime", - "HowSoCheap": "How so cheap?", - "SelfFunded": "100% Self-funded", - "SelfFundedBlurb": "We don't have any investors or VC to answer to, so we can decide when we make a profit. We're here to make cool stuff, not money.", - "WorkWithBest": "Working with the best", - "WorkWithBestBlurb": "We partner with other cool organizations and help get their cool stuff out there. We're all about the community :3", - "workWithMe": "Work with us!", - "NoWait": "What's more to say?", - "NoWaitBlurb": "Check out our projects and see if there's something you like!" - }, - "nav": { - "support": "Support", - "docs": "Docs", - "solutions": "Solutions", - "legal": "Legal", - "payments": "Payment Center", - "blog": "Blog", - "discord": "Discord", - "contact": "Contact Us", - "terms": "Terms of Service", - "privacy": "Privacy Policy", - "jp-payments": "特定商取引法に基づく表記", - "gdpr": "GDPR Compliance", - "myAccount": "My Account", - "resources": "Resources", - "cookieConsent": "We use cookies for analytics and making stuff work. By clicking 'mmmmmmm cookies 🍪', you agree to our use of cookies.", - "accept": "mmmmmmm cookies 🍪" - }, - "contact": { - "title": "Contact Us", - "mail": "Email", - "phone": "Phone (JP Only)*", - "discord": "Discord", - "join": "Join our Discord", - "general-support": "General Support", - "billing-support": "Billing Support", - "abuse-reports": "Abuse Reports", - "phone-disclaimer": "*Calling this number from outside of Japan may result in high charges. Please use the email or Discord for support." - } + "home": { + "creating-cool": "Creating cool", + "makeLifeEasier": "to make life easier.", + "stuff": "stuff", + "apps": "Apps", + "tools": "Tools", + "bots": "Bots", + "mainBlurb1": "We create open-source solutions for those itches in life that need scratching.", + "mainBlurb2": "Enrich your life without breaking the bank.", + "takeLook": "Take a look", + "learnMore": "Learn More", + "infoTitle": "what makes us special", + "infoBlurb": "The MikanDev Difference", + "OSSonOSS": "Open Source with Open Source", + "OSSonOSSBlurb": "We believe in the power of open source. All of our projects are free to self-host, modify and contribute to. Any third-party services we use are also open source.", + "partOfPage": "the very page you're reading is open source!", + "viewOnGH": "View on GitHub", + "SimpleNCheap": "Designed with simplicity for ultimate cost-effectiveness", + "SimpleNCheapBlurb": "We don't believe in overcomplicating things. Our projects are designed to be simple to use, and aren't held up by expensive third-party services. The savings are passed on to you!", + "monthlyCost": "Avg. Monthly running cost", + "MAUBilled": "MAU billed services used", + "despite": "Despite...", + "monthlyBandwidth": "Avg. Monthly bandwidth usage", + "mainServices": "Main services", + "monthlyUptime": "Avg. Monthly uptime", + "HowSoCheap": "How so cheap?", + "SelfFunded": "100% Self-funded", + "SelfFundedBlurb": "We don't have any investors or VC to answer to, so we can decide when we make a profit. We're here to make cool stuff, not money.", + "WorkWithBest": "Working with the best", + "WorkWithBestBlurb": "We partner with other cool organizations and help get their cool stuff out there. We're all about the community :3", + "workWithMe": "Work with us!", + "NoWait": "What's more to say?", + "NoWaitBlurb": "Check out our projects and see if there's something you like!" + }, + "nav": { + "support": "Support", + "docs": "Docs", + "solutions": "Solutions", + "legal": "Legal", + "payments": "Payment Center", + "blog": "Blog", + "discord": "Discord", + "contact": "Contact Us", + "terms": "Terms of Service", + "privacy": "Privacy Policy", + "jp-payments": "特定商取引法に基づく表記", + "gdpr": "GDPR Compliance", + "myAccount": "My Account", + "resources": "Resources", + "cookieConsent": "We use cookies for analytics and making stuff work. By clicking 'mmmmmmm cookies 🍪', you agree to our use of cookies.", + "accept": "mmmmmmm cookies 🍪" + }, + "contact": { + "title": "Contact Us", + "mail": "Email", + "phone": "Phone (JP Only)*", + "discord": "Discord", + "join": "Join our Discord", + "general-support": "General Support", + "billing-support": "Billing Support", + "abuse-reports": "Abuse Reports", + "phone-disclaimer": "*Calling this number from outside of Japan may result in high charges. Please use the email or Discord for support." + } } diff --git a/src/messages/ja.json b/src/messages/ja.json index 54bb18f..abbc9d4 100644 --- a/src/messages/ja.json +++ b/src/messages/ja.json @@ -1,65 +1,65 @@ { - "home": { - "creating-cool": "生活を豊かにする", - "makeLifeEasier": "を作っています。", - "stuff": "ヤツ", - "apps": "アプリ", - "tools": "ツール", - "bots": "Bot", - "mainBlurb1": "日常生活で出会う問題に対するオープンソースの解決策を作ります。", - "mainBlurb2": "大金持ちでなくても人生を豊かに。", - "takeLook": "見てみよう", - "learnMore": "もっと知る", - "infoTitle": "私達の秘訣", - "infoBlurb": "「The MikanDev Difference」", - "OSSonOSS": "オープンソース上のオープンソース", - "OSSonOSSBlurb": "私達はオープンソースの力を信じています。私達のプロジェクトは全て自己ホスト、修正、貢献が可能です。使用するサードパーティサービスもオープンソースです。", - "partOfPage": "このページもなんとオープンソースです!", - "viewOnGH": "GitHubで見てみる", - "SimpleNCheap": "シンプルさを追求し生まれた究極ののコストパフォマンス", - "SimpleNCheapBlurb": "私達は複雑なことを好みません。私達のプロジェクトは使いやすさを重視し、高額なサードパーティサービスに依存しません。その節約分はあなたに還元されます!", - "monthlyCost": "平均月額運用費用", - "MAUBilled": "従量課金サービス使用", - "despite": "にもかかわらず...", - "monthlyBandwidth": "平均月間帯域幅使用量", - "mainServices": "主要サービス", - "monthlyUptime": "平均月間稼働率", - "HowSoCheap": "なぜこんなに安いの?", - "SelfFunded": "100%自己資金", - "SelfFundedBlurb": "私達は投資家やVCに責任を負う必要がないため、利益を上げるタイミングを自分たちで決めることができます。私達はお金を稼ぐためではなく、面白いものを作るためにここにいます。", - "WorkWithBest": "最高の人たちと一緒に", - "WorkWithBestBlurb": "私達は他の素敵な組織と提携し、彼らの素晴らしいものを世に出すお手伝いをします。私達はコミュニティに全力を注いでいます!", - "workWithMe": "私たちと一緒にやろう!", - "NoWait": "これ以上言うことはありません。", - "NoWaitBlurb": "私たちのプロジェクトをチェックして、気に入るものがあるかどうかを見てください!" - }, - "nav": { - "support": "サポート", - "docs": "ドキュメント", - "solutions": "ソリューション", - "legal": "法的条約", - "payments": "支払いセンター", - "blog": "ブログ", - "discord": "Discord", - "contact": "お問い合わせ", - "terms": "利用規約", - "privacy": "プライバシーポリシー", - "jp-payments": "特定商取引法に基づく表記", - "gdpr": "GDPRコンプライアンス", - "myAccount": "マイアカウント", - "resources": "リソース", - "cookieConsent": "そこの君!このサイトはCookieを使ってるぞ!!いいよね?", - "accept": "いいね!" - }, - "contact": { - "title": "お問い合わせ", - "mail": "メール", - "phone": "電話 (日本のみ)*", - "discord": "Discord", - "join": "Discordに参加", - "general-support": "一般サポート", - "billing-support": "請求に関する問い合わせ", - "abuse-reports": "不正行為の報告", - "phone-disclaimer": "※日本国内の電話番号のみ対応しています。" - } + "home": { + "creating-cool": "生活を豊かにする", + "makeLifeEasier": "を作っています。", + "stuff": "ヤツ", + "apps": "アプリ", + "tools": "ツール", + "bots": "Bot", + "mainBlurb1": "日常生活で出会う問題に対するオープンソースの解決策を作ります。", + "mainBlurb2": "大金持ちでなくても人生を豊かに。", + "takeLook": "見てみよう", + "learnMore": "もっと知る", + "infoTitle": "私達の秘訣", + "infoBlurb": "「The MikanDev Difference」", + "OSSonOSS": "オープンソース上のオープンソース", + "OSSonOSSBlurb": "私達はオープンソースの力を信じています。私達のプロジェクトは全て自己ホスト、修正、貢献が可能です。使用するサードパーティサービスもオープンソースです。", + "partOfPage": "このページもなんとオープンソースです!", + "viewOnGH": "GitHubで見てみる", + "SimpleNCheap": "シンプルさを追求し生まれた究極ののコストパフォマンス", + "SimpleNCheapBlurb": "私達は複雑なことを好みません。私達のプロジェクトは使いやすさを重視し、高額なサードパーティサービスに依存しません。その節約分はあなたに還元されます!", + "monthlyCost": "平均月額運用費用", + "MAUBilled": "従量課金サービス使用", + "despite": "にもかかわらず...", + "monthlyBandwidth": "平均月間帯域幅使用量", + "mainServices": "主要サービス", + "monthlyUptime": "平均月間稼働率", + "HowSoCheap": "なぜこんなに安いの?", + "SelfFunded": "100%自己資金", + "SelfFundedBlurb": "私達は投資家やVCに責任を負う必要がないため、利益を上げるタイミングを自分たちで決めることができます。私達はお金を稼ぐためではなく、面白いものを作るためにここにいます。", + "WorkWithBest": "最高の人たちと一緒に", + "WorkWithBestBlurb": "私達は他の素敵な組織と提携し、彼らの素晴らしいものを世に出すお手伝いをします。私達はコミュニティに全力を注いでいます!", + "workWithMe": "私たちと一緒にやろう!", + "NoWait": "これ以上言うことはありません。", + "NoWaitBlurb": "私たちのプロジェクトをチェックして、気に入るものがあるかどうかを見てください!" + }, + "nav": { + "support": "サポート", + "docs": "ドキュメント", + "solutions": "ソリューション", + "legal": "法的条約", + "payments": "支払いセンター", + "blog": "ブログ", + "discord": "Discord", + "contact": "お問い合わせ", + "terms": "利用規約", + "privacy": "プライバシーポリシー", + "jp-payments": "特定商取引法に基づく表記", + "gdpr": "GDPRコンプライアンス", + "myAccount": "マイアカウント", + "resources": "リソース", + "cookieConsent": "そこの君!このサイトはCookieを使ってるぞ!!いいよね?", + "accept": "いいね!" + }, + "contact": { + "title": "お問い合わせ", + "mail": "メール", + "phone": "電話 (日本のみ)*", + "discord": "Discord", + "join": "Discordに参加", + "general-support": "一般サポート", + "billing-support": "請求に関する問い合わせ", + "abuse-reports": "不正行為の報告", + "phone-disclaimer": "※日本国内の電話番号のみ対応しています。" + } } diff --git a/src/middleware.ts b/src/middleware.ts deleted file mode 100644 index 38a46be..0000000 --- a/src/middleware.ts +++ /dev/null @@ -1,10 +0,0 @@ -import createMiddleware from "next-intl/middleware"; -import { routing } from "@/i18n/routing"; - -export default createMiddleware(routing); - -export const config = { - matcher: [ - "/((?!api|_next/static|_next/image|img|favicon.ico|sw.js|sitemap.xml|vroid*|98gas9mkeb.txt|robots.txt|opengraph-image.png).*)", - ], -}; diff --git a/tailwind.config.ts b/tailwind.config.ts index 2b2e786..8657b5a 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,37 +1,36 @@ import type { Config } from "tailwindcss"; const config: Config = { - content: [ - "./index.html", - "./pages/**/*.{js,ts,jsx,tsx,mdx}", - "./components/**/*.{js,ts,jsx,tsx,mdx}", - "./app/**/*.{js,ts,jsx,tsx,mdx}", - ], - theme: { - extend: { - colors: { - primary: "#ff9900", - "on-primary": "#ffffff", - secondary: "#ff7700", - "on-secondary": "#ffffff", - }, - animation: { - marquee: "marquee var(--duration) linear infinite", - "marquee-vertical": - "marquee-vertical var(--duration) linear infinite", - }, - keyframes: { - marquee: { - from: { transform: "translateX(0)" }, - to: { transform: "translateX(calc(-100% - var(--gap)))" }, - }, - "marquee-vertical": { - from: { transform: "translateY(0)" }, - to: { transform: "translateY(calc(-100% - var(--gap)))" }, - }, - }, - }, - }, - plugins: [], + content: [ + "./index.html", + "./pages/**/*.{js,ts,jsx,tsx,mdx}", + "./components/**/*.{js,ts,jsx,tsx,mdx}", + "./app/**/*.{js,ts,jsx,tsx,mdx}", + ], + theme: { + extend: { + colors: { + primary: "#ff9900", + "on-primary": "#ffffff", + secondary: "#ff7700", + "on-secondary": "#ffffff", + }, + animation: { + marquee: "marquee var(--duration) linear infinite", + "marquee-vertical": "marquee-vertical var(--duration) linear infinite", + }, + keyframes: { + marquee: { + from: { transform: "translateX(0)" }, + to: { transform: "translateX(calc(-100% - var(--gap)))" }, + }, + "marquee-vertical": { + from: { transform: "translateY(0)" }, + to: { transform: "translateY(calc(-100% - var(--gap)))" }, + }, + }, + }, + }, + plugins: [], }; export default config; diff --git a/tsconfig.json b/tsconfig.json index 59829b3..54c5280 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,36 +1,37 @@ { - "compilerOptions": { - "target": "es2017", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": ["./src/*"] - } - }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts", - "nextra.config.jsx", - "theme.config.jsx", - "app/libraries/logto.js", - "app/ui/cobe.jsx" - ], - "exclude": ["node_modules", "sst.config.ts"] + "compilerOptions": { + "target": "es2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + "nextra.config.jsx", + "theme.config.jsx", + "app/libraries/logto.js", + "app/ui/cobe.jsx", + ".next/dev/types/**/*.ts" + ], + "exclude": ["node_modules", "sst.config.ts"] } diff --git a/wrangler.jsonc b/wrangler.jsonc deleted file mode 100644 index 1ca1072..0000000 --- a/wrangler.jsonc +++ /dev/null @@ -1,45 +0,0 @@ -{ - "$schema": "node_modules/wrangler/config-schema.json", - "main": ".open-next/worker.js", - "name": "mikn-dev", - "compatibility_date": "2025-05-03", - "compatibility_flags": [ - // Enable Node.js API - // see https://developers.cloudflare.com/workers/configuration/compatibility-flags/#nodejs-compatibility-flag - "nodejs_compat", - // Allow to fetch URLs in your app - // see https://developers.cloudflare.com/workers/configuration/compatibility-flags/#global-fetch-strictly-public - "global_fetch_strictly_public" - ], - "assets": { - "directory": ".open-next/assets", - "binding": "ASSETS" - }, - "kv_namespaces": [ - { - "binding": "NEXT_INC_CACHE_KV", - "id": "914f30b5215d4d3c9dbae19952e042c5" - } - ], - "durable_objects": { - "bindings": [ - { - "name": "NEXT_CACHE_DO_QUEUE", - "class_name": "DOQueueHandler" - } - ] - }, - "migrations": [ - { - "tag": "v1", - "new_sqlite_classes": ["DOQueueHandler", "DOShardedTagCache"] - } - ], - "services": [ - { - "binding": "WORKER_SELF_REFERENCE", - // The service should match the "name" of your worker - "service": "mikn-dev" - } - ] -} From f4f6e38336f648206f99ceef95831456daf34a28 Mon Sep 17 00:00:00 2001 From: maamokun Date: Mon, 27 Oct 2025 22:29:57 +0900 Subject: [PATCH 03/10] feat: MDI config and React Compiler --- bun.lock | 9 +++++++++ imgLoader.ts | 19 +++++++++++++++++++ next.config.mjs | 5 +++++ package.json | 1 + src/assets/cloudfront.png | Bin 13913 -> 0 bytes src/imgLoader.ts | 23 ----------------------- 6 files changed, 34 insertions(+), 23 deletions(-) create mode 100644 imgLoader.ts delete mode 100644 src/assets/cloudfront.png delete mode 100644 src/imgLoader.ts diff --git a/bun.lock b/bun.lock index 622a670..5e0f19d 100644 --- a/bun.lock +++ b/bun.lock @@ -13,6 +13,7 @@ "@swetrix/nextjs": "^1.0.1", "@tailwindcss/postcss": "^4.1.7", "@types/three": "^0.176.0", + "babel-plugin-react-compiler": "^1.0.0", "caniuse-lite": "^1.0.30001664", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -49,8 +50,14 @@ "packages": { "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], + "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], + "@biomejs/biome": ["@biomejs/biome@2.3.1", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.1", "@biomejs/cli-darwin-x64": "2.3.1", "@biomejs/cli-linux-arm64": "2.3.1", "@biomejs/cli-linux-arm64-musl": "2.3.1", "@biomejs/cli-linux-x64": "2.3.1", "@biomejs/cli-linux-x64-musl": "2.3.1", "@biomejs/cli-win32-arm64": "2.3.1", "@biomejs/cli-win32-x64": "2.3.1" }, "bin": { "biome": "bin/biome" } }, "sha512-A29evf1R72V5bo4o2EPxYMm5mtyGvzp2g+biZvRFx29nWebGyyeOSsDWGx3tuNNMFRepGwxmA9ZQ15mzfabK2w=="], "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ombSf3MnTUueiYGN1SeI9tBCsDUhpWzOwS63Dove42osNh0PfE1cUtHFx6eZ1+MYCCLwXzlFlYFdrJ+U7h6LcA=="], @@ -463,6 +470,8 @@ "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], + "babel-plugin-react-compiler": ["babel-plugin-react-compiler@1.0.0", "", { "dependencies": { "@babel/types": "^7.26.0" } }, "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw=="], + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "base-x": ["base-x@5.0.1", "", {}, "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg=="], diff --git a/imgLoader.ts b/imgLoader.ts new file mode 100644 index 0000000..c70a0f7 --- /dev/null +++ b/imgLoader.ts @@ -0,0 +1,19 @@ +const optimizerUrl = process.env.NEXT_PUBLIC_IMAGE_OPTIMIZER_URL || ""; +const hostname = process.env.CF_PAGES_URL; + +export default function ImageLoader({ + src, + width, + quality, +}: { + src: string; + width: number; + quality: number; +}) { + if (process.env.NODE_ENV === "development") { + return src; + } + const params = [`size=${width}`]; + params.push(`quality=${quality || 75}`); + return `${optimizerUrl}/${encodeURIComponent(`${hostname}${src}`)}?${params.join("&")}`; +} diff --git a/next.config.mjs b/next.config.mjs index 5cdd0b4..75bc556 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -6,6 +6,11 @@ const withNextIntl = createNextIntlPlugin(); const nextConfig = { output: "export", + images: { + loader: "custom", + loaderFile: "./imgLoader.ts", + }, + reactCompiler: true, }; export default withNextIntl(nextConfig); diff --git a/package.json b/package.json index ef4a9f3..7e83761 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@swetrix/nextjs": "^1.0.1", "@tailwindcss/postcss": "^4.1.7", "@types/three": "^0.176.0", + "babel-plugin-react-compiler": "^1.0.0", "caniuse-lite": "^1.0.30001664", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/src/assets/cloudfront.png b/src/assets/cloudfront.png deleted file mode 100644 index 4cabff857b2e95fc89836b7f618ac550e162c278..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13913 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 B&=vpy diff --git a/src/imgLoader.ts b/src/imgLoader.ts deleted file mode 100644 index daa6c34..0000000 --- a/src/imgLoader.ts +++ /dev/null @@ -1,23 +0,0 @@ -const normalizeSrc = (src: string) => { - return src.startsWith("/") ? src.slice(1) : src; -}; - -export default function cloudflareLoader({ - src, - width, - quality, -}: { - src: string; - width: number; - quality?: number; -}) { - if (process.env.NODE_ENV === "development") { - return src; - } - const params = [`width=${width}`]; - if (quality) { - params.push(`quality=${quality}`); - } - const paramsString = params.join(","); - return `/cdn-cgi/image/${paramsString}/${normalizeSrc(src)}`; -} From 89eab1ada1f4b03715ed9ada81b9e12177705665 Mon Sep 17 00:00:00 2001 From: maamokun Date: Mon, 27 Oct 2025 23:09:03 +0900 Subject: [PATCH 04/10] feat: i18n reconfiguration --- src/app/[locale]/page.tsx | 2 +- src/app/[locale]/template.tsx | 5 --- src/app/consent-manager.client.tsx | 55 -------------------------- src/i18n/request.ts | 31 ++------------- src/messages/en.json | 62 +----------------------------- 5 files changed, 5 insertions(+), 150 deletions(-) delete mode 100644 src/app/consent-manager.client.tsx diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx index 98d337c..e75513d 100644 --- a/src/app/[locale]/page.tsx +++ b/src/app/[locale]/page.tsx @@ -6,7 +6,7 @@ export default async function IndexPage(params: Promise<{ locale: string }>) { setRequestLocale(locale); - const t = await getTranslations("HomePage"); + const t = await getTranslations("home"); return ( <> diff --git a/src/app/[locale]/template.tsx b/src/app/[locale]/template.tsx index 19a4d82..24481f6 100644 --- a/src/app/[locale]/template.tsx +++ b/src/app/[locale]/template.tsx @@ -1,13 +1,8 @@ "use client"; -import { useTranslations } from "next-intl"; import { useSwetrix } from "@swetrix/nextjs"; -import { useRouter, usePathname } from "next/navigation"; import { ReactNode } from "react"; export default function PagesLayout({ children }: { children: ReactNode }) { - const router = useRouter(); - const pathname = usePathname(); - const t = useTranslations("nav"); useSwetrix("XxNIMaHCaVG3", { apiURL: "https://analytics.mikandev.tech/log" }); return ( diff --git a/src/app/consent-manager.client.tsx b/src/app/consent-manager.client.tsx deleted file mode 100644 index 7c0a6f3..0000000 --- a/src/app/consent-manager.client.tsx +++ /dev/null @@ -1,55 +0,0 @@ -"use client"; - -import type { ReactNode } from "react"; -import { ClientSideOptionsProvider } from "@c15t/nextjs/client"; - -/** - * Client-side consent manager wrapper for handling scripts and callbacks - * - * This component is rendered on the client and provides the ability to: - * - Load integration scripts (Google Tag Manager, Meta Pixel, TikTok Pixel, etc.) - * - Handle client-side callbacks (onConsentSet, onError, onBannerFetched) - * - Manage script lifecycle (onLoad, onDelete) - * - * @param props - Component properties - * @param props.children - Child components to render within the client-side context - * - * @returns The client-side options provider with children - * - * @see https://c15t.com/docs/frameworks/next/callbacks - * @see https://c15t.com/docs/frameworks/next/script-loader - */ -export function ConsentManagerClient({ children }: { children: ReactNode }) { - return ( - console.log('GTM loaded'), - // }, - // }), - ] - } - // 📝 Add your callbacks here - // Callbacks allow you to react to consent events - callbacks={ - { - // Example: - // onConsentSet(response) { - // console.log('Consent updated:', response); - // }, - // onError(error) { - // console.error('Consent error:', error); - // }, - } - } - > - {children} - - ); -} diff --git a/src/i18n/request.ts b/src/i18n/request.ts index a8532f2..cd53451 100644 --- a/src/i18n/request.ts +++ b/src/i18n/request.ts @@ -1,35 +1,10 @@ import { getRequestConfig } from "next-intl/server"; -import { routing } from "./routing"; -export default getRequestConfig(async ({ requestLocale }) => { - let locale = await requestLocale; - - if (!locale || !routing.locales.includes(locale as any)) { - locale = routing.defaultLocale; - } - - if (process.env.NODE_ENV === "development") { - const res = await fetch( - `${process.env.TOLGEE_API_URL}/v2/projects/${process.env.TOLGEE_PROJECT_ID}/translations/${locale}`, - { - headers: { - "x-api-key": `${process.env.TOLGEE_API_KEY}`, - }, - }, - ); - const data = await res.json(); - const messages = data[locale]; - - return { - locale, - messages, - }; - } - - const res = await fetch(`${process.env.I18N_PUBLIC_URL}/${locale}.json`); +export default getRequestConfig(async () => { + const locale = "en"; return { locale, - messages: await res.json(), + messages: (await import(`../messages/${locale}.json`)).default, }; }); diff --git a/src/messages/en.json b/src/messages/en.json index cdb8f8a..bdaf2be 100644 --- a/src/messages/en.json +++ b/src/messages/en.json @@ -1,65 +1,5 @@ { "home": { - "creating-cool": "Creating cool", - "makeLifeEasier": "to make life easier.", - "stuff": "stuff", - "apps": "Apps", - "tools": "Tools", - "bots": "Bots", - "mainBlurb1": "We create open-source solutions for those itches in life that need scratching.", - "mainBlurb2": "Enrich your life without breaking the bank.", - "takeLook": "Take a look", - "learnMore": "Learn More", - "infoTitle": "what makes us special", - "infoBlurb": "The MikanDev Difference", - "OSSonOSS": "Open Source with Open Source", - "OSSonOSSBlurb": "We believe in the power of open source. All of our projects are free to self-host, modify and contribute to. Any third-party services we use are also open source.", - "partOfPage": "the very page you're reading is open source!", - "viewOnGH": "View on GitHub", - "SimpleNCheap": "Designed with simplicity for ultimate cost-effectiveness", - "SimpleNCheapBlurb": "We don't believe in overcomplicating things. Our projects are designed to be simple to use, and aren't held up by expensive third-party services. The savings are passed on to you!", - "monthlyCost": "Avg. Monthly running cost", - "MAUBilled": "MAU billed services used", - "despite": "Despite...", - "monthlyBandwidth": "Avg. Monthly bandwidth usage", - "mainServices": "Main services", - "monthlyUptime": "Avg. Monthly uptime", - "HowSoCheap": "How so cheap?", - "SelfFunded": "100% Self-funded", - "SelfFundedBlurb": "We don't have any investors or VC to answer to, so we can decide when we make a profit. We're here to make cool stuff, not money.", - "WorkWithBest": "Working with the best", - "WorkWithBestBlurb": "We partner with other cool organizations and help get their cool stuff out there. We're all about the community :3", - "workWithMe": "Work with us!", - "NoWait": "What's more to say?", - "NoWaitBlurb": "Check out our projects and see if there's something you like!" - }, - "nav": { - "support": "Support", - "docs": "Docs", - "solutions": "Solutions", - "legal": "Legal", - "payments": "Payment Center", - "blog": "Blog", - "discord": "Discord", - "contact": "Contact Us", - "terms": "Terms of Service", - "privacy": "Privacy Policy", - "jp-payments": "特定商取引法に基づく表記", - "gdpr": "GDPR Compliance", - "myAccount": "My Account", - "resources": "Resources", - "cookieConsent": "We use cookies for analytics and making stuff work. By clicking 'mmmmmmm cookies 🍪', you agree to our use of cookies.", - "accept": "mmmmmmm cookies 🍪" - }, - "contact": { - "title": "Contact Us", - "mail": "Email", - "phone": "Phone (JP Only)*", - "discord": "Discord", - "join": "Join our Discord", - "general-support": "General Support", - "billing-support": "Billing Support", - "abuse-reports": "Abuse Reports", - "phone-disclaimer": "*Calling this number from outside of Japan may result in high charges. Please use the email or Discord for support." + "hi": "Hello" } } From 01c4b09e494a68eccd52d2b2f388cadf9235a060 Mon Sep 17 00:00:00 2001 From: maamokun Date: Mon, 27 Oct 2025 23:24:01 +0900 Subject: [PATCH 05/10] fix: remove old components --- bun.lock | 3 + package.json | 9 +- src/components/fancy/NumberTicker.tsx | 58 ----- src/components/fancy/code-comp.tsx | 101 -------- src/components/fancy/icon-cloud.tsx | 324 ------------------------ src/components/fancy/marqee.tsx | 73 ------ src/components/fancy/typewriter.tsx | 133 ---------- src/components/nUI/Footer.tsx | 93 ------- src/components/nUI/Header.tsx | 348 -------------------------- src/components/nUI/MenuToggle.tsx | 43 ---- src/components/nUI/hooks.tsx | 15 -- tsconfig.json | 29 ++- 12 files changed, 22 insertions(+), 1207 deletions(-) delete mode 100644 src/components/fancy/NumberTicker.tsx delete mode 100644 src/components/fancy/code-comp.tsx delete mode 100644 src/components/fancy/icon-cloud.tsx delete mode 100644 src/components/fancy/marqee.tsx delete mode 100644 src/components/fancy/typewriter.tsx delete mode 100644 src/components/nUI/Footer.tsx delete mode 100644 src/components/nUI/Header.tsx delete mode 100644 src/components/nUI/MenuToggle.tsx delete mode 100644 src/components/nUI/hooks.tsx diff --git a/bun.lock b/bun.lock index 5e0f19d..64a53d9 100644 --- a/bun.lock +++ b/bun.lock @@ -18,6 +18,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "daisyui": "^5.0.0", + "gsap": "^3.13.0", "lucide-react": "^0.548.0", "motion": "^11.15.0", "next": "^16.0.0", @@ -612,6 +613,8 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "gsap": ["gsap@3.13.0", "", {}, "sha512-QL7MJ2WMjm1PHWsoFrAQH/J8wUeqZvMtHO58qdekHpCfhvhSL4gSiz6vJf5EeMP0LOn3ZCprL2ki/gjED8ghVw=="], + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], diff --git a/package.json b/package.json index 7e83761..8194279 100644 --- a/package.json +++ b/package.json @@ -4,14 +4,10 @@ "private": true, "scripts": { "build": "next build", - "dev": "NODE_OPTIONS='--inspect' next dev --turbo", + "dev": "next dev --turbo", "format": "biome format --write .", "lint": "next lint", - "start": "next start", - "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview", - "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy", - "upload": "opennextjs-cloudflare build && opennextjs-cloudflare upload", - "cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts" + "start": "next start" }, "dependencies": { "@c15t/nextjs": "^1.7.1", @@ -28,6 +24,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "daisyui": "^5.0.0", + "gsap": "^3.13.0", "lucide-react": "^0.548.0", "motion": "^11.15.0", "next": "^16.0.0", diff --git a/src/components/fancy/NumberTicker.tsx b/src/components/fancy/NumberTicker.tsx deleted file mode 100644 index bab26dd..0000000 --- a/src/components/fancy/NumberTicker.tsx +++ /dev/null @@ -1,58 +0,0 @@ -"use client"; - -import { useEffect, useRef } from "react"; -import { useInView, useMotionValue, useSpring } from "motion/react"; - -import { cn } from "../cn"; - -export function NumberTicker({ - value, - direction = "up", - delay = 0, - className, - decimalPlaces = 0, -}: { - value: number; - direction?: "up" | "down"; - className?: string; - delay?: number; // delay in s - decimalPlaces?: number; -}) { - const ref = useRef(null); - const motionValue = useMotionValue(direction === "down" ? value : 0); - const springValue = useSpring(motionValue, { - damping: 60, - stiffness: 100, - }); - const isInView = useInView(ref, { once: true, margin: "0px" }); - - useEffect(() => { - isInView && - setTimeout(() => { - motionValue.set(direction === "down" ? 0 : value); - }, delay * 1000); - }, [motionValue, isInView, delay, value, direction]); - - useEffect( - () => - springValue.on("change", (latest) => { - if (ref.current) { - ref.current.textContent = Intl.NumberFormat("en-US", { - minimumFractionDigits: decimalPlaces, - maximumFractionDigits: decimalPlaces, - }).format(Number(latest.toFixed(decimalPlaces))); - } - }), - [springValue, decimalPlaces], - ); - - return ( - - ); -} diff --git a/src/components/fancy/code-comp.tsx b/src/components/fancy/code-comp.tsx deleted file mode 100644 index d5a55aa..0000000 --- a/src/components/fancy/code-comp.tsx +++ /dev/null @@ -1,101 +0,0 @@ -"use client"; - -import { LuFile } from "react-icons/lu"; -import { useTheme } from "next-themes"; -import { useEffect, useState } from "react"; -import { codeToHtml } from "shiki"; - -interface CodeComparisonProps { - beforeCode: string; - afterCode: string; - language: string; - filename: string; - lightTheme: string; - darkTheme: string; - beforeTitle: string; - afterTitle: string; -} - -export function CodeComparison({ - beforeCode, - afterCode, - language, - filename, - lightTheme, - darkTheme, - beforeTitle, - afterTitle, -}: CodeComparisonProps) { - const { theme, systemTheme } = useTheme(); - const [highlightedBefore, setHighlightedBefore] = useState(""); - const [highlightedAfter, setHighlightedAfter] = useState(""); - - useEffect(() => { - const currentTheme = theme === "system" ? systemTheme : theme; - const selectedTheme = currentTheme === "dark" ? darkTheme : lightTheme; - - async function highlightCode() { - const before = await codeToHtml(beforeCode, { - lang: language, - theme: selectedTheme, - }); - const after = await codeToHtml(afterCode, { - lang: language, - theme: selectedTheme, - }); - setHighlightedBefore(before); - setHighlightedAfter(after); - } - - highlightCode(); - }, [ - theme, - systemTheme, - beforeCode, - afterCode, - language, - lightTheme, - darkTheme, - ]); - - const renderCode = (code: string, highlighted: string) => { - if (highlighted) { - return ( -
- ); - } else { - return ( -
-          {code}
-        
- ); - } - }; - return ( -
-
-
-
-
- - {filename} - {beforeTitle} -
- {renderCode(beforeCode, highlightedBefore)} -
-
-
- - {filename} - {afterTitle} -
- {renderCode(afterCode, highlightedAfter)} -
-
-
-
- ); -} diff --git a/src/components/fancy/icon-cloud.tsx b/src/components/fancy/icon-cloud.tsx deleted file mode 100644 index 1e9ffc2..0000000 --- a/src/components/fancy/icon-cloud.tsx +++ /dev/null @@ -1,324 +0,0 @@ -"use client"; - -import React, { useEffect, useRef, useState } from "react"; -import { renderToString } from "react-dom/server"; - -interface Icon { - x: number; - y: number; - z: number; - scale: number; - opacity: number; - id: number; -} - -interface IconCloudProps { - icons?: React.ReactNode[]; - images?: string[]; -} - -function easeOutCubic(t: number): number { - return 1 - Math.pow(1 - t, 3); -} - -export function IconCloud({ icons, images }: IconCloudProps) { - const canvasRef = useRef(null); - const [iconPositions, setIconPositions] = useState([]); - const [rotation, setRotation] = useState({ x: 0, y: 0 }); - const [isDragging, setIsDragging] = useState(false); - const [lastMousePos, setLastMousePos] = useState({ x: 0, y: 0 }); - const [mousePos, setMousePos] = useState({ x: 0, y: 0 }); - const [targetRotation, setTargetRotation] = useState<{ - x: number; - y: number; - startX: number; - startY: number; - distance: number; - startTime: number; - duration: number; - } | null>(null); - const animationFrameRef = useRef(); - const rotationRef = useRef(rotation); - const iconCanvasesRef = useRef([]); - const imagesLoadedRef = useRef([]); - - // Create icon canvases once when icons/images change - useEffect(() => { - if (!icons && !images) return; - - const items = icons || images || []; - imagesLoadedRef.current = new Array(items.length).fill(false); - - const newIconCanvases = items.map((item, index) => { - const offscreen = document.createElement("canvas"); - offscreen.width = 40; - offscreen.height = 40; - const offCtx = offscreen.getContext("2d"); - - if (offCtx) { - if (images) { - // Handle image URLs directly - const img = new Image(); - img.crossOrigin = "anonymous"; - img.src = items[index] as string; - img.onload = () => { - offCtx.clearRect(0, 0, offscreen.width, offscreen.height); - - // Create circular clipping path - offCtx.beginPath(); - offCtx.arc(20, 20, 20, 0, Math.PI * 2); - offCtx.closePath(); - offCtx.clip(); - - // Draw the image - offCtx.drawImage(img, 0, 0, 40, 40); - - imagesLoadedRef.current[index] = true; - }; - } else { - // Handle SVG icons - offCtx.scale(0.4, 0.4); - const svgString = renderToString(item as React.ReactElement); - const img = new Image(); - img.src = "data:image/svg+xml;base64," + btoa(svgString); - img.onload = () => { - offCtx.clearRect(0, 0, offscreen.width, offscreen.height); - offCtx.drawImage(img, 0, 0); - imagesLoadedRef.current[index] = true; - }; - } - } - return offscreen; - }); - - iconCanvasesRef.current = newIconCanvases; - }, [icons, images]); - - // Generate initial icon positions on a sphere - useEffect(() => { - const items = icons || images || []; - const newIcons: Icon[] = []; - const numIcons = items.length || 20; - - // Fibonacci sphere parameters - const offset = 2 / numIcons; - const increment = Math.PI * (3 - Math.sqrt(5)); - - for (let i = 0; i < numIcons; i++) { - const y = i * offset - 1 + offset / 2; - const r = Math.sqrt(1 - y * y); - const phi = i * increment; - - const x = Math.cos(phi) * r; - const z = Math.sin(phi) * r; - - newIcons.push({ - x: x * 100, - y: y * 100, - z: z * 100, - scale: 1, - opacity: 1, - id: i, - }); - } - setIconPositions(newIcons); - }, [icons, images]); - - // Handle mouse events - const handleMouseDown = (e: React.MouseEvent) => { - const rect = canvasRef.current?.getBoundingClientRect(); - if (!rect || !canvasRef.current) return; - - const x = e.clientX - rect.left; - const y = e.clientY - rect.top; - - const ctx = canvasRef.current.getContext("2d"); - if (!ctx) return; - - iconPositions.forEach((icon) => { - const cosX = Math.cos(rotationRef.current.x); - const sinX = Math.sin(rotationRef.current.x); - const cosY = Math.cos(rotationRef.current.y); - const sinY = Math.sin(rotationRef.current.y); - - const rotatedX = icon.x * cosY - icon.z * sinY; - const rotatedZ = icon.x * sinY + icon.z * cosY; - const rotatedY = icon.y * cosX + rotatedZ * sinX; - - const screenX = canvasRef.current!.width / 2 + rotatedX; - const screenY = canvasRef.current!.height / 2 + rotatedY; - - const scale = (rotatedZ + 200) / 300; - const radius = 20 * scale; - const dx = x - screenX; - const dy = y - screenY; - - if (dx * dx + dy * dy < radius * radius) { - const targetX = -Math.atan2( - icon.y, - Math.sqrt(icon.x * icon.x + icon.z * icon.z), - ); - const targetY = Math.atan2(icon.x, icon.z); - - const currentX = rotationRef.current.x; - const currentY = rotationRef.current.y; - const distance = Math.sqrt( - Math.pow(targetX - currentX, 2) + Math.pow(targetY - currentY, 2), - ); - - const duration = Math.min(2000, Math.max(800, distance * 1000)); - - setTargetRotation({ - x: targetX, - y: targetY, - startX: currentX, - startY: currentY, - distance, - startTime: performance.now(), - duration, - }); - return; - } - }); - - setIsDragging(true); - setLastMousePos({ x: e.clientX, y: e.clientY }); - }; - - const handleMouseMove = (e: React.MouseEvent) => { - const rect = canvasRef.current?.getBoundingClientRect(); - if (rect) { - const x = e.clientX - rect.left; - const y = e.clientY - rect.top; - setMousePos({ x, y }); - } - - if (isDragging) { - const deltaX = e.clientX - lastMousePos.x; - const deltaY = e.clientY - lastMousePos.y; - - rotationRef.current = { - x: rotationRef.current.x + deltaY * 0.002, - y: rotationRef.current.y + deltaX * 0.002, - }; - - setLastMousePos({ x: e.clientX, y: e.clientY }); - } - }; - - const handleMouseUp = () => { - setIsDragging(false); - }; - - // Animation and rendering - useEffect(() => { - const canvas = canvasRef.current; - const ctx = canvas?.getContext("2d"); - if (!canvas || !ctx) return; - - const animate = () => { - ctx.clearRect(0, 0, canvas.width, canvas.height); - - const centerX = canvas.width / 2; - const centerY = canvas.height / 2; - const maxDistance = Math.sqrt(centerX * centerX + centerY * centerY); - const dx = mousePos.x - centerX; - const dy = mousePos.y - centerY; - const distance = Math.sqrt(dx * dx + dy * dy); - const speed = 0.003 + (distance / maxDistance) * 0.01; - - if (targetRotation) { - const elapsed = performance.now() - targetRotation.startTime; - const progress = Math.min(1, elapsed / targetRotation.duration); - const easedProgress = easeOutCubic(progress); - - rotationRef.current = { - x: - targetRotation.startX + - (targetRotation.x - targetRotation.startX) * easedProgress, - y: - targetRotation.startY + - (targetRotation.y - targetRotation.startY) * easedProgress, - }; - - if (progress >= 1) { - setTargetRotation(null); - } - } else if (!isDragging) { - rotationRef.current = { - x: rotationRef.current.x + (dy / canvas.height) * speed, - y: rotationRef.current.y + (dx / canvas.width) * speed, - }; - } - - iconPositions.forEach((icon, index) => { - const cosX = Math.cos(rotationRef.current.x); - const sinX = Math.sin(rotationRef.current.x); - const cosY = Math.cos(rotationRef.current.y); - const sinY = Math.sin(rotationRef.current.y); - - const rotatedX = icon.x * cosY - icon.z * sinY; - const rotatedZ = icon.x * sinY + icon.z * cosY; - const rotatedY = icon.y * cosX + rotatedZ * sinX; - - const scale = (rotatedZ + 200) / 300; - const opacity = Math.max(0.2, Math.min(1, (rotatedZ + 150) / 200)); - - ctx.save(); - ctx.translate( - canvas.width / 2 + rotatedX, - canvas.height / 2 + rotatedY, - ); - ctx.scale(scale, scale); - ctx.globalAlpha = opacity; - - if (icons || images) { - // Only try to render icons/images if they exist - if ( - iconCanvasesRef.current[index] && - imagesLoadedRef.current[index] - ) { - ctx.drawImage(iconCanvasesRef.current[index], -20, -20, 40, 40); - } - } else { - // Show numbered circles if no icons/images are provided - ctx.beginPath(); - ctx.arc(0, 0, 20, 0, Math.PI * 2); - ctx.fillStyle = "#4444ff"; - ctx.fill(); - ctx.fillStyle = "white"; - ctx.textAlign = "center"; - ctx.textBaseline = "middle"; - ctx.font = "16px Arial"; - ctx.fillText(`${icon.id + 1}`, 0, 0); - } - - ctx.restore(); - }); - animationFrameRef.current = requestAnimationFrame(animate); - }; - - animate(); - - return () => { - if (animationFrameRef.current) { - cancelAnimationFrame(animationFrameRef.current); - } - }; - }, [icons, images, iconPositions, isDragging, mousePos, targetRotation]); - - return ( - - ); -} diff --git a/src/components/fancy/marqee.tsx b/src/components/fancy/marqee.tsx deleted file mode 100644 index b7650de..0000000 --- a/src/components/fancy/marqee.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { cn } from "../cn"; -import { ComponentPropsWithoutRef } from "react"; - -interface MarqueeProps extends ComponentPropsWithoutRef<"div"> { - /** - * Optional CSS class name to apply custom styles - */ - className?: string; - /** - * Whether to reverse the animation direction - * @default false - */ - reverse?: boolean; - /** - * Whether to pause the animation on hover - * @default false - */ - pauseOnHover?: boolean; - /** - * Content to be displayed in the marquee - */ - children: React.ReactNode; - /** - * Whether to animate vertically instead of horizontally - * @default false - */ - vertical?: boolean; - /** - * Number of times to repeat the content - * @default 4 - */ - repeat?: number; -} - -export function Marquee({ - className, - reverse = false, - pauseOnHover = false, - children, - vertical = false, - repeat = 4, - ...props -}: MarqueeProps) { - return ( -
- {Array(repeat) - .fill(0) - .map((_, i) => ( -
- {children} -
- ))} -
- ); -} diff --git a/src/components/fancy/typewriter.tsx b/src/components/fancy/typewriter.tsx deleted file mode 100644 index 30e2652..0000000 --- a/src/components/fancy/typewriter.tsx +++ /dev/null @@ -1,133 +0,0 @@ -"use client"; -import { cn } from "../cn"; -import { motion, Variants } from "motion/react"; -import { useEffect, useState } from "react"; - -interface TypewriterProps { - text: string | string[]; - speed?: number; - initialDelay?: number; - waitTime?: number; - deleteSpeed?: number; - loop?: boolean; - className?: string; - showCursor?: boolean; - hideCursorOnType?: boolean; - cursorChar?: string | React.ReactNode; - cursorAnimationVariants?: { - initial: Variants["initial"]; - animate: Variants["animate"]; - }; - cursorClassName?: string; -} - -const Typewriter = ({ - text, - speed = 50, - initialDelay = 0, - waitTime = 2000, - deleteSpeed = 30, - loop = true, - className, - showCursor = true, - hideCursorOnType = false, - cursorChar = "|", - cursorClassName = "ml-1", - cursorAnimationVariants = { - initial: { opacity: 0 }, - animate: { - opacity: 1, - transition: { - duration: 0.01, - repeat: Infinity, - repeatDelay: 0.4, - repeatType: "reverse", - }, - }, - }, -}: TypewriterProps) => { - const [displayText, setDisplayText] = useState(""); - const [currentIndex, setCurrentIndex] = useState(0); - const [isDeleting, setIsDeleting] = useState(false); - const [currentTextIndex, setCurrentTextIndex] = useState(0); - - const texts = Array.isArray(text) ? text : [text]; - - useEffect(() => { - let timeout: NodeJS.Timeout; - - const currentText = texts[currentTextIndex]; - - const startTyping = () => { - if (isDeleting) { - if (displayText === "") { - setIsDeleting(false); - if (currentTextIndex === texts.length - 1 && !loop) { - return; - } - setCurrentTextIndex((prev) => (prev + 1) % texts.length); - setCurrentIndex(0); - timeout = setTimeout(() => {}, waitTime); - } else { - timeout = setTimeout(() => { - setDisplayText((prev) => prev.slice(0, -1)); - }, deleteSpeed); - } - } else { - if (currentIndex < currentText.length) { - timeout = setTimeout(() => { - setDisplayText((prev) => prev + currentText[currentIndex]); - setCurrentIndex((prev) => prev + 1); - }, speed); - } else if (texts.length > 1) { - timeout = setTimeout(() => { - setIsDeleting(true); - }, waitTime); - } - } - }; - - // Apply initial delay only at the start - if (currentIndex === 0 && !isDeleting && displayText === "") { - timeout = setTimeout(startTyping, initialDelay); - } else { - startTyping(); - } - - return () => clearTimeout(timeout); - }, [ - currentIndex, - displayText, - isDeleting, - speed, - deleteSpeed, - waitTime, - texts, - currentTextIndex, - loop, - ]); - - return ( -
- {displayText} - {showCursor && ( - - {cursorChar} - - )} -
- ); -}; - -export default Typewriter; diff --git a/src/components/nUI/Footer.tsx b/src/components/nUI/Footer.tsx deleted file mode 100644 index 14c3274..0000000 --- a/src/components/nUI/Footer.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import React from "react"; - -import { IconType } from "react-icons"; -import { tv } from "tailwind-variants"; - -export const footerVariants = tv({ - base: "w-full bg-primary", -}); - -export interface FooterProps { - social: { - name: string; - href: string; - icon: IconType; - }[]; - links: { - name: string; - children: { - name: string; - href: string; - }[]; - }[]; - copylight?: string; - className?: string; - children?: React.ReactNode; -} - -export const Footer: React.FC = ({ - social, - links, - children, - className, - copylight = " 2021- Neody. All rights reserved.", -}) => { - const maxWidth = links.length < 4 ? "max-w-4xl" : "max-w-5xl"; - - return ( -
-
-
- {links.map((item) => ( -
-

- {item.name} -

- -
- ))} - {children} -
-
-
-
-

- © {copylight} -

-
- {social.map((item) => ( - - - - ))} -
-
-
-
-
-
- ); -}; -Footer.displayName = "Footer"; diff --git a/src/components/nUI/Header.tsx b/src/components/nUI/Header.tsx deleted file mode 100644 index 368a3d2..0000000 --- a/src/components/nUI/Header.tsx +++ /dev/null @@ -1,348 +0,0 @@ -import type React from "react"; -import { type ComponentPropsWithoutRef, forwardRef, useState } from "react"; -import { tv } from "tailwind-variants"; -import { motion, useMotionValueEvent, useScroll } from "motion/react"; -import { useLockBodyScroll, useToggle } from "react-use"; -import { MenuToggle } from "./MenuToggle"; -import { useIsWide } from "./hooks"; -import Link from "next/link"; - -const headerVariants = tv({ - base: "fixed inset-x-0 top-0 z-50 py-2 transition-[padding-top,padding-bottom,box-shadow] ease-in-out lg:py-0 text-white", - variants: { - isScrolled: { - true: "border-b border-outline bg-primary border-primary backdrop-blur-sm lg:bg-opacity-70", - false: "bg-transparent lg:py-4", - }, - }, -}); - -const barVariants = { - rest: { opacity: 0, y: 5 }, - hover: { - opacity: 1, - y: 0, - transition: { - delay: 0.1, - type: "spring", - }, - }, -}; - -const mobileMenuContainerVariants = { - open: { - display: "block", - }, - closed: { - display: "none", - transition: { delay: 0.8 }, - }, -}; - -const mobileMenuItemContainerVariants = { - open: { - opacity: 1, - transition: { - ease: "easeOut", - staggerChildren: 0.07, - delayChildren: 0.2, - }, - }, - closed: { - opacity: 0, - transition: { delay: 0.6, staggerChildren: 0.05, staggerDirection: -1 }, - }, -}; - -const mobileMenuItemVariants = { - open: { - y: 0, - opacity: 1, - transition: { - ease: "easeOut", - y: { stiffness: 1000, velocity: -100 }, - }, - }, - closed: { - y: 50, - opacity: 0, - transition: { - ease: "easeIn", - y: { stiffness: 1000 }, - }, - }, -}; - -const mobileMenuButtonsVariants = { - open: { - opacity: 1, - transition: { delay: 0.4, duration: 0.4 }, - }, - closed: { - opacity: 0, - transition: { delay: 0 }, - }, -}; - -const headerAnimationVariants = { - show: { - top: 0, - transition: { ease: "easeOut", stiffness: 100 }, - }, - hide: { - top: -88, - }, -}; - -interface MobileMenuItemProps { - name: string; - href: string; - index: number; - isCurrent: boolean; - color: string; -} - -const MobileMenuItem: React.FC = ({ - name, - href, - color, - isCurrent, -}) => { - return ( - - - {name} - {isCurrent && ( - - Current page - - - )} - - - ); -}; - -export interface HeaderButtonProps { - href?: string; - target?: "_blank" | "_self" | "_parent" | "_top"; - title: string; - onClick?: () => void; - disabled?: boolean; - className?: string; -} - -export interface HeaderProps extends ComponentPropsWithoutRef<"div"> { - brand?: { - name: string; - href: string; - logo: string; - showTitle?: boolean; - rounded?: boolean; - }; - navigation: { name: string; href: string }[]; - buttons?: HeaderButtonProps[]; - color?: string; - current?: string | number; -} - -export const Header = forwardRef( - ( - { - navigation, - brand = { - logo: "/", - href: "/", - name: "/", - }, - current, - color, - buttons, - }: HeaderProps, - ref, - ) => { - const [isScrolled, setIsScrolled] = useState(false); - const [lastYPosition, setLastYPosition] = useState(0); - const [isHeaderShown, setIsHeaderShown] = useState(true); - const isWide = useIsWide(); - - const { scrollY } = useScroll(); - const [isMobileMenuOpen, toggleMobileMenuOpen] = useToggle(false); - - const headerHeight = 88; - - useLockBodyScroll(isMobileMenuOpen); - - useMotionValueEvent(scrollY, "change", (latest) => { - setIsScrolled(latest > 10); - if (!isMobileMenuOpen) { - setIsHeaderShown(latest < headerHeight || latest < lastYPosition); - setLastYPosition(latest); - } - }); - - return ( - - - toggleMobileMenuOpen()} /> - - - {brand.name} - {brand.showTitle && ( - - {brand.name} - - )} - - - - - {navigation.map((item, index) => { - const _color = color || ""; - const isCurrent = - (typeof current === "string" && item.href === current) || - (typeof current === "number" && index === current); - return ( - - ); - })} - {buttons?.length && ( - - {buttons?.map((buttonProps) => { - return buttonProps.href ? ( - - - - ) : ( - - ); - })} - - )} - - - -
- {navigation.map((item, index) => { - const _color = color; - const isCurrent = - (typeof current === "string" && item.href === current) || - (typeof current === "number" && index === current); - return ( - - {item.name} - {isCurrent ? ( - - - - ) : ( - - - - )} - - ); - })} -
- -
- {buttons?.map((buttonProps) => { - return buttonProps.href ? ( - - - - ) : ( - - ); - })} -
- -
- - - ); - }, -); -Header.displayName = "Header"; diff --git a/src/components/nUI/MenuToggle.tsx b/src/components/nUI/MenuToggle.tsx deleted file mode 100644 index a03953d..0000000 --- a/src/components/nUI/MenuToggle.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import * as React from "react"; -import { SVGMotionProps, motion } from "motion/react"; - -const Path: React.FC> = (props) => ( - -); - -export interface MenuToggleProps { - toggle: () => void; -} - -export const MenuToggle: React.FC = ({ toggle }) => ( - -); diff --git a/src/components/nUI/hooks.tsx b/src/components/nUI/hooks.tsx deleted file mode 100644 index dd0d0f2..0000000 --- a/src/components/nUI/hooks.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { useEffect, useState } from "react"; -import { useMedia } from "react-use"; - -export const useIsWide = () => { - const [isWide, setIsWide] = useState(false); - - const _isWide = useMedia("(min-width: 780px)", false); - - useEffect(() => { - setIsWide(_isWide); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [_isWide]); - - return isWide; -}; diff --git a/tsconfig.json b/tsconfig.json index 54c5280..5f6ae26 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,18 +1,22 @@ { "compilerOptions": { - "target": "es2017", - "lib": ["dom", "dom.iterable", "esnext"], + "target": "ES2017", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, - "strict": true, + "strict": false, "noEmit": true, - "esModuleInterop": true, + "incremental": true, "module": "esnext", + "esModuleInterop": true, "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "jsx": "react-jsx", - "incremental": true, "plugins": [ { "name": "next" @@ -24,14 +28,13 @@ }, "include": [ "next-env.d.ts", - "**/*.ts", - "**/*.tsx", ".next/types/**/*.ts", - "nextra.config.jsx", - "theme.config.jsx", - "app/libraries/logto.js", - "app/ui/cobe.jsx", - ".next/dev/types/**/*.ts" + ".next/dev/types/**/*.ts", + "**/*.mts", + "**/*.ts", + "**/*.tsx" ], - "exclude": ["node_modules", "sst.config.ts"] + "exclude": [ + "node_modules" + ] } From 2cce34bbde7064e040c661e94391798b353a11ec Mon Sep 17 00:00:00 2001 From: maamokun Date: Mon, 27 Oct 2025 23:27:45 +0900 Subject: [PATCH 06/10] feat: add some components --- src/components/ClickSpark.tsx | 161 ++++ src/components/SplashCursor.tsx | 1288 +++++++++++++++++++++++++++++++ src/components/TargetCursor.tsx | 359 +++++++++ 3 files changed, 1808 insertions(+) create mode 100644 src/components/ClickSpark.tsx create mode 100644 src/components/SplashCursor.tsx create mode 100644 src/components/TargetCursor.tsx diff --git a/src/components/ClickSpark.tsx b/src/components/ClickSpark.tsx new file mode 100644 index 0000000..f1406a3 --- /dev/null +++ b/src/components/ClickSpark.tsx @@ -0,0 +1,161 @@ +import React, { useRef, useEffect, useCallback } from 'react'; + +interface ClickSparkProps { + sparkColor?: string; + sparkSize?: number; + sparkRadius?: number; + sparkCount?: number; + duration?: number; + easing?: 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out'; + extraScale?: number; + children?: React.ReactNode; +} + +interface Spark { + x: number; + y: number; + angle: number; + startTime: number; +} + +const ClickSpark: React.FC = ({ + sparkColor = '#fff', + sparkSize = 10, + sparkRadius = 15, + sparkCount = 8, + duration = 400, + easing = 'ease-out', + extraScale = 1.0, + children +}) => { + const canvasRef = useRef(null); + const sparksRef = useRef([]); + const startTimeRef = useRef(null); + + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + + const parent = canvas.parentElement; + if (!parent) return; + + let resizeTimeout: NodeJS.Timeout; + + const resizeCanvas = () => { + const { width, height } = parent.getBoundingClientRect(); + if (canvas.width !== width || canvas.height !== height) { + canvas.width = width; + canvas.height = height; + } + }; + + const handleResize = () => { + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(resizeCanvas, 100); + }; + + const ro = new ResizeObserver(handleResize); + ro.observe(parent); + + resizeCanvas(); + + return () => { + ro.disconnect(); + clearTimeout(resizeTimeout); + }; + }, []); + + const easeFunc = useCallback( + (t: number) => { + switch (easing) { + case 'linear': + return t; + case 'ease-in': + return t * t; + case 'ease-in-out': + return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t; + default: + return t * (2 - t); + } + }, + [easing] + ); + + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + const ctx = canvas.getContext('2d'); + if (!ctx) return; + + let animationId: number; + + const draw = (timestamp: number) => { + if (!startTimeRef.current) { + startTimeRef.current = timestamp; + } + ctx?.clearRect(0, 0, canvas.width, canvas.height); + + sparksRef.current = sparksRef.current.filter((spark: Spark) => { + const elapsed = timestamp - spark.startTime; + if (elapsed >= duration) { + return false; + } + + const progress = elapsed / duration; + const eased = easeFunc(progress); + + const distance = eased * sparkRadius * extraScale; + const lineLength = sparkSize * (1 - eased); + + const x1 = spark.x + distance * Math.cos(spark.angle); + const y1 = spark.y + distance * Math.sin(spark.angle); + const x2 = spark.x + (distance + lineLength) * Math.cos(spark.angle); + const y2 = spark.y + (distance + lineLength) * Math.sin(spark.angle); + + ctx.strokeStyle = sparkColor; + ctx.lineWidth = 2; + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.stroke(); + + return true; + }); + + animationId = requestAnimationFrame(draw); + }; + + animationId = requestAnimationFrame(draw); + + return () => { + cancelAnimationFrame(animationId); + }; + }, [sparkColor, sparkSize, sparkRadius, sparkCount, duration, easeFunc, extraScale]); + + const handleClick = (e: React.MouseEvent): void => { + const canvas = canvasRef.current; + if (!canvas) return; + const rect = canvas.getBoundingClientRect(); + const x = e.clientX - rect.left; + const y = e.clientY - rect.top; + + const now = performance.now(); + const newSparks: Spark[] = Array.from({ length: sparkCount }, (_, i) => ({ + x, + y, + angle: (2 * Math.PI * i) / sparkCount, + startTime: now + })); + + sparksRef.current.push(...newSparks); + }; + + return ( +
+ + {children} +
+ ); +}; + +export default ClickSpark; diff --git a/src/components/SplashCursor.tsx b/src/components/SplashCursor.tsx new file mode 100644 index 0000000..06e41e2 --- /dev/null +++ b/src/components/SplashCursor.tsx @@ -0,0 +1,1288 @@ +'use client'; +import React, { useEffect, useRef } from 'react'; + +interface ColorRGB { + r: number; + g: number; + b: number; +} + +interface SplashCursorProps { + SIM_RESOLUTION?: number; + DYE_RESOLUTION?: number; + CAPTURE_RESOLUTION?: number; + DENSITY_DISSIPATION?: number; + VELOCITY_DISSIPATION?: number; + PRESSURE?: number; + PRESSURE_ITERATIONS?: number; + CURL?: number; + SPLAT_RADIUS?: number; + SPLAT_FORCE?: number; + SHADING?: boolean; + COLOR_UPDATE_SPEED?: number; + BACK_COLOR?: ColorRGB; + TRANSPARENT?: boolean; +} + +interface Pointer { + id: number; + texcoordX: number; + texcoordY: number; + prevTexcoordX: number; + prevTexcoordY: number; + deltaX: number; + deltaY: number; + down: boolean; + moved: boolean; + color: ColorRGB; +} + +function pointerPrototype(): Pointer { + return { + id: -1, + texcoordX: 0, + texcoordY: 0, + prevTexcoordX: 0, + prevTexcoordY: 0, + deltaX: 0, + deltaY: 0, + down: false, + moved: false, + color: { r: 0, g: 0, b: 0 } + }; +} + +export default function SplashCursor({ + SIM_RESOLUTION = 128, + DYE_RESOLUTION = 1440, + CAPTURE_RESOLUTION = 512, + DENSITY_DISSIPATION = 3.5, + VELOCITY_DISSIPATION = 2, + PRESSURE = 0.1, + PRESSURE_ITERATIONS = 20, + CURL = 3, + SPLAT_RADIUS = 0.2, + SPLAT_FORCE = 6000, + SHADING = true, + COLOR_UPDATE_SPEED = 10, + BACK_COLOR = { r: 0.5, g: 0, b: 0 }, + TRANSPARENT = true +}: SplashCursorProps) { + const canvasRef = useRef(null); + + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + + let pointers: Pointer[] = [pointerPrototype()]; + + let config = { + SIM_RESOLUTION: SIM_RESOLUTION!, + DYE_RESOLUTION: DYE_RESOLUTION!, + CAPTURE_RESOLUTION: CAPTURE_RESOLUTION!, + DENSITY_DISSIPATION: DENSITY_DISSIPATION!, + VELOCITY_DISSIPATION: VELOCITY_DISSIPATION!, + PRESSURE: PRESSURE!, + PRESSURE_ITERATIONS: PRESSURE_ITERATIONS!, + CURL: CURL!, + SPLAT_RADIUS: SPLAT_RADIUS!, + SPLAT_FORCE: SPLAT_FORCE!, + SHADING, + COLOR_UPDATE_SPEED: COLOR_UPDATE_SPEED!, + PAUSED: false, + BACK_COLOR, + TRANSPARENT + }; + + const { gl, ext } = getWebGLContext(canvas); + if (!gl || !ext) return; + + if (!ext.supportLinearFiltering) { + config.DYE_RESOLUTION = 256; + config.SHADING = false; + } + + function getWebGLContext(canvas: HTMLCanvasElement) { + const params = { + alpha: true, + depth: false, + stencil: false, + antialias: false, + preserveDrawingBuffer: false + }; + + let gl = canvas.getContext('webgl2', params) as WebGL2RenderingContext | null; + + if (!gl) { + gl = (canvas.getContext('webgl', params) || + canvas.getContext('experimental-webgl', params)) as WebGL2RenderingContext | null; + } + + if (!gl) { + throw new Error('Unable to initialize WebGL.'); + } + + const isWebGL2 = 'drawBuffers' in gl; + + let supportLinearFiltering = false; + let halfFloat = null; + + if (isWebGL2) { + (gl as WebGL2RenderingContext).getExtension('EXT_color_buffer_float'); + supportLinearFiltering = !!(gl as WebGL2RenderingContext).getExtension('OES_texture_float_linear'); + } else { + halfFloat = gl.getExtension('OES_texture_half_float'); + supportLinearFiltering = !!gl.getExtension('OES_texture_half_float_linear'); + } + + gl.clearColor(0, 0, 0, 1); + + const halfFloatTexType = isWebGL2 + ? (gl as WebGL2RenderingContext).HALF_FLOAT + : (halfFloat && (halfFloat as any).HALF_FLOAT_OES) || 0; + + let formatRGBA: any; + let formatRG: any; + let formatR: any; + + if (isWebGL2) { + formatRGBA = getSupportedFormat(gl, (gl as WebGL2RenderingContext).RGBA16F, gl.RGBA, halfFloatTexType); + formatRG = getSupportedFormat( + gl, + (gl as WebGL2RenderingContext).RG16F, + (gl as WebGL2RenderingContext).RG, + halfFloatTexType + ); + formatR = getSupportedFormat( + gl, + (gl as WebGL2RenderingContext).R16F, + (gl as WebGL2RenderingContext).RED, + halfFloatTexType + ); + } else { + formatRGBA = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType); + formatRG = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType); + formatR = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType); + } + + return { + gl, + ext: { + formatRGBA, + formatRG, + formatR, + halfFloatTexType, + supportLinearFiltering + } + }; + } + + function getSupportedFormat( + gl: WebGLRenderingContext | WebGL2RenderingContext, + internalFormat: number, + format: number, + type: number + ): { internalFormat: number; format: number } | null { + if (!supportRenderTextureFormat(gl, internalFormat, format, type)) { + if ('drawBuffers' in gl) { + const gl2 = gl as WebGL2RenderingContext; + switch (internalFormat) { + case gl2.R16F: + return getSupportedFormat(gl2, gl2.RG16F, gl2.RG, type); + case gl2.RG16F: + return getSupportedFormat(gl2, gl2.RGBA16F, gl2.RGBA, type); + default: + return null; + } + } + return null; + } + return { internalFormat, format }; + } + + function supportRenderTextureFormat( + gl: WebGLRenderingContext | WebGL2RenderingContext, + internalFormat: number, + format: number, + type: number + ) { + const texture = gl.createTexture(); + if (!texture) return false; + + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 4, 4, 0, format, type, null); + + const fbo = gl.createFramebuffer(); + if (!fbo) return false; + + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); + const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER); + return status === gl.FRAMEBUFFER_COMPLETE; + } + + function hashCode(s: string) { + if (!s.length) return 0; + let hash = 0; + for (let i = 0; i < s.length; i++) { + hash = (hash << 5) - hash + s.charCodeAt(i); + hash |= 0; + } + return hash; + } + + function addKeywords(source: string, keywords: string[] | null) { + if (!keywords) return source; + let keywordsString = ''; + for (const keyword of keywords) { + keywordsString += `#define ${keyword}\n`; + } + return keywordsString + source; + } + + function compileShader(type: number, source: string, keywords: string[] | null = null): WebGLShader | null { + const shaderSource = addKeywords(source, keywords); + const shader = gl.createShader(type); + if (!shader) return null; + gl.shaderSource(shader, shaderSource); + gl.compileShader(shader); + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + console.trace(gl.getShaderInfoLog(shader)); + } + return shader; + } + + function createProgram(vertexShader: WebGLShader | null, fragmentShader: WebGLShader | null): WebGLProgram | null { + if (!vertexShader || !fragmentShader) return null; + const program = gl.createProgram(); + if (!program) return null; + gl.attachShader(program, vertexShader); + gl.attachShader(program, fragmentShader); + gl.linkProgram(program); + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + console.trace(gl.getProgramInfoLog(program)); + } + return program; + } + + function getUniforms(program: WebGLProgram) { + let uniforms: Record = {}; + const uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); + for (let i = 0; i < uniformCount; i++) { + const uniformInfo = gl.getActiveUniform(program, i); + if (uniformInfo) { + uniforms[uniformInfo.name] = gl.getUniformLocation(program, uniformInfo.name); + } + } + return uniforms; + } + + class Program { + program: WebGLProgram | null; + uniforms: Record; + + constructor(vertexShader: WebGLShader | null, fragmentShader: WebGLShader | null) { + this.program = createProgram(vertexShader, fragmentShader); + this.uniforms = this.program ? getUniforms(this.program) : {}; + } + + bind() { + if (this.program) gl.useProgram(this.program); + } + } + + class Material { + vertexShader: WebGLShader | null; + fragmentShaderSource: string; + programs: Record; + activeProgram: WebGLProgram | null; + uniforms: Record; + + constructor(vertexShader: WebGLShader | null, fragmentShaderSource: string) { + this.vertexShader = vertexShader; + this.fragmentShaderSource = fragmentShaderSource; + this.programs = {}; + this.activeProgram = null; + this.uniforms = {}; + } + + setKeywords(keywords: string[]) { + let hash = 0; + for (const kw of keywords) { + hash += hashCode(kw); + } + let program = this.programs[hash]; + if (program == null) { + const fragmentShader = compileShader(gl.FRAGMENT_SHADER, this.fragmentShaderSource, keywords); + program = createProgram(this.vertexShader, fragmentShader); + this.programs[hash] = program; + } + if (program === this.activeProgram) return; + if (program) { + this.uniforms = getUniforms(program); + } + this.activeProgram = program; + } + + bind() { + if (this.activeProgram) { + gl.useProgram(this.activeProgram); + } + } + } + + const baseVertexShader = compileShader( + gl.VERTEX_SHADER, + ` + precision highp float; + attribute vec2 aPosition; + varying vec2 vUv; + varying vec2 vL; + varying vec2 vR; + varying vec2 vT; + varying vec2 vB; + uniform vec2 texelSize; + + void main () { + vUv = aPosition * 0.5 + 0.5; + vL = vUv - vec2(texelSize.x, 0.0); + vR = vUv + vec2(texelSize.x, 0.0); + vT = vUv + vec2(0.0, texelSize.y); + vB = vUv - vec2(0.0, texelSize.y); + gl_Position = vec4(aPosition, 0.0, 1.0); + } + ` + ); + + const copyShader = compileShader( + gl.FRAGMENT_SHADER, + ` + precision mediump float; + precision mediump sampler2D; + varying highp vec2 vUv; + uniform sampler2D uTexture; + + void main () { + gl_FragColor = texture2D(uTexture, vUv); + } + ` + ); + + const clearShader = compileShader( + gl.FRAGMENT_SHADER, + ` + precision mediump float; + precision mediump sampler2D; + varying highp vec2 vUv; + uniform sampler2D uTexture; + uniform float value; + + void main () { + gl_FragColor = value * texture2D(uTexture, vUv); + } + ` + ); + + const displayShaderSource = ` + precision highp float; + precision highp sampler2D; + varying vec2 vUv; + varying vec2 vL; + varying vec2 vR; + varying vec2 vT; + varying vec2 vB; + uniform sampler2D uTexture; + uniform sampler2D uDithering; + uniform vec2 ditherScale; + uniform vec2 texelSize; + + vec3 linearToGamma (vec3 color) { + color = max(color, vec3(0)); + return max(1.055 * pow(color, vec3(0.416666667)) - 0.055, vec3(0)); + } + + void main () { + vec3 c = texture2D(uTexture, vUv).rgb; + #ifdef SHADING + vec3 lc = texture2D(uTexture, vL).rgb; + vec3 rc = texture2D(uTexture, vR).rgb; + vec3 tc = texture2D(uTexture, vT).rgb; + vec3 bc = texture2D(uTexture, vB).rgb; + + float dx = length(rc) - length(lc); + float dy = length(tc) - length(bc); + + vec3 n = normalize(vec3(dx, dy, length(texelSize))); + vec3 l = vec3(0.0, 0.0, 1.0); + + float diffuse = clamp(dot(n, l) + 0.7, 0.7, 1.0); + c *= diffuse; + #endif + + float a = max(c.r, max(c.g, c.b)); + gl_FragColor = vec4(c, a); + } + `; + + const splatShader = compileShader( + gl.FRAGMENT_SHADER, + ` + precision highp float; + precision highp sampler2D; + varying vec2 vUv; + uniform sampler2D uTarget; + uniform float aspectRatio; + uniform vec3 color; + uniform vec2 point; + uniform float radius; + + void main () { + vec2 p = vUv - point.xy; + p.x *= aspectRatio; + vec3 splat = exp(-dot(p, p) / radius) * color; + vec3 base = texture2D(uTarget, vUv).xyz; + gl_FragColor = vec4(base + splat, 1.0); + } + ` + ); + + const advectionShader = compileShader( + gl.FRAGMENT_SHADER, + ` + precision highp float; + precision highp sampler2D; + varying vec2 vUv; + uniform sampler2D uVelocity; + uniform sampler2D uSource; + uniform vec2 texelSize; + uniform vec2 dyeTexelSize; + uniform float dt; + uniform float dissipation; + + vec4 bilerp (sampler2D sam, vec2 uv, vec2 tsize) { + vec2 st = uv / tsize - 0.5; + vec2 iuv = floor(st); + vec2 fuv = fract(st); + + vec4 a = texture2D(sam, (iuv + vec2(0.5, 0.5)) * tsize); + vec4 b = texture2D(sam, (iuv + vec2(1.5, 0.5)) * tsize); + vec4 c = texture2D(sam, (iuv + vec2(0.5, 1.5)) * tsize); + vec4 d = texture2D(sam, (iuv + vec2(1.5, 1.5)) * tsize); + + return mix(mix(a, b, fuv.x), mix(c, d, fuv.x), fuv.y); + } + + void main () { + #ifdef MANUAL_FILTERING + vec2 coord = vUv - dt * bilerp(uVelocity, vUv, texelSize).xy * texelSize; + vec4 result = bilerp(uSource, coord, dyeTexelSize); + #else + vec2 coord = vUv - dt * texture2D(uVelocity, vUv).xy * texelSize; + vec4 result = texture2D(uSource, coord); + #endif + float decay = 1.0 + dissipation * dt; + gl_FragColor = result / decay; + } + `, + ext.supportLinearFiltering ? null : ['MANUAL_FILTERING'] + ); + + const divergenceShader = compileShader( + gl.FRAGMENT_SHADER, + ` + precision mediump float; + precision mediump sampler2D; + varying highp vec2 vUv; + varying highp vec2 vL; + varying highp vec2 vR; + varying highp vec2 vT; + varying highp vec2 vB; + uniform sampler2D uVelocity; + + void main () { + float L = texture2D(uVelocity, vL).x; + float R = texture2D(uVelocity, vR).x; + float T = texture2D(uVelocity, vT).y; + float B = texture2D(uVelocity, vB).y; + + vec2 C = texture2D(uVelocity, vUv).xy; + if (vL.x < 0.0) { L = -C.x; } + if (vR.x > 1.0) { R = -C.x; } + if (vT.y > 1.0) { T = -C.y; } + if (vB.y < 0.0) { B = -C.y; } + + float div = 0.5 * (R - L + T - B); + gl_FragColor = vec4(div, 0.0, 0.0, 1.0); + } + ` + ); + + const curlShader = compileShader( + gl.FRAGMENT_SHADER, + ` + precision mediump float; + precision mediump sampler2D; + varying highp vec2 vUv; + varying highp vec2 vL; + varying highp vec2 vR; + varying highp vec2 vT; + varying highp vec2 vB; + uniform sampler2D uVelocity; + + void main () { + float L = texture2D(uVelocity, vL).y; + float R = texture2D(uVelocity, vR).y; + float T = texture2D(uVelocity, vT).x; + float B = texture2D(uVelocity, vB).x; + float vorticity = R - L - T + B; + gl_FragColor = vec4(0.5 * vorticity, 0.0, 0.0, 1.0); + } + ` + ); + + const vorticityShader = compileShader( + gl.FRAGMENT_SHADER, + ` + precision highp float; + precision highp sampler2D; + varying vec2 vUv; + varying vec2 vL; + varying vec2 vR; + varying vec2 vT; + varying vec2 vB; + uniform sampler2D uVelocity; + uniform sampler2D uCurl; + uniform float curl; + uniform float dt; + + void main () { + float L = texture2D(uCurl, vL).x; + float R = texture2D(uCurl, vR).x; + float T = texture2D(uCurl, vT).x; + float B = texture2D(uCurl, vB).x; + float C = texture2D(uCurl, vUv).x; + + vec2 force = 0.5 * vec2(abs(T) - abs(B), abs(R) - abs(L)); + force /= length(force) + 0.0001; + force *= curl * C; + force.y *= -1.0; + + vec2 velocity = texture2D(uVelocity, vUv).xy; + velocity += force * dt; + velocity = min(max(velocity, -1000.0), 1000.0); + gl_FragColor = vec4(velocity, 0.0, 1.0); + } + ` + ); + + const pressureShader = compileShader( + gl.FRAGMENT_SHADER, + ` + precision mediump float; + precision mediump sampler2D; + varying highp vec2 vUv; + varying highp vec2 vL; + varying highp vec2 vR; + varying highp vec2 vT; + varying highp vec2 vB; + uniform sampler2D uPressure; + uniform sampler2D uDivergence; + + void main () { + float L = texture2D(uPressure, vL).x; + float R = texture2D(uPressure, vR).x; + float T = texture2D(uPressure, vT).x; + float B = texture2D(uPressure, vB).x; + float C = texture2D(uPressure, vUv).x; + float divergence = texture2D(uDivergence, vUv).x; + float pressure = (L + R + B + T - divergence) * 0.25; + gl_FragColor = vec4(pressure, 0.0, 0.0, 1.0); + } + ` + ); + + const gradientSubtractShader = compileShader( + gl.FRAGMENT_SHADER, + ` + precision mediump float; + precision mediump sampler2D; + varying highp vec2 vUv; + varying highp vec2 vL; + varying highp vec2 vR; + varying highp vec2 vT; + varying highp vec2 vB; + uniform sampler2D uPressure; + uniform sampler2D uVelocity; + + void main () { + float L = texture2D(uPressure, vL).x; + float R = texture2D(uPressure, vR).x; + float T = texture2D(uPressure, vT).x; + float B = texture2D(uPressure, vB).x; + vec2 velocity = texture2D(uVelocity, vUv).xy; + velocity.xy -= vec2(R - L, T - B); + gl_FragColor = vec4(velocity, 0.0, 1.0); + } + ` + ); + + const blit = (() => { + const buffer = gl.createBuffer()!; + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, -1, 1, 1, 1, 1, -1]), gl.STATIC_DRAW); + const elemBuffer = gl.createBuffer()!; + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elemBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 0, 2, 3]), gl.STATIC_DRAW); + gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(0); + + return (target: FBO | null, doClear = false) => { + if (!gl) return; + if (!target) { + gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + } else { + gl.viewport(0, 0, target.width, target.height); + gl.bindFramebuffer(gl.FRAMEBUFFER, target.fbo); + } + if (doClear) { + gl.clearColor(0, 0, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + } + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + }; + })(); + + interface FBO { + texture: WebGLTexture; + fbo: WebGLFramebuffer; + width: number; + height: number; + texelSizeX: number; + texelSizeY: number; + attach: (id: number) => number; + } + + interface DoubleFBO { + width: number; + height: number; + texelSizeX: number; + texelSizeY: number; + read: FBO; + write: FBO; + swap: () => void; + } + + let dye: DoubleFBO; + let velocity: DoubleFBO; + let divergence: FBO; + let curl: FBO; + let pressure: DoubleFBO; + + const copyProgram = new Program(baseVertexShader, copyShader); + const clearProgram = new Program(baseVertexShader, clearShader); + const splatProgram = new Program(baseVertexShader, splatShader); + const advectionProgram = new Program(baseVertexShader, advectionShader); + const divergenceProgram = new Program(baseVertexShader, divergenceShader); + const curlProgram = new Program(baseVertexShader, curlShader); + const vorticityProgram = new Program(baseVertexShader, vorticityShader); + const pressureProgram = new Program(baseVertexShader, pressureShader); + const gradienSubtractProgram = new Program(baseVertexShader, gradientSubtractShader); + const displayMaterial = new Material(baseVertexShader, displayShaderSource); + + function createFBO(w: number, h: number, internalFormat: number, format: number, type: number, param: number): FBO { + gl.activeTexture(gl.TEXTURE0); + const texture = gl.createTexture()!; + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, param); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, param); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, w, h, 0, format, type, null); + const fbo = gl.createFramebuffer()!; + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); + gl.viewport(0, 0, w, h); + gl.clear(gl.COLOR_BUFFER_BIT); + + const texelSizeX = 1 / w; + const texelSizeY = 1 / h; + + return { + texture, + fbo, + width: w, + height: h, + texelSizeX, + texelSizeY, + attach(id: number) { + gl.activeTexture(gl.TEXTURE0 + id); + gl.bindTexture(gl.TEXTURE_2D, texture); + return id; + } + }; + } + + function createDoubleFBO( + w: number, + h: number, + internalFormat: number, + format: number, + type: number, + param: number + ): DoubleFBO { + const fbo1 = createFBO(w, h, internalFormat, format, type, param); + const fbo2 = createFBO(w, h, internalFormat, format, type, param); + return { + width: w, + height: h, + texelSizeX: fbo1.texelSizeX, + texelSizeY: fbo1.texelSizeY, + read: fbo1, + write: fbo2, + swap() { + const tmp = this.read; + this.read = this.write; + this.write = tmp; + } + }; + } + + function resizeFBO( + target: FBO, + w: number, + h: number, + internalFormat: number, + format: number, + type: number, + param: number + ) { + const newFBO = createFBO(w, h, internalFormat, format, type, param); + copyProgram.bind(); + if (copyProgram.uniforms.uTexture) gl.uniform1i(copyProgram.uniforms.uTexture, target.attach(0)); + blit(newFBO, false); + return newFBO; + } + + function resizeDoubleFBO( + target: DoubleFBO, + w: number, + h: number, + internalFormat: number, + format: number, + type: number, + param: number + ) { + if (target.width === w && target.height === h) return target; + target.read = resizeFBO(target.read, w, h, internalFormat, format, type, param); + target.write = createFBO(w, h, internalFormat, format, type, param); + target.width = w; + target.height = h; + target.texelSizeX = 1 / w; + target.texelSizeY = 1 / h; + return target; + } + + function initFramebuffers() { + const simRes = getResolution(config.SIM_RESOLUTION!); + const dyeRes = getResolution(config.DYE_RESOLUTION!); + + const texType = ext.halfFloatTexType; + const rgba = ext.formatRGBA; + const rg = ext.formatRG; + const r = ext.formatR; + const filtering = ext.supportLinearFiltering ? gl.LINEAR : gl.NEAREST; + gl.disable(gl.BLEND); + + if (!dye) { + dye = createDoubleFBO(dyeRes.width, dyeRes.height, rgba.internalFormat, rgba.format, texType, filtering); + } else { + dye = resizeDoubleFBO(dye, dyeRes.width, dyeRes.height, rgba.internalFormat, rgba.format, texType, filtering); + } + + if (!velocity) { + velocity = createDoubleFBO(simRes.width, simRes.height, rg.internalFormat, rg.format, texType, filtering); + } else { + velocity = resizeDoubleFBO( + velocity, + simRes.width, + simRes.height, + rg.internalFormat, + rg.format, + texType, + filtering + ); + } + + divergence = createFBO(simRes.width, simRes.height, r.internalFormat, r.format, texType, gl.NEAREST); + curl = createFBO(simRes.width, simRes.height, r.internalFormat, r.format, texType, gl.NEAREST); + pressure = createDoubleFBO(simRes.width, simRes.height, r.internalFormat, r.format, texType, gl.NEAREST); + } + + function updateKeywords() { + const displayKeywords: string[] = []; + if (config.SHADING) displayKeywords.push('SHADING'); + displayMaterial.setKeywords(displayKeywords); + } + + function getResolution(resolution: number) { + const w = gl.drawingBufferWidth; + const h = gl.drawingBufferHeight; + const aspectRatio = w / h; + let aspect = aspectRatio < 1 ? 1 / aspectRatio : aspectRatio; + const min = Math.round(resolution); + const max = Math.round(resolution * aspect); + if (w > h) { + return { width: max, height: min }; + } + return { width: min, height: max }; + } + + function scaleByPixelRatio(input: number) { + const pixelRatio = window.devicePixelRatio || 1; + return Math.floor(input * pixelRatio); + } + + updateKeywords(); + initFramebuffers(); + + let lastUpdateTime = Date.now(); + let colorUpdateTimer = 0.0; + + function updateFrame() { + const dt = calcDeltaTime(); + if (resizeCanvas()) initFramebuffers(); + updateColors(dt); + applyInputs(); + step(dt); + render(null); + requestAnimationFrame(updateFrame); + } + + function calcDeltaTime() { + const now = Date.now(); + let dt = (now - lastUpdateTime) / 1000; + dt = Math.min(dt, 0.016666); + lastUpdateTime = now; + return dt; + } + + function resizeCanvas() { + const width = scaleByPixelRatio(canvas!.clientWidth); + const height = scaleByPixelRatio(canvas!.clientHeight); + if (canvas!.width !== width || canvas!.height !== height) { + canvas!.width = width; + canvas!.height = height; + return true; + } + return false; + } + + function updateColors(dt: number) { + colorUpdateTimer += dt * config.COLOR_UPDATE_SPEED; + if (colorUpdateTimer >= 1) { + colorUpdateTimer = wrap(colorUpdateTimer, 0, 1); + pointers.forEach(p => { + p.color = generateColor(); + }); + } + } + + function applyInputs() { + for (const p of pointers) { + if (p.moved) { + p.moved = false; + splatPointer(p); + } + } + } + + function step(dt: number) { + gl.disable(gl.BLEND); + + curlProgram.bind(); + if (curlProgram.uniforms.texelSize) { + gl.uniform2f(curlProgram.uniforms.texelSize, velocity.texelSizeX, velocity.texelSizeY); + } + if (curlProgram.uniforms.uVelocity) { + gl.uniform1i(curlProgram.uniforms.uVelocity, velocity.read.attach(0)); + } + blit(curl); + + vorticityProgram.bind(); + if (vorticityProgram.uniforms.texelSize) { + gl.uniform2f(vorticityProgram.uniforms.texelSize, velocity.texelSizeX, velocity.texelSizeY); + } + if (vorticityProgram.uniforms.uVelocity) { + gl.uniform1i(vorticityProgram.uniforms.uVelocity, velocity.read.attach(0)); + } + if (vorticityProgram.uniforms.uCurl) { + gl.uniform1i(vorticityProgram.uniforms.uCurl, curl.attach(1)); + } + if (vorticityProgram.uniforms.curl) { + gl.uniform1f(vorticityProgram.uniforms.curl, config.CURL); + } + if (vorticityProgram.uniforms.dt) { + gl.uniform1f(vorticityProgram.uniforms.dt, dt); + } + blit(velocity.write); + velocity.swap(); + + divergenceProgram.bind(); + if (divergenceProgram.uniforms.texelSize) { + gl.uniform2f(divergenceProgram.uniforms.texelSize, velocity.texelSizeX, velocity.texelSizeY); + } + if (divergenceProgram.uniforms.uVelocity) { + gl.uniform1i(divergenceProgram.uniforms.uVelocity, velocity.read.attach(0)); + } + blit(divergence); + + clearProgram.bind(); + if (clearProgram.uniforms.uTexture) { + gl.uniform1i(clearProgram.uniforms.uTexture, pressure.read.attach(0)); + } + if (clearProgram.uniforms.value) { + gl.uniform1f(clearProgram.uniforms.value, config.PRESSURE); + } + blit(pressure.write); + pressure.swap(); + + pressureProgram.bind(); + if (pressureProgram.uniforms.texelSize) { + gl.uniform2f(pressureProgram.uniforms.texelSize, velocity.texelSizeX, velocity.texelSizeY); + } + if (pressureProgram.uniforms.uDivergence) { + gl.uniform1i(pressureProgram.uniforms.uDivergence, divergence.attach(0)); + } + for (let i = 0; i < config.PRESSURE_ITERATIONS; i++) { + if (pressureProgram.uniforms.uPressure) { + gl.uniform1i(pressureProgram.uniforms.uPressure, pressure.read.attach(1)); + } + blit(pressure.write); + pressure.swap(); + } + + gradienSubtractProgram.bind(); + if (gradienSubtractProgram.uniforms.texelSize) { + gl.uniform2f(gradienSubtractProgram.uniforms.texelSize, velocity.texelSizeX, velocity.texelSizeY); + } + if (gradienSubtractProgram.uniforms.uPressure) { + gl.uniform1i(gradienSubtractProgram.uniforms.uPressure, pressure.read.attach(0)); + } + if (gradienSubtractProgram.uniforms.uVelocity) { + gl.uniform1i(gradienSubtractProgram.uniforms.uVelocity, velocity.read.attach(1)); + } + blit(velocity.write); + velocity.swap(); + + advectionProgram.bind(); + if (advectionProgram.uniforms.texelSize) { + gl.uniform2f(advectionProgram.uniforms.texelSize, velocity.texelSizeX, velocity.texelSizeY); + } + if (!ext.supportLinearFiltering && advectionProgram.uniforms.dyeTexelSize) { + gl.uniform2f(advectionProgram.uniforms.dyeTexelSize, velocity.texelSizeX, velocity.texelSizeY); + } + const velocityId = velocity.read.attach(0); + if (advectionProgram.uniforms.uVelocity) { + gl.uniform1i(advectionProgram.uniforms.uVelocity, velocityId); + } + if (advectionProgram.uniforms.uSource) { + gl.uniform1i(advectionProgram.uniforms.uSource, velocityId); + } + if (advectionProgram.uniforms.dt) { + gl.uniform1f(advectionProgram.uniforms.dt, dt); + } + if (advectionProgram.uniforms.dissipation) { + gl.uniform1f(advectionProgram.uniforms.dissipation, config.VELOCITY_DISSIPATION); + } + blit(velocity.write); + velocity.swap(); + + if (!ext.supportLinearFiltering && advectionProgram.uniforms.dyeTexelSize) { + gl.uniform2f(advectionProgram.uniforms.dyeTexelSize, dye.texelSizeX, dye.texelSizeY); + } + if (advectionProgram.uniforms.uVelocity) { + gl.uniform1i(advectionProgram.uniforms.uVelocity, velocity.read.attach(0)); + } + if (advectionProgram.uniforms.uSource) { + gl.uniform1i(advectionProgram.uniforms.uSource, dye.read.attach(1)); + } + if (advectionProgram.uniforms.dissipation) { + gl.uniform1f(advectionProgram.uniforms.dissipation, config.DENSITY_DISSIPATION); + } + blit(dye.write); + dye.swap(); + } + + function render(target: FBO | null) { + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + gl.enable(gl.BLEND); + drawDisplay(target); + } + + function drawDisplay(target: FBO | null) { + const width = target ? target.width : gl.drawingBufferWidth; + const height = target ? target.height : gl.drawingBufferHeight; + displayMaterial.bind(); + if (config.SHADING && displayMaterial.uniforms.texelSize) { + gl.uniform2f(displayMaterial.uniforms.texelSize, 1 / width, 1 / height); + } + if (displayMaterial.uniforms.uTexture) { + gl.uniform1i(displayMaterial.uniforms.uTexture, dye.read.attach(0)); + } + blit(target, false); + } + + function splatPointer(pointer: Pointer) { + const dx = pointer.deltaX * config.SPLAT_FORCE; + const dy = pointer.deltaY * config.SPLAT_FORCE; + splat(pointer.texcoordX, pointer.texcoordY, dx, dy, pointer.color); + } + + function clickSplat(pointer: Pointer) { + const color = generateColor(); + color.r *= 10; + color.g *= 10; + color.b *= 10; + const dx = 10 * (Math.random() - 0.5); + const dy = 30 * (Math.random() - 0.5); + splat(pointer.texcoordX, pointer.texcoordY, dx, dy, color); + } + + function splat(x: number, y: number, dx: number, dy: number, color: ColorRGB) { + splatProgram.bind(); + if (splatProgram.uniforms.uTarget) { + gl.uniform1i(splatProgram.uniforms.uTarget, velocity.read.attach(0)); + } + if (splatProgram.uniforms.aspectRatio) { + gl.uniform1f(splatProgram.uniforms.aspectRatio, canvas!.width / canvas!.height); + } + if (splatProgram.uniforms.point) { + gl.uniform2f(splatProgram.uniforms.point, x, y); + } + if (splatProgram.uniforms.color) { + gl.uniform3f(splatProgram.uniforms.color, dx, dy, 0); + } + if (splatProgram.uniforms.radius) { + gl.uniform1f(splatProgram.uniforms.radius, correctRadius(config.SPLAT_RADIUS / 100)!); + } + blit(velocity.write); + velocity.swap(); + + if (splatProgram.uniforms.uTarget) { + gl.uniform1i(splatProgram.uniforms.uTarget, dye.read.attach(0)); + } + if (splatProgram.uniforms.color) { + gl.uniform3f(splatProgram.uniforms.color, color.r, color.g, color.b); + } + blit(dye.write); + dye.swap(); + } + + function correctRadius(radius: number) { + const aspectRatio = canvas!.width / canvas!.height; + if (aspectRatio > 1) radius *= aspectRatio; + return radius; + } + + function updatePointerDownData(pointer: Pointer, id: number, posX: number, posY: number) { + pointer.id = id; + pointer.down = true; + pointer.moved = false; + pointer.texcoordX = posX / canvas!.width; + pointer.texcoordY = 1 - posY / canvas!.height; + pointer.prevTexcoordX = pointer.texcoordX; + pointer.prevTexcoordY = pointer.texcoordY; + pointer.deltaX = 0; + pointer.deltaY = 0; + pointer.color = generateColor(); + } + + function updatePointerMoveData(pointer: Pointer, posX: number, posY: number, color: ColorRGB) { + pointer.prevTexcoordX = pointer.texcoordX; + pointer.prevTexcoordY = pointer.texcoordY; + pointer.texcoordX = posX / canvas!.width; + pointer.texcoordY = 1 - posY / canvas!.height; + pointer.deltaX = correctDeltaX(pointer.texcoordX - pointer.prevTexcoordX)!; + pointer.deltaY = correctDeltaY(pointer.texcoordY - pointer.prevTexcoordY)!; + pointer.moved = Math.abs(pointer.deltaX) > 0 || Math.abs(pointer.deltaY) > 0; + pointer.color = color; + } + + function updatePointerUpData(pointer: Pointer) { + pointer.down = false; + } + + function correctDeltaX(delta: number) { + const aspectRatio = canvas!.width / canvas!.height; + if (aspectRatio < 1) delta *= aspectRatio; + return delta; + } + + function correctDeltaY(delta: number) { + const aspectRatio = canvas!.width / canvas!.height; + if (aspectRatio > 1) delta /= aspectRatio; + return delta; + } + + function generateColor(): ColorRGB { + const c = HSVtoRGB(Math.random(), 1.0, 1.0); + c.r *= 0.15; + c.g *= 0.15; + c.b *= 0.15; + return c; + } + + function HSVtoRGB(h: number, s: number, v: number): ColorRGB { + let r = 0, + g = 0, + b = 0; + const i = Math.floor(h * 6); + const f = h * 6 - i; + const p = v * (1 - s); + const q = v * (1 - f * s); + const t = v * (1 - (1 - f) * s); + + switch (i % 6) { + case 0: + r = v; + g = t; + b = p; + break; + case 1: + r = q; + g = v; + b = p; + break; + case 2: + r = p; + g = v; + b = t; + break; + case 3: + r = p; + g = q; + b = v; + break; + case 4: + r = t; + g = p; + b = v; + break; + case 5: + r = v; + g = p; + b = q; + break; + } + return { r, g, b }; + } + + function wrap(value: number, min: number, max: number) { + const range = max - min; + if (range === 0) return min; + return ((value - min) % range) + min; + } + + window.addEventListener('mousedown', e => { + const pointer = pointers[0]; + const posX = scaleByPixelRatio(e.clientX); + const posY = scaleByPixelRatio(e.clientY); + updatePointerDownData(pointer, -1, posX, posY); + clickSplat(pointer); + }); + + function handleFirstMouseMove(e: MouseEvent) { + const pointer = pointers[0]; + const posX = scaleByPixelRatio(e.clientX); + const posY = scaleByPixelRatio(e.clientY); + const color = generateColor(); + updateFrame(); + updatePointerMoveData(pointer, posX, posY, color); + document.body.removeEventListener('mousemove', handleFirstMouseMove); + } + document.body.addEventListener('mousemove', handleFirstMouseMove); + + window.addEventListener('mousemove', e => { + const pointer = pointers[0]; + const posX = scaleByPixelRatio(e.clientX); + const posY = scaleByPixelRatio(e.clientY); + const color = pointer.color; + updatePointerMoveData(pointer, posX, posY, color); + }); + + function handleFirstTouchStart(e: TouchEvent) { + const touches = e.targetTouches; + const pointer = pointers[0]; + for (let i = 0; i < touches.length; i++) { + const posX = scaleByPixelRatio(touches[i].clientX); + const posY = scaleByPixelRatio(touches[i].clientY); + updateFrame(); + updatePointerDownData(pointer, touches[i].identifier, posX, posY); + } + document.body.removeEventListener('touchstart', handleFirstTouchStart); + } + document.body.addEventListener('touchstart', handleFirstTouchStart); + + window.addEventListener( + 'touchstart', + e => { + const touches = e.targetTouches; + const pointer = pointers[0]; + for (let i = 0; i < touches.length; i++) { + const posX = scaleByPixelRatio(touches[i].clientX); + const posY = scaleByPixelRatio(touches[i].clientY); + updatePointerDownData(pointer, touches[i].identifier, posX, posY); + } + }, + false + ); + + window.addEventListener( + 'touchmove', + e => { + const touches = e.targetTouches; + const pointer = pointers[0]; + for (let i = 0; i < touches.length; i++) { + const posX = scaleByPixelRatio(touches[i].clientX); + const posY = scaleByPixelRatio(touches[i].clientY); + updatePointerMoveData(pointer, posX, posY, pointer.color); + } + }, + false + ); + + window.addEventListener('touchend', e => { + const touches = e.changedTouches; + const pointer = pointers[0]; + for (let i = 0; i < touches.length; i++) { + updatePointerUpData(pointer); + } + }); + }, [ + SIM_RESOLUTION, + DYE_RESOLUTION, + CAPTURE_RESOLUTION, + DENSITY_DISSIPATION, + VELOCITY_DISSIPATION, + PRESSURE, + PRESSURE_ITERATIONS, + CURL, + SPLAT_RADIUS, + SPLAT_FORCE, + SHADING, + COLOR_UPDATE_SPEED, + BACK_COLOR, + TRANSPARENT + ]); + + return ( +
+ +
+ ); +} diff --git a/src/components/TargetCursor.tsx b/src/components/TargetCursor.tsx new file mode 100644 index 0000000..4d8ee3d --- /dev/null +++ b/src/components/TargetCursor.tsx @@ -0,0 +1,359 @@ +import React, { useEffect, useRef, useCallback, useMemo } from 'react'; +import { gsap } from 'gsap'; + +export interface TargetCursorProps { + targetSelector?: string; + spinDuration?: number; + hideDefaultCursor?: boolean; +} + +const TargetCursor: React.FC = ({ + targetSelector = '.cursor-target', + spinDuration = 2, + hideDefaultCursor = true +}) => { + const cursorRef = useRef(null); + const cornersRef = useRef>(null); + const spinTl = useRef(null); + const dotRef = useRef(null); + const constants = useMemo( + () => ({ + borderWidth: 3, + cornerSize: 12, + parallaxStrength: 0.00005 + }), + [] + ); + + const moveCursor = useCallback((x: number, y: number) => { + if (!cursorRef.current) return; + gsap.to(cursorRef.current, { + x, + y, + duration: 0.1, + ease: 'power3.out' + }); + }, []); + + useEffect(() => { + if (!cursorRef.current) return; + + const originalCursor = document.body.style.cursor; + if (hideDefaultCursor) { + document.body.style.cursor = 'none'; + } + + const cursor = cursorRef.current; + cornersRef.current = cursor.querySelectorAll('.target-cursor-corner'); + + let activeTarget: Element | null = null; + let currentTargetMove: ((ev: Event) => void) | null = null; + let currentLeaveHandler: (() => void) | null = null; + let isAnimatingToTarget = false; + let resumeTimeout: ReturnType | null = null; + + const cleanupTarget = (target: Element) => { + if (currentTargetMove) { + target.removeEventListener('mousemove', currentTargetMove); + } + if (currentLeaveHandler) { + target.removeEventListener('mouseleave', currentLeaveHandler); + } + currentTargetMove = null; + currentLeaveHandler = null; + }; + + gsap.set(cursor, { + xPercent: -50, + yPercent: -50, + x: window.innerWidth / 2, + y: window.innerHeight / 2 + }); + + const createSpinTimeline = () => { + if (spinTl.current) { + spinTl.current.kill(); + } + spinTl.current = gsap + .timeline({ repeat: -1 }) + .to(cursor, { rotation: '+=360', duration: spinDuration, ease: 'none' }); + }; + + createSpinTimeline(); + + const moveHandler = (e: MouseEvent) => moveCursor(e.clientX, e.clientY); + window.addEventListener('mousemove', moveHandler); + + const scrollHandler = () => { + if (!activeTarget || !cursorRef.current) return; + + const mouseX = gsap.getProperty(cursorRef.current, 'x') as number; + const mouseY = gsap.getProperty(cursorRef.current, 'y') as number; + + const elementUnderMouse = document.elementFromPoint(mouseX, mouseY); + const isStillOverTarget = + elementUnderMouse && + (elementUnderMouse === activeTarget || elementUnderMouse.closest(targetSelector) === activeTarget); + + if (!isStillOverTarget) { + if (currentLeaveHandler) { + currentLeaveHandler(); + } + } + }; + + window.addEventListener('scroll', scrollHandler, { passive: true }); + window.addEventListener('mousemove', moveHandler); + + const mouseDownHandler = (): void => { + if (!dotRef.current) return; + gsap.to(dotRef.current, { scale: 0.7, duration: 0.3 }); + gsap.to(cursorRef.current, { scale: 0.9, duration: 0.2 }); + }; + + const mouseUpHandler = (): void => { + if (!dotRef.current) return; + gsap.to(dotRef.current, { scale: 1, duration: 0.3 }); + gsap.to(cursorRef.current, { scale: 1, duration: 0.2 }); + }; + + window.addEventListener('mousedown', mouseDownHandler); + window.addEventListener('mouseup', mouseUpHandler); + + const enterHandler = (e: MouseEvent) => { + const directTarget = e.target as Element; + + const allTargets: Element[] = []; + let current = directTarget; + while (current && current !== document.body) { + if (current.matches(targetSelector)) { + allTargets.push(current); + } + current = current.parentElement!; + } + + const target = allTargets[0] || null; + if (!target || !cursorRef.current || !cornersRef.current) return; + + if (activeTarget === target) return; + + if (activeTarget) { + cleanupTarget(activeTarget); + } + + if (resumeTimeout) { + clearTimeout(resumeTimeout); + resumeTimeout = null; + } + + activeTarget = target; + const corners = Array.from(cornersRef.current); + corners.forEach(corner => { + gsap.killTweensOf(corner); + }); + gsap.killTweensOf(cursorRef.current, 'rotation'); + spinTl.current?.pause(); + + gsap.set(cursorRef.current, { rotation: 0 }); + + const updateCorners = (mouseX?: number, mouseY?: number) => { + const rect = target.getBoundingClientRect(); + const cursorRect = cursorRef.current!.getBoundingClientRect(); + + const cursorCenterX = cursorRect.left + cursorRect.width / 2; + const cursorCenterY = cursorRect.top + cursorRect.height / 2; + + const [tlc, trc, brc, blc] = Array.from(cornersRef.current!); + + const { borderWidth, cornerSize, parallaxStrength } = constants; + + let tlOffset = { + x: rect.left - cursorCenterX - borderWidth, + y: rect.top - cursorCenterY - borderWidth + }; + let trOffset = { + x: rect.right - cursorCenterX + borderWidth - cornerSize, + y: rect.top - cursorCenterY - borderWidth + }; + let brOffset = { + x: rect.right - cursorCenterX + borderWidth - cornerSize, + y: rect.bottom - cursorCenterY + borderWidth - cornerSize + }; + let blOffset = { + x: rect.left - cursorCenterX - borderWidth, + y: rect.bottom - cursorCenterY + borderWidth - cornerSize + }; + + if (mouseX !== undefined && mouseY !== undefined) { + const targetCenterX = rect.left + rect.width / 2; + const targetCenterY = rect.top + rect.height / 2; + const mouseOffsetX = (mouseX - targetCenterX) * parallaxStrength; + const mouseOffsetY = (mouseY - targetCenterY) * parallaxStrength; + + tlOffset.x += mouseOffsetX; + tlOffset.y += mouseOffsetY; + trOffset.x += mouseOffsetX; + trOffset.y += mouseOffsetY; + brOffset.x += mouseOffsetX; + brOffset.y += mouseOffsetY; + blOffset.x += mouseOffsetX; + blOffset.y += mouseOffsetY; + } + + const tl = gsap.timeline(); + const corners = [tlc, trc, brc, blc]; + const offsets = [tlOffset, trOffset, brOffset, blOffset]; + + corners.forEach((corner, index) => { + tl.to( + corner, + { + x: offsets[index].x, + y: offsets[index].y, + duration: 0.2, + ease: 'power2.out' + }, + 0 + ); + }); + }; + + isAnimatingToTarget = true; + updateCorners(); + + setTimeout(() => { + isAnimatingToTarget = false; + }, 1); + + let moveThrottle: number | null = null; + const targetMove = (ev: Event) => { + if (moveThrottle || isAnimatingToTarget) return; + moveThrottle = requestAnimationFrame(() => { + const mouseEvent = ev as MouseEvent; + updateCorners(mouseEvent.clientX, mouseEvent.clientY); + moveThrottle = null; + }); + }; + + const leaveHandler = () => { + activeTarget = null; + isAnimatingToTarget = false; + + if (cornersRef.current) { + const corners = Array.from(cornersRef.current); + gsap.killTweensOf(corners); + + const { cornerSize } = constants; + const positions = [ + { x: -cornerSize * 1.5, y: -cornerSize * 1.5 }, + { x: cornerSize * 0.5, y: -cornerSize * 1.5 }, + { x: cornerSize * 0.5, y: cornerSize * 0.5 }, + { x: -cornerSize * 1.5, y: cornerSize * 0.5 } + ]; + + const tl = gsap.timeline(); + corners.forEach((corner, index) => { + tl.to( + corner, + { + x: positions[index].x, + y: positions[index].y, + duration: 0.3, + ease: 'power3.out' + }, + 0 + ); + }); + } + + resumeTimeout = setTimeout(() => { + if (!activeTarget && cursorRef.current && spinTl.current) { + const currentRotation = gsap.getProperty(cursorRef.current, 'rotation') as number; + const normalizedRotation = currentRotation % 360; + + spinTl.current.kill(); + spinTl.current = gsap + .timeline({ repeat: -1 }) + .to(cursorRef.current, { rotation: '+=360', duration: spinDuration, ease: 'none' }); + + gsap.to(cursorRef.current, { + rotation: normalizedRotation + 360, + duration: spinDuration * (1 - normalizedRotation / 360), + ease: 'none', + onComplete: () => { + spinTl.current?.restart(); + } + }); + } + resumeTimeout = null; + }, 50); + + cleanupTarget(target); + }; + + currentTargetMove = targetMove; + currentLeaveHandler = leaveHandler; + + target.addEventListener('mousemove', targetMove); + target.addEventListener('mouseleave', leaveHandler); + }; + + window.addEventListener('mouseover', enterHandler, { passive: true }); + + return () => { + window.removeEventListener('mousemove', moveHandler); + window.removeEventListener('mouseover', enterHandler); + window.removeEventListener('scroll', scrollHandler); + + if (activeTarget) { + cleanupTarget(activeTarget); + } + + spinTl.current?.kill(); + document.body.style.cursor = originalCursor; + }; + }, [targetSelector, spinDuration, moveCursor, constants, hideDefaultCursor]); + + useEffect(() => { + if (!cursorRef.current || !spinTl.current) return; + + if (spinTl.current.isActive()) { + spinTl.current.kill(); + spinTl.current = gsap + .timeline({ repeat: -1 }) + .to(cursorRef.current, { rotation: '+=360', duration: spinDuration, ease: 'none' }); + } + }, [spinDuration]); + + return ( +
+
+
+
+
+
+
+ ); +}; + +export default TargetCursor; From e04bede7bcefed2f2316d558ccb8a4528ceb764d Mon Sep 17 00:00:00 2001 From: maamokun Date: Tue, 28 Oct 2025 14:35:15 +0900 Subject: [PATCH 07/10] feat: Cursor Toys! --- .idea/copilotDiffState.xml | 17 + bun.lock | 249 ++++++- components.json | 4 +- package.json | 11 +- src/app/[locale]/layout.tsx | 16 +- src/app/[locale]/page.tsx | 4 +- src/app/[locale]/template.tsx | 9 +- src/app/globals.css | 12 - src/app/layout.tsx | 20 +- src/components/ClickSpark.tsx | 38 +- src/components/CursorToys.tsx | 26 + src/components/CustomCursor.tsx | 35 + src/components/FluidGlass.tsx | 385 ++++++++++ src/components/GlobalCursorToys.tsx | 13 + src/components/SettingsController.tsx | 99 +++ src/components/SplashCursor.tsx | 445 +++++++++--- src/components/TargetCursor.tsx | 120 ++-- .../animate-ui/components/buttons/button.tsx | 57 ++ src/components/animate-ui/icons/icon.tsx | 658 ++++++++++++++++++ src/components/animate-ui/icons/settings.tsx | 97 +++ .../animate-ui/primitives/animate/slot.tsx | 97 +++ .../animate-ui/primitives/buttons/button.tsx | 35 + .../primitives/radix/radio-group.tsx | 130 ++++ src/{app => components}/consent-manager.tsx | 0 src/contexts/CursorToysContext.tsx | 44 ++ src/hooks/use-controlled-state.tsx | 33 + src/hooks/use-is-in-view.tsx | 25 + src/interfaces/CursorToys.ts | 6 + src/lib/get-strict-context.tsx | 36 + tsconfig.json | 10 +- 30 files changed, 2488 insertions(+), 243 deletions(-) create mode 100644 .idea/copilotDiffState.xml create mode 100644 src/components/CursorToys.tsx create mode 100644 src/components/CustomCursor.tsx create mode 100644 src/components/FluidGlass.tsx create mode 100644 src/components/GlobalCursorToys.tsx create mode 100644 src/components/SettingsController.tsx create mode 100644 src/components/animate-ui/components/buttons/button.tsx create mode 100644 src/components/animate-ui/icons/icon.tsx create mode 100644 src/components/animate-ui/icons/settings.tsx create mode 100644 src/components/animate-ui/primitives/animate/slot.tsx create mode 100644 src/components/animate-ui/primitives/buttons/button.tsx create mode 100644 src/components/animate-ui/primitives/radix/radio-group.tsx rename src/{app => components}/consent-manager.tsx (100%) create mode 100644 src/contexts/CursorToysContext.tsx create mode 100644 src/hooks/use-controlled-state.tsx create mode 100644 src/hooks/use-is-in-view.tsx create mode 100644 src/interfaces/CursorToys.ts create mode 100644 src/lib/get-strict-context.tsx diff --git a/.idea/copilotDiffState.xml b/.idea/copilotDiffState.xml new file mode 100644 index 0000000..66475ce --- /dev/null +++ b/.idea/copilotDiffState.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/bun.lock b/bun.lock index 64a53d9..018ab31 100644 --- a/bun.lock +++ b/bun.lock @@ -9,7 +9,8 @@ "@pixiv/three-vrm": "^3.3.4", "@pixiv/three-vrm-animation": "^3.3.4", "@radix-ui/react-slot": "^1.2.3", - "@react-three/fiber": "^9.1.2", + "@react-three/drei": "^10.7.6", + "@react-three/fiber": "^9.4.0", "@swetrix/nextjs": "^1.0.1", "@tailwindcss/postcss": "^4.1.7", "@types/three": "^0.176.0", @@ -20,11 +21,13 @@ "daisyui": "^5.0.0", "gsap": "^3.13.0", "lucide-react": "^0.548.0", - "motion": "^11.15.0", + "maath": "^0.10.8", + "motion": "^12.23.24", "next": "^16.0.0", "next-intl": "^4.4.0", "next-themes": "^0.4.4", "postcss": "^8.5.3", + "radix-ui": "^1.4.3", "react": "^19.2.0", "react-dom": "^19.2.0", "react-icons": "^5.2.1", @@ -35,13 +38,13 @@ "tailwind-merge": "^3.3.1", "tailwind-variants": "^0.3.0", "tailwindcss-animate": "^1.0.7", - "three": "^0.176.0", + "three": "^0.180.0", "tw-animate-css": "^1.4.0", }, "devDependencies": { "@biomejs/biome": "^2.3.1", "@types/node": "^20", - "@types/react": "^18", + "@types/react": "^19.2.2", "@types/react-dom": "^18", "tailwindcss": "^4.1.7", "typescript": "^5", @@ -97,6 +100,14 @@ "@emnapi/runtime": ["@emnapi/runtime@1.6.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA=="], + "@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="], + + "@floating-ui/dom": ["@floating-ui/dom@1.7.4", "", { "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" } }, "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA=="], + + "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.6", "", { "dependencies": { "@floating-ui/dom": "^1.7.4" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw=="], + + "@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="], + "@formatjs/ecma402-abstract": ["@formatjs/ecma402-abstract@2.3.6", "", { "dependencies": { "@formatjs/fast-memoize": "2.2.7", "@formatjs/intl-localematcher": "0.6.2", "decimal.js": "^10.4.3", "tslib": "^2.8.0" } }, "sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw=="], "@formatjs/fast-memoize": ["@formatjs/fast-memoize@2.2.7", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ=="], @@ -171,6 +182,10 @@ "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], + "@mediapipe/tasks-vision": ["@mediapipe/tasks-vision@0.10.17", "", {}, "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg=="], + + "@monogrid/gainmap-js": ["@monogrid/gainmap-js@3.1.0", "", { "dependencies": { "promise-worker-transferable": "^1.0.4" }, "peerDependencies": { "three": ">= 0.159.0" } }, "sha512-Obb0/gEd/HReTlg8ttaYk+0m62gQJmCblMOjHSMHRrBP2zdfKMHLCRbh/6ex9fSUJMKdjjIEiohwkbGD3wj2Nw=="], + "@next/env": ["@next/env@16.0.0", "", {}, "sha512-s5j2iFGp38QsG1LWRQaE2iUY3h1jc014/melHFfLdrsMJPqxqDQwWNwyQTcNoUSGZlCVZuM7t7JDMmSyRilsnA=="], "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.0.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/CntqDCnk5w2qIwMiF0a9r6+9qunZzFmU0cBX4T82LOflE72zzH6gnOjCwUXYKOBlQi8OpP/rMj8cBIr18x4TA=="], @@ -333,40 +348,128 @@ "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], - "@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="], + "@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="], + + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], + + "@radix-ui/react-accessible-icon": ["@radix-ui/react-accessible-icon@1.1.7", "", { "dependencies": { "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A=="], + + "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="], + + "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="], + + "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="], + + "@radix-ui/react-aspect-ratio": ["@radix-ui/react-aspect-ratio@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g=="], + + "@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="], - "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.4", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collapsible": "1.1.4", "@radix-ui/react-collection": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.0.3", "@radix-ui/react-use-controllable-state": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-SGCxlSBaMvEzDROzyZjsVNzu9XY5E28B3k8jOENyrz6csOv/pG1eHyYfLJai1n9tRjwG61coXDhfpgtxKxUv5g=="], + "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="], - "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.4", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.3", "@radix-ui/react-primitive": "2.0.3", "@radix-ui/react-use-controllable-state": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-u7LCw1EYInQtBNLGjm9nZ89S/4GcvX1UR5XbekEgnQae2Hkpq39ycJ1OhdeN1/JDfVNG91kWaWoest127TaEKQ=="], + "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="], - "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.0.3", "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-mM2pxoQw5HJ49rkzwOs7Y6J4oYH22wS8BfK2/bBxROlI4xuR0c4jEenQP63LlTlDkO6Buj2Vt+QYAYcOgqtrXA=="], + "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="], "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="], "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], + "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww=="], + + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="], + "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="], + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="], + + "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw=="], + + "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="], + + "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="], + + "@radix-ui/react-form": ["@radix-ui/react-form@0.1.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ=="], + + "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg=="], + "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], - "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IrVLIhskYhH3nLvtcBLQFZr61tBG7wx7O3kEmdzcYwRGAEBmBicGGL7ATzNgruYJ3xBTbuzEEq9OXJM3PAX3tA=="], + "@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="], + + "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="], + + "@radix-ui/react-menubar": ["@radix-ui/react-menubar@1.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA=="], + + "@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w=="], + + "@radix-ui/react-one-time-password-field": ["@radix-ui/react-one-time-password-field@0.1.8", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg=="], + + "@radix-ui/react-password-toggle-field": ["@radix-ui/react-password-toggle-field@0.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw=="], - "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Pf/t/GkndH7CQ8wE2hbkXA+WyZ83fhQQn5DDmwDiDo6AwN/fhaH8oqZ0jRjMrO2iaMhDi6P1HRx6AZwyMinY1g=="], + "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="], + + "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="], + + "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="], + + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="], + + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], + + "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.7", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="], + + "@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="], + + "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="], + + "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="], + + "@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="], + + "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="], + + "@radix-ui/react-slider": ["@radix-ui/react-slider@1.3.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw=="], "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], - "@radix-ui/react-switch": ["@radix-ui/react-switch@1.1.4", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.0.3", "@radix-ui/react-use-controllable-state": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zGP6W8plLeogoeGMiTHJ/uvf+TE1C2chVsEwfP8YlvpQKJHktG+iCkUtCLGPAuDV8/qDSmIRPm4NggaTxFMVBQ=="], + "@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="], + + "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="], + + "@radix-ui/react-toast": ["@radix-ui/react-toast@1.2.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g=="], + + "@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ=="], + + "@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q=="], + + "@radix-ui/react-toolbar": ["@radix-ui/react-toolbar@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-toggle-group": "1.1.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg=="], + + "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="], "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], - "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-YnEXIy8/ga01Y1PN0VfaNH//MhA91JlEGVBDxDzROqwrAtG5Yr2QGEPz8A/rJA3C7ZAHryOYGaUv8fLSW2H/mg=="], + "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="], + + "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="], + + "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="], + + "@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.0", "", { "dependencies": { "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA=="], "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="], + "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.1", "", { "dependencies": { "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w=="], + "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="], + "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.3", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="], + + "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], + + "@react-three/drei": ["@react-three/drei@10.7.6", "", { "dependencies": { "@babel/runtime": "^7.26.0", "@mediapipe/tasks-vision": "0.10.17", "@monogrid/gainmap-js": "^3.0.6", "@use-gesture/react": "^10.3.1", "camera-controls": "^3.1.0", "cross-env": "^7.0.3", "detect-gpu": "^5.0.56", "glsl-noise": "^0.0.0", "hls.js": "^1.5.17", "maath": "^0.10.8", "meshline": "^3.3.1", "stats-gl": "^2.2.8", "stats.js": "^0.17.0", "suspend-react": "^0.1.3", "three-mesh-bvh": "^0.8.3", "three-stdlib": "^2.35.6", "troika-three-text": "^0.52.4", "tunnel-rat": "^0.1.2", "use-sync-external-store": "^1.4.0", "utility-types": "^3.11.0", "zustand": "^5.0.1" }, "peerDependencies": { "@react-three/fiber": "^9.0.0", "react": "^19", "react-dom": "^19", "three": ">=0.159" }, "optionalPeers": ["react-dom"] }, "sha512-ZSFwRlRaa4zjtB7yHO6Q9xQGuyDCzE7whXBhum92JslcMRC3aouivp0rAzszcVymIoJx6PXmibyP+xr+zKdwLg=="], + "@react-three/fiber": ["@react-three/fiber@9.4.0", "", { "dependencies": { "@babel/runtime": "^7.17.8", "@types/react-reconciler": "^0.32.0", "@types/webxr": "*", "base64-js": "^1.5.1", "buffer": "^6.0.3", "its-fine": "^2.0.0", "react-reconciler": "^0.31.0", "react-use-measure": "^2.1.7", "scheduler": "^0.25.0", "suspend-react": "^0.1.3", "use-sync-external-store": "^1.4.0", "zustand": "^5.0.3" }, "peerDependencies": { "expo": ">=43.0", "expo-asset": ">=8.4", "expo-file-system": ">=11.0", "expo-gl": ">=11.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-native": ">=0.78", "three": ">=0.156" }, "optionalPeers": ["expo", "expo-asset", "expo-file-system", "expo-gl", "react-dom", "react-native"] }, "sha512-k4iu1R6e5D54918V4sqmISUkI5OgTw3v7/sDRKEC632Wd5g2WBtUS5gyG63X0GJO/HZUj1tsjSXfyzwrUHZl1g=="], "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.52.5", "", { "os": "linux", "cpu": "x64" }, "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q=="], @@ -427,6 +530,8 @@ "@tweenjs/tween.js": ["@tweenjs/tween.js@23.1.3", "", {}, "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA=="], + "@types/draco3d": ["@types/draco3d@1.4.10", "", {}, "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw=="], + "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], "@types/js-cookie": ["@types/js-cookie@2.2.7", "", {}, "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA=="], @@ -435,9 +540,9 @@ "@types/node": ["@types/node@20.19.23", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-yIdlVVVHXpmqRhtyovZAcSy0MiPcYWGkoO4CGe/+jpP0hmNuihm4XhHbADpK++MsiLHP5MVlv+bcgdF99kSiFQ=="], - "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="], + "@types/offscreencanvas": ["@types/offscreencanvas@2019.7.3", "", {}, "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A=="], - "@types/react": ["@types/react@18.3.26", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA=="], + "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], "@types/react-dom": ["@types/react-dom@18.3.7", "", { "peerDependencies": { "@types/react": "^18.0.0" } }, "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ=="], @@ -453,6 +558,10 @@ "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], + "@use-gesture/core": ["@use-gesture/core@10.3.1", "", {}, "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw=="], + + "@use-gesture/react": ["@use-gesture/react@10.3.1", "", { "dependencies": { "@use-gesture/core": "10.3.1" }, "peerDependencies": { "react": ">= 16.8.0" } }, "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g=="], + "@webgpu/types": ["@webgpu/types@0.1.66", "", {}, "sha512-YA2hLrwLpDsRueNDXIMqN9NTzD6bCDkuXbOSe0heS+f8YE8usA6Gbv1prj81pzVHrbaAma7zObnIC+I6/sXJgA=="], "@xobotyi/scrollbar-width": ["@xobotyi/scrollbar-width@1.9.5", "", {}, "sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ=="], @@ -469,6 +578,8 @@ "app-root-path": ["app-root-path@3.1.0", "", {}, "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA=="], + "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], + "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], "babel-plugin-react-compiler": ["babel-plugin-react-compiler@1.0.0", "", { "dependencies": { "@babel/types": "^7.26.0" } }, "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw=="], @@ -479,6 +590,8 @@ "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + "bidi-js": ["bidi-js@1.0.3", "", { "dependencies": { "require-from-string": "^2.0.2" } }, "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw=="], + "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], @@ -491,6 +604,8 @@ "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + "camera-controls": ["camera-controls@3.1.1", "", { "peerDependencies": { "three": ">=0.126.1" } }, "sha512-zC3DcoQPJ0CbTZ8WHthzi8nMvVF71cppOTBcH4cMLreMkU3y3fzBPViGvz1BefWPo9+kv9BP41tvIsabsXTz+Q=="], + "caniuse-lite": ["caniuse-lite@1.0.30001751", "", {}, "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], @@ -529,6 +644,8 @@ "copy-to-clipboard": ["copy-to-clipboard@3.3.3", "", { "dependencies": { "toggle-selection": "^1.0.6" } }, "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA=="], + "cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="], + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "css-in-js-utils": ["css-in-js-utils@3.1.0", "", { "dependencies": { "hyphenate-style-name": "^1.0.3" } }, "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A=="], @@ -553,12 +670,18 @@ "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], + "detect-gpu": ["detect-gpu@5.0.70", "", { "dependencies": { "webgl-constants": "^1.1.1" } }, "sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w=="], + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], + "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], + "draco3d": ["draco3d@1.5.7", "", {}, "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ=="], + "drizzle-orm": ["drizzle-orm@0.44.7", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-quIpnYznjU9lHshEOAYLoZ9s3jweleHlZIAWR/jX9gAWNg/JhQ1wj0KGRf7/Zm+obRrYd9GjPVJg790QY9N5AQ=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], @@ -595,7 +718,7 @@ "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - "framer-motion": ["framer-motion@11.18.2", "", { "dependencies": { "motion-dom": "^11.18.1", "motion-utils": "^11.18.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w=="], + "framer-motion": ["framer-motion@12.23.24", "", { "dependencies": { "motion-dom": "^12.23.23", "motion-utils": "^12.23.6", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w=="], "fumadb": ["fumadb@0.1.1", "", { "dependencies": { "@clack/prompts": "^0.11.0", "@paralleldrive/cuid2": "^2.2.2", "commander": "^14.0.0", "kysely": "^0.28.3", "kysely-typeorm": "^0.3.0", "semver": "^7.7.2", "zod": "^4.0.5" }, "peerDependencies": { "convex": "^1.25.0", "drizzle-orm": "^0.44.0", "mongodb": "6.x.x", "prisma": "6.x.x", "typeorm": "0.x.x" }, "optionalPeers": ["convex", "drizzle-orm", "mongodb", "prisma", "typeorm"] }, "sha512-p2+qTHEP+8J+hyCmDXQIib1eXNvr3pIIqRcbKkbYEgN/upBOPr6/kfgYCLipdXie73ryYWubom+kWgL010zwkQ=="], @@ -605,10 +728,14 @@ "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], "glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], + "glsl-noise": ["glsl-noise@0.0.0", "", {}, "sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w=="], + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], @@ -627,12 +754,16 @@ "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="], + "hls.js": ["hls.js@1.6.13", "", {}, "sha512-hNEzjZNHf5bFrUNvdS4/1RjIanuJ6szpWNfTaX5I6WfGynWXGT7K/YQLYtemSvFExzeMdgdE4SsyVLJbd5PcZA=="], + "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="], "hyphenate-style-name": ["hyphenate-style-name@1.1.0", "", {}, "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw=="], "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="], + "import-in-the-middle": ["import-in-the-middle@1.15.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^1.2.2", "module-details-from-path": "^1.0.3" } }, "sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA=="], "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], @@ -649,6 +780,8 @@ "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "is-promise": ["is-promise@2.2.2", "", {}, "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="], + "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], "is-what": ["is-what@5.5.0", "", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="], @@ -669,6 +802,8 @@ "kysely-typeorm": ["kysely-typeorm@0.3.0", "", { "peerDependencies": { "kysely": ">= 0.24.0 < 1", "typeorm": ">= 0.3.0 < 0.4.0" } }, "sha512-xQDx6+HagVmtXeuYd3Sz2CPYc/jOo7JO1ALldYPdwRrbiwSs9GFyNPp5JbElkfZB+T4DRb+A53pKWKYjlgSFeA=="], + "lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="], + "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="], @@ -701,6 +836,8 @@ "lucide-react": ["lucide-react@0.548.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-63b16z63jM9yc1MwxajHeuu0FRZFsDtljtDjYm26Kd86UQ5HQzu9ksEtoUUw4RBuewodw/tGFmvipePvRsKeDA=="], + "maath": ["maath@0.10.8", "", { "peerDependencies": { "@types/three": ">=0.134.0", "three": ">=0.134.0" } }, "sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g=="], + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], @@ -709,6 +846,8 @@ "mdn-data": ["mdn-data@2.0.14", "", {}, "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="], + "meshline": ["meshline@3.3.1", "", { "peerDependencies": { "three": ">=0.137" } }, "sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ=="], + "meshoptimizer": ["meshoptimizer@0.18.1", "", {}, "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw=="], "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="], @@ -727,11 +866,11 @@ "module-details-from-path": ["module-details-from-path@1.0.4", "", {}, "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w=="], - "motion": ["motion@11.18.2", "", { "dependencies": { "framer-motion": "^11.18.2", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-JLjvFDuFr42NFtcVoMAyC2sEjnpA8xpy6qWPyzQvCloznAyQ8FIXioxWfHiLtgYhoVpfUqSWpn1h9++skj9+Wg=="], + "motion": ["motion@12.23.24", "", { "dependencies": { "framer-motion": "^12.23.24", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-Rc5E7oe2YZ72N//S3QXGzbnXgqNrTESv8KKxABR20q2FLch9gHLo0JLyYo2hZ238bZ9Gx6cWhj9VO0IgwbMjCw=="], - "motion-dom": ["motion-dom@11.18.1", "", { "dependencies": { "motion-utils": "^11.18.1" } }, "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw=="], + "motion-dom": ["motion-dom@12.23.23", "", { "dependencies": { "motion-utils": "^12.23.6" } }, "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA=="], - "motion-utils": ["motion-utils@11.18.1", "", {}, "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA=="], + "motion-utils": ["motion-utils@12.23.6", "", {}, "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], @@ -767,12 +906,18 @@ "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + "potpack": ["potpack@1.0.2", "", {}, "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ=="], + + "promise-worker-transferable": ["promise-worker-transferable@1.0.4", "", { "dependencies": { "is-promise": "^2.1.0", "lie": "^3.0.2" } }, "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw=="], + "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], "protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="], "radash": ["radash@12.1.1", "", {}, "sha512-h36JMxKRqrAxVD8201FrCpyeNuUY9Y5zZwujr20fFO77tpUtGa6EZzfKw/3WaiBX95fq7+MpsuMLNdSnORAwSA=="], + "radix-ui": ["radix-ui@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-accessible-icon": "1.1.7", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-aspect-ratio": "1.1.7", "@radix-ui/react-avatar": "1.1.10", "@radix-ui/react-checkbox": "1.3.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-context-menu": "2.2.16", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-form": "0.1.8", "@radix-ui/react-hover-card": "1.1.15", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-menubar": "1.1.16", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-one-time-password-field": "0.1.8", "@radix-ui/react-password-toggle-field": "0.1.3", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-progress": "1.1.7", "@radix-ui/react-radio-group": "1.3.8", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-toolbar": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-escape-keydown": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="], + "react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="], "react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="], @@ -781,6 +926,12 @@ "react-reconciler": ["react-reconciler@0.31.0", "", { "dependencies": { "scheduler": "^0.25.0" }, "peerDependencies": { "react": "^19.0.0" } }, "sha512-7Ob7Z+URmesIsIVRjnLoDGwBEG/tVitidU0nMsqX/eeJaLY89RISO/10ERe0MqmzuKUUB1rmY+h1itMbUHg9BQ=="], + "react-remove-scroll": ["react-remove-scroll@2.7.1", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA=="], + + "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], + + "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], + "react-universal-interface": ["react-universal-interface@0.6.2", "", { "peerDependencies": { "react": "*", "tslib": "*" } }, "sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw=="], "react-use": ["react-use@17.6.0", "", { "dependencies": { "@types/js-cookie": "^2.2.6", "@xobotyi/scrollbar-width": "^1.9.5", "copy-to-clipboard": "^3.3.1", "fast-deep-equal": "^3.1.3", "fast-shallow-equal": "^1.0.0", "js-cookie": "^2.2.1", "nano-css": "^5.6.2", "react-universal-interface": "^0.6.2", "resize-observer-polyfill": "^1.5.1", "screenfull": "^5.1.0", "set-harmonic-interval": "^1.0.1", "throttle-debounce": "^3.0.1", "ts-easing": "^0.2.0", "tslib": "^2.1.0" }, "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-OmedEScUMKFfzn1Ir8dBxiLLSOzhKe/dPZwVxcujweSj45aNM7BEGPb9BEVIgVEqEXx6f3/TsXzwIktNgUR02g=="], @@ -797,6 +948,8 @@ "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + "require-in-the-middle": ["require-in-the-middle@7.5.2", "", { "dependencies": { "debug": "^4.3.5", "module-details-from-path": "^1.0.3", "resolve": "^1.22.8" } }, "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ=="], "resize-observer-polyfill": ["resize-observer-polyfill@1.5.1", "", {}, "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="], @@ -853,6 +1006,10 @@ "stacktrace-js": ["stacktrace-js@2.0.2", "", { "dependencies": { "error-stack-parser": "^2.0.6", "stack-generator": "^2.0.5", "stacktrace-gps": "^3.0.4" } }, "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg=="], + "stats-gl": ["stats-gl@2.4.2", "", { "dependencies": { "@types/three": "*", "three": "^0.170.0" } }, "sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ=="], + + "stats.js": ["stats.js@0.17.0", "", {}, "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw=="], + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], @@ -887,7 +1044,11 @@ "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], - "three": ["three@0.176.0", "", {}, "sha512-PWRKYWQo23ojf9oZSlRGH8K09q7nRSWx6LY/HF/UUrMdYgN9i1e2OwJYHoQjwc6HF/4lvvYLC5YC1X8UJL2ZpA=="], + "three": ["three@0.180.0", "", {}, "sha512-o+qycAMZrh+TsE01GqWUxUIKR1AL0S8pq7zDkYOQw8GqfX8b8VoCKYUoHbhiX5j+7hr8XsuHDVU6+gkQJQKg9w=="], + + "three-mesh-bvh": ["three-mesh-bvh@0.8.3", "", { "peerDependencies": { "three": ">= 0.159.0" } }, "sha512-4G5lBaF+g2auKX3P0yqx+MJC6oVt6sB5k+CchS6Ob0qvH0YIhuUk1eYr7ktsIpY+albCqE80/FVQGV190PmiAg=="], + + "three-stdlib": ["three-stdlib@2.36.0", "", { "dependencies": { "@types/draco3d": "^1.4.0", "@types/offscreencanvas": "^2019.6.4", "@types/webxr": "^0.5.2", "draco3d": "^1.4.1", "fflate": "^0.6.9", "potpack": "^1.0.1" }, "peerDependencies": { "three": ">=0.128.0" } }, "sha512-kv0Byb++AXztEGsULgMAs8U2jgUdz6HPpAB/wDJnLiLlaWQX2APHhiTJIN7rqW+Of0eRgcp7jn05U1BsCP3xBA=="], "throttle-debounce": ["throttle-debounce@3.0.1", "", {}, "sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg=="], @@ -897,10 +1058,18 @@ "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], + "troika-three-text": ["troika-three-text@0.52.4", "", { "dependencies": { "bidi-js": "^1.0.2", "troika-three-utils": "^0.52.4", "troika-worker-utils": "^0.52.0", "webgl-sdf-generator": "1.1.1" }, "peerDependencies": { "three": ">=0.125.0" } }, "sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg=="], + + "troika-three-utils": ["troika-three-utils@0.52.4", "", { "peerDependencies": { "three": ">=0.125.0" } }, "sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A=="], + + "troika-worker-utils": ["troika-worker-utils@0.52.0", "", {}, "sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw=="], + "ts-easing": ["ts-easing@0.2.0", "", {}, "sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "tunnel-rat": ["tunnel-rat@0.1.2", "", { "dependencies": { "zustand": "^4.3.2" } }, "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ=="], + "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="], "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], @@ -923,16 +1092,26 @@ "unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="], + "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], + "use-intl": ["use-intl@4.4.0", "", { "dependencies": { "@formatjs/fast-memoize": "^2.2.0", "@schummar/icu-type-parser": "1.21.5", "intl-messageformat": "^10.5.14" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" } }, "sha512-smFekJWtokDRBLC5/ZumlBREzdXOkw06+56Ifj2uRe9266Mk+yWQm2PcJO+EwlOE5sHIXHixOTzN6V8E0RGUbw=="], + "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], + "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="], + "utility-types": ["utility-types@3.11.0", "", {}, "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw=="], + "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], + "webgl-constants": ["webgl-constants@1.1.1", "", {}, "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg=="], + + "webgl-sdf-generator": ["webgl-sdf-generator@1.1.1", "", {}, "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA=="], + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], @@ -957,8 +1136,12 @@ "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], + "@c15t/react/@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.4", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collapsible": "1.1.4", "@radix-ui/react-collection": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.0.3", "@radix-ui/react-use-controllable-state": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-SGCxlSBaMvEzDROzyZjsVNzu9XY5E28B3k8jOENyrz6csOv/pG1eHyYfLJai1n9tRjwG61coXDhfpgtxKxUv5g=="], + "@c15t/react/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + "@c15t/react/@radix-ui/react-switch": ["@radix-ui/react-switch@1.1.4", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.0.3", "@radix-ui/react-use-controllable-state": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zGP6W8plLeogoeGMiTHJ/uvf+TE1C2chVsEwfP8YlvpQKJHktG+iCkUtCLGPAuDV8/qDSmIRPm4NggaTxFMVBQ=="], + "@formatjs/ecma402-abstract/@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.6.2", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA=="], "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], @@ -1053,10 +1236,6 @@ "@pixiv/types-vrmc-vrm-animation-1.0/@pixiv/types-vrmc-vrm-1.0": ["@pixiv/types-vrmc-vrm-1.0@2.0.3", "", {}, "sha512-RMP34Bk1qLFQv/CRB1Zqvn2qMFfWQfP2Hms5QrrfoBsW9XroZdEe0zPLNbGmUPYh4F7VtBb+B7+RCuymRtpehA=="], - "@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], - - "@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.6.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-zq/ay+9fNIJJtJiZxdTnXS20PllcYMX3OE23ESc4HK/bdYu3cOWYVhsOhVnXALfU/uqJIxn5NBPd9z4v+SfoSg=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.6.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA=="], @@ -1081,10 +1260,32 @@ "stacktrace-gps/source-map": ["source-map@0.5.6", "", {}, "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA=="], + "stats-gl/three": ["three@0.170.0", "", {}, "sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ=="], + "swetrix/@types/node": ["@types/node@14.18.63", "", {}, "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ=="], "tailwind-variants/tailwind-merge": ["tailwind-merge@2.5.4", "", {}, "sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q=="], + "three-stdlib/fflate": ["fflate@0.6.10", "", {}, "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg=="], + + "tunnel-rat/zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="], + + "@c15t/react/@radix-ui/react-accordion/@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="], + + "@c15t/react/@radix-ui/react-accordion/@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.4", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.3", "@radix-ui/react-primitive": "2.0.3", "@radix-ui/react-use-controllable-state": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-u7LCw1EYInQtBNLGjm9nZ89S/4GcvX1UR5XbekEgnQae2Hkpq39ycJ1OhdeN1/JDfVNG91kWaWoest127TaEKQ=="], + + "@c15t/react/@radix-ui/react-accordion/@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.0.3", "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-mM2pxoQw5HJ49rkzwOs7Y6J4oYH22wS8BfK2/bBxROlI4xuR0c4jEenQP63LlTlDkO6Buj2Vt+QYAYcOgqtrXA=="], + + "@c15t/react/@radix-ui/react-accordion/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Pf/t/GkndH7CQ8wE2hbkXA+WyZ83fhQQn5DDmwDiDo6AwN/fhaH8oqZ0jRjMrO2iaMhDi6P1HRx6AZwyMinY1g=="], + + "@c15t/react/@radix-ui/react-accordion/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-YnEXIy8/ga01Y1PN0VfaNH//MhA91JlEGVBDxDzROqwrAtG5Yr2QGEPz8A/rJA3C7ZAHryOYGaUv8fLSW2H/mg=="], + + "@c15t/react/@radix-ui/react-switch/@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="], + + "@c15t/react/@radix-ui/react-switch/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Pf/t/GkndH7CQ8wE2hbkXA+WyZ83fhQQn5DDmwDiDo6AwN/fhaH8oqZ0jRjMrO2iaMhDi6P1HRx6AZwyMinY1g=="], + + "@c15t/react/@radix-ui/react-switch/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-YnEXIy8/ga01Y1PN0VfaNH//MhA91JlEGVBDxDzROqwrAtG5Yr2QGEPz8A/rJA3C7ZAHryOYGaUv8fLSW2H/mg=="], + "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], @@ -1132,5 +1333,7 @@ "next/sharp/@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw=="], "next/sharp/@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.4", "", { "os": "win32", "cpu": "x64" }, "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig=="], + + "@c15t/react/@radix-ui/react-accordion/@radix-ui/react-collapsible/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IrVLIhskYhH3nLvtcBLQFZr61tBG7wx7O3kEmdzcYwRGAEBmBicGGL7ATzNgruYJ3xBTbuzEEq9OXJM3PAX3tA=="], } } diff --git a/components.json b/components.json index f826c54..c1ada72 100644 --- a/components.json +++ b/components.json @@ -18,5 +18,7 @@ "lib": "@/lib", "hooks": "@/hooks" }, - "registries": {} + "registries": { + "@animate-ui": "https://animate-ui.com/r/{name}.json" + } } diff --git a/package.json b/package.json index 8194279..7ef1adf 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "@pixiv/three-vrm": "^3.3.4", "@pixiv/three-vrm-animation": "^3.3.4", "@radix-ui/react-slot": "^1.2.3", - "@react-three/fiber": "^9.1.2", + "@react-three/drei": "^10.7.6", + "@react-three/fiber": "^9.4.0", "@swetrix/nextjs": "^1.0.1", "@tailwindcss/postcss": "^4.1.7", "@types/three": "^0.176.0", @@ -26,11 +27,13 @@ "daisyui": "^5.0.0", "gsap": "^3.13.0", "lucide-react": "^0.548.0", - "motion": "^11.15.0", + "maath": "^0.10.8", + "motion": "^12.23.24", "next": "^16.0.0", "next-intl": "^4.4.0", "next-themes": "^0.4.4", "postcss": "^8.5.3", + "radix-ui": "^1.4.3", "react": "^19.2.0", "react-dom": "^19.2.0", "react-icons": "^5.2.1", @@ -41,13 +44,13 @@ "tailwind-merge": "^3.3.1", "tailwind-variants": "^0.3.0", "tailwindcss-animate": "^1.0.7", - "three": "^0.176.0", + "three": "^0.180.0", "tw-animate-css": "^1.4.0" }, "devDependencies": { "@biomejs/biome": "^2.3.1", "@types/node": "^20", - "@types/react": "^18", + "@types/react": "^19.2.2", "@types/react-dom": "^18", "tailwindcss": "^4.1.7", "typescript": "^5" diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx index fd9a51f..1d066f7 100644 --- a/src/app/[locale]/layout.tsx +++ b/src/app/[locale]/layout.tsx @@ -1,5 +1,4 @@ import type { Metadata } from "next"; -import localFont from "next/font/local"; import { Toaster } from "sonner"; import { NextIntlClientProvider } from "next-intl"; import { getMessages, setRequestLocale } from "next-intl/server"; @@ -7,8 +6,7 @@ import { notFound } from "next/navigation"; import { routing } from "@/i18n/routing"; import { ReactNode } from "react"; import "../globals.css"; - -const hsr = localFont({ src: "../../assets/fonts/HSR.woff2" }); +import { ConsentManager } from "@/components/consent-manager"; export const metadata: Metadata = { title: "MikanDev", @@ -41,13 +39,13 @@ export default async function LocaleLayout({ const messages = await getMessages(); return ( - - - + <> + + {children} - - - + + + ); } diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx index e75513d..31d3ff9 100644 --- a/src/app/[locale]/page.tsx +++ b/src/app/[locale]/page.tsx @@ -1,4 +1,4 @@ -import { Button } from "@/components/ui/button"; +import { Button } from "@/components/animate-ui/components/buttons/button"; import { setRequestLocale, getTranslations } from "next-intl/server"; export default async function IndexPage(params: Promise<{ locale: string }>) { @@ -9,7 +9,7 @@ export default async function IndexPage(params: Promise<{ locale: string }>) { const t = await getTranslations("home"); return ( <> - + ); } diff --git a/src/app/[locale]/template.tsx b/src/app/[locale]/template.tsx index 24481f6..d79ca9c 100644 --- a/src/app/[locale]/template.tsx +++ b/src/app/[locale]/template.tsx @@ -1,13 +1,16 @@ "use client"; import { useSwetrix } from "@swetrix/nextjs"; import { ReactNode } from "react"; +import { CursorToys } from "@/components/CursorToys"; +import SettingsController from "@/components/SettingsController"; export default function PagesLayout({ children }: { children: ReactNode }) { useSwetrix("XxNIMaHCaVG3", { apiURL: "https://analytics.mikandev.tech/log" }); return ( - <> -
{children}
- + + {children} + + ); } diff --git a/src/app/globals.css b/src/app/globals.css index 4e354cd..04dd10c 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -38,12 +38,6 @@ --sidebar-accent-foreground: #fafafa; --sidebar-border: #ff9900; --sidebar-ring: #525252; - --font-sans: - ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; - --font-mono: - ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", - "Courier New", monospace; --radius: 0.625rem; --shadow-x: 0; --shadow-y: 1px; @@ -98,12 +92,6 @@ --sidebar-accent-foreground: #fafafa; --sidebar-border: #ff9900; --sidebar-ring: #525252; - --font-sans: - ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; - --font-mono: - ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", - "Courier New", monospace; --radius: 0.625rem; --shadow-x: 0; --shadow-y: 1px; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 95763b1..ddadfb8 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,16 +1,18 @@ import { ReactNode } from "react"; -import type { Metadata } from "next"; -import { ConsentManager } from "./consent-manager"; +import localFont from "next/font/local"; +import { CursorToysProvider } from "@/contexts/CursorToysContext"; -export const metadata: Metadata = { - title: "MikanDev", - description: "We make cool stuff to make life easier 🍊", -}; +const hsr = localFont({ + src: "../assets/fonts/HSR.woff2", + variable: "--font-sans", +}); export default function RootLayout({ children }: { children: ReactNode }) { return ( - - <>{children} - + + + {children} + + ); } diff --git a/src/components/ClickSpark.tsx b/src/components/ClickSpark.tsx index f1406a3..5282452 100644 --- a/src/components/ClickSpark.tsx +++ b/src/components/ClickSpark.tsx @@ -1,4 +1,5 @@ -import React, { useRef, useEffect, useCallback } from 'react'; +"use client"; +import React, { useRef, useEffect, useCallback } from "react"; interface ClickSparkProps { sparkColor?: string; @@ -6,7 +7,7 @@ interface ClickSparkProps { sparkRadius?: number; sparkCount?: number; duration?: number; - easing?: 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out'; + easing?: "linear" | "ease-in" | "ease-out" | "ease-in-out"; extraScale?: number; children?: React.ReactNode; } @@ -19,14 +20,14 @@ interface Spark { } const ClickSpark: React.FC = ({ - sparkColor = '#fff', + sparkColor = "#fff", sparkSize = 10, sparkRadius = 15, sparkCount = 8, duration = 400, - easing = 'ease-out', + easing = "ease-out", extraScale = 1.0, - children + children, }) => { const canvasRef = useRef(null); const sparksRef = useRef([]); @@ -68,23 +69,23 @@ const ClickSpark: React.FC = ({ const easeFunc = useCallback( (t: number) => { switch (easing) { - case 'linear': + case "linear": return t; - case 'ease-in': + case "ease-in": return t * t; - case 'ease-in-out': + case "ease-in-out": return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t; default: return t * (2 - t); } }, - [easing] + [easing], ); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; - const ctx = canvas.getContext('2d'); + const ctx = canvas.getContext("2d"); if (!ctx) return; let animationId: number; @@ -130,7 +131,15 @@ const ClickSpark: React.FC = ({ return () => { cancelAnimationFrame(animationId); }; - }, [sparkColor, sparkSize, sparkRadius, sparkCount, duration, easeFunc, extraScale]); + }, [ + sparkColor, + sparkSize, + sparkRadius, + sparkCount, + duration, + easeFunc, + extraScale, + ]); const handleClick = (e: React.MouseEvent): void => { const canvas = canvasRef.current; @@ -144,7 +153,7 @@ const ClickSpark: React.FC = ({ x, y, angle: (2 * Math.PI * i) / sparkCount, - startTime: now + startTime: now, })); sparksRef.current.push(...newSparks); @@ -152,7 +161,10 @@ const ClickSpark: React.FC = ({ return (
- + {children}
); diff --git a/src/components/CursorToys.tsx b/src/components/CursorToys.tsx new file mode 100644 index 0000000..d45ae0c --- /dev/null +++ b/src/components/CursorToys.tsx @@ -0,0 +1,26 @@ +"use client"; +import { ICursorToys } from "@/interfaces/CursorToys"; +import { FC } from "react"; +import { useCursorToys } from "@/contexts/CursorToysContext"; + +import ClickSpark from "@/components/ClickSpark"; +import SplashCursor from "@/components/SplashCursor"; +import CustomCursor from "@/components/CustomCursor"; +import TargetCursor from "@/components/TargetCursor"; + +export const CursorToys: FC = ({ children }) => { + const { selectedToy } = useCursorToys(); + + if (selectedToy === "spark") { + return {children}; + } + + return ( + <> + {selectedToy === "splash" && } + {selectedToy === "custom" && } + {selectedToy === "target" && } + {children} + + ); +}; diff --git a/src/components/CustomCursor.tsx b/src/components/CustomCursor.tsx new file mode 100644 index 0000000..a24d352 --- /dev/null +++ b/src/components/CustomCursor.tsx @@ -0,0 +1,35 @@ +"use client"; +import { useEffect, useState } from "react"; +import Mikan from "@/assets/img/mikan.png"; +import Image from "next/image"; + +export default function CustomCursor() { + const [position, setPosition] = useState({ x: 0, y: 0 }); + + useEffect(() => { + document.body.style.cursor = "none"; + + const handleMouseMove = (e: MouseEvent) => { + setPosition({ x: e.clientX, y: e.clientY }); + }; + + window.addEventListener("mousemove", handleMouseMove); + + return () => { + window.removeEventListener("mousemove", handleMouseMove); + document.body.style.cursor = "auto"; + }; + }, []); + + return ( +
+ Custom Cursor +
+ ); +} diff --git a/src/components/FluidGlass.tsx b/src/components/FluidGlass.tsx new file mode 100644 index 0000000..7a5998f --- /dev/null +++ b/src/components/FluidGlass.tsx @@ -0,0 +1,385 @@ +import * as THREE from "three"; +import { useRef, useState, useEffect, memo, ReactNode } from "react"; +import { + Canvas, + createPortal, + useFrame, + useThree, + ThreeElements, +} from "@react-three/fiber"; +import { + useFBO, + useGLTF, + useScroll, + Image, + Scroll, + Preload, + ScrollControls, + MeshTransmissionMaterial, + Text, +} from "@react-three/drei"; +import { easing } from "maath"; + +type Mode = "lens" | "bar" | "cube"; + +interface NavItem { + label: string; + link: string; +} + +type ModeProps = Record; + +interface FluidGlassProps { + mode?: Mode; + lensProps?: ModeProps; + barProps?: ModeProps; + cubeProps?: ModeProps; +} + +export default function FluidGlass({ + mode = "lens", + lensProps = {}, + barProps = {}, + cubeProps = {}, +}: FluidGlassProps) { + const Wrapper = mode === "bar" ? Bar : mode === "cube" ? Cube : Lens; + const rawOverrides = + mode === "bar" ? barProps : mode === "cube" ? cubeProps : lensProps; + + const { + navItems = [ + { label: "Home", link: "" }, + { label: "About", link: "" }, + { label: "Contact", link: "" }, + ], + ...modeProps + } = rawOverrides; + + return ( + + + {mode === "bar" && } + + + + + + + + + + + ); +} + +type MeshProps = ThreeElements["mesh"]; + +interface ModeWrapperProps extends MeshProps { + children?: ReactNode; + glb: string; + geometryKey: string; + lockToBottom?: boolean; + followPointer?: boolean; + modeProps?: ModeProps; +} + +interface ZoomMaterial extends THREE.Material { + zoom: number; +} + +interface ZoomMesh extends THREE.Mesh {} + +type ZoomGroup = THREE.Group & { children: ZoomMesh[] }; + +const ModeWrapper = memo(function ModeWrapper({ + children, + glb, + geometryKey, + lockToBottom = false, + followPointer = true, + modeProps = {}, + ...props +}: ModeWrapperProps) { + const ref = useRef(null!); + const { nodes } = useGLTF(glb); + const buffer = useFBO(); + const { viewport: vp } = useThree(); + const [scene] = useState(() => new THREE.Scene()); + const geoWidthRef = useRef(1); + + useEffect(() => { + const geo = (nodes[geometryKey] as THREE.Mesh)?.geometry; + geo.computeBoundingBox(); + geoWidthRef.current = geo.boundingBox!.max.x - geo.boundingBox!.min.x || 1; + }, [nodes, geometryKey]); + + useFrame((state, delta) => { + const { gl, viewport, pointer, camera } = state; + const v = viewport.getCurrentViewport(camera, [0, 0, 15]); + + const destX = followPointer ? (pointer.x * v.width) / 2 : 0; + const destY = lockToBottom + ? -v.height / 2 + 0.2 + : followPointer + ? (pointer.y * v.height) / 2 + : 0; + easing.damp3(ref.current.position, [destX, destY, 15], 0.15, delta); + + if ((modeProps as { scale?: number }).scale == null) { + const maxWorld = v.width * 0.9; + const desired = maxWorld / geoWidthRef.current; + ref.current.scale.setScalar(Math.min(0.15, desired)); + } + + gl.setRenderTarget(buffer); + gl.render(scene, camera); + gl.setRenderTarget(null); + gl.setClearColor(0x5227ff, 1); + }); + + const { + scale, + ior, + thickness, + anisotropy, + chromaticAberration, + ...extraMat + } = modeProps as { + scale?: number; + ior?: number; + thickness?: number; + anisotropy?: number; + chromaticAberration?: number; + [key: string]: unknown; + }; + + return ( + <> + {createPortal(children, scene)} + + + + + + + + + ); +}); + +function Lens({ modeProps, ...p }: { modeProps?: ModeProps } & MeshProps) { + return ( + + ); +} + +function Cube({ modeProps, ...p }: { modeProps?: ModeProps } & MeshProps) { + return ( + + ); +} + +function Bar({ modeProps = {}, ...p }: { modeProps?: ModeProps } & MeshProps) { + const defaultMat = { + transmission: 1, + roughness: 0, + thickness: 10, + ior: 1.15, + color: "#ffffff", + attenuationColor: "#ffffff", + attenuationDistance: 0.25, + }; + + return ( + + ); +} + +function NavItems({ items }: { items: NavItem[] }) { + const group = useRef(null!); + const { viewport, camera } = useThree(); + + const DEVICE = { + mobile: { max: 639, spacing: 0.2, fontSize: 0.035 }, + tablet: { max: 1023, spacing: 0.24, fontSize: 0.045 }, + desktop: { max: Infinity, spacing: 0.3, fontSize: 0.045 }, + }; + const getDevice = () => { + const w = window.innerWidth; + return w <= DEVICE.mobile.max + ? "mobile" + : w <= DEVICE.tablet.max + ? "tablet" + : "desktop"; + }; + + const [device, setDevice] = useState(getDevice()); + + useEffect(() => { + const onResize = () => setDevice(getDevice()); + window.addEventListener("resize", onResize); + return () => window.removeEventListener("resize", onResize); + }, []); + + const { spacing, fontSize } = DEVICE[device]; + + useFrame(() => { + if (!group.current) return; + const v = viewport.getCurrentViewport(camera, [0, 0, 15]); + group.current.position.set(0, -v.height / 2 + 0.2, 15.1); + + group.current.children.forEach((child, i) => { + child.position.x = (i - (items.length - 1) / 2) * spacing; + }); + }); + + const handleNavigate = (link: string) => { + if (!link) return; + link.startsWith("#") + ? (window.location.hash = link) + : (window.location.href = link); + }; + + return ( + + {items.map(({ label, link }) => ( + { + e.stopPropagation(); + handleNavigate(link); + }} + onPointerOver={() => (document.body.style.cursor = "pointer")} + onPointerOut={() => (document.body.style.cursor = "auto")} + > + {label} + + ))} + + ); +} + +function Images() { + const group = useRef(null!); + const data = useScroll(); + const { height } = useThree((s) => s.viewport); + + useFrame(() => { + group.current.children[0].material.zoom = 1 + data.range(0, 1 / 3) / 3; + group.current.children[1].material.zoom = 1 + data.range(0, 1 / 3) / 3; + group.current.children[2].material.zoom = + 1 + data.range(1.15 / 3, 1 / 3) / 2; + group.current.children[3].material.zoom = + 1 + data.range(1.15 / 3, 1 / 3) / 2; + group.current.children[4].material.zoom = + 1 + data.range(1.15 / 3, 1 / 3) / 2; + }); + + return ( + + + + + + + + ); +} + +function Typography() { + const DEVICE = { + mobile: { fontSize: 0.2 }, + tablet: { fontSize: 0.4 }, + desktop: { fontSize: 0.6 }, + }; + const getDevice = () => { + const w = window.innerWidth; + return w <= 639 ? "mobile" : w <= 1023 ? "tablet" : "desktop"; + }; + + const [device, setDevice] = useState(getDevice()); + + useEffect(() => { + const onResize = () => setDevice(getDevice()); + window.addEventListener("resize", onResize); + return () => window.removeEventListener("resize", onResize); + }, []); + + const { fontSize } = DEVICE[device]; + + return ( + + React Bits + + ); +} diff --git a/src/components/GlobalCursorToys.tsx b/src/components/GlobalCursorToys.tsx new file mode 100644 index 0000000..535472c --- /dev/null +++ b/src/components/GlobalCursorToys.tsx @@ -0,0 +1,13 @@ +"use client"; +import { useCursorToys } from "@/contexts/CursorToysContext"; +import TargetCursor from "@/components/TargetCursor"; + +export default function GlobalCursorToys() { + const { selectedToy } = useCursorToys(); + + if (selectedToy === "target") { + return ; + } + + return null; +} diff --git a/src/components/SettingsController.tsx b/src/components/SettingsController.tsx new file mode 100644 index 0000000..217206a --- /dev/null +++ b/src/components/SettingsController.tsx @@ -0,0 +1,99 @@ +"use client"; +import { motion, AnimatePresence } from "motion/react"; +import { useState } from "react"; +import { Settings } from "@/components/animate-ui/icons/settings"; +import { useConsentManager } from "@c15t/react"; +import { Button } from "@/components/animate-ui/components/buttons/button"; +import { useCursorToys } from "@/contexts/CursorToysContext"; + +interface AccButtonProps { + children?: React.ReactNode; +} + +const AnimatedButton = ({ onClick }: { onClick: () => void }) => { + return ( + +
+ +
+
+ ); +}; + +export default function SettingsController({ children }: AccButtonProps) { + const [open, setOpen] = useState(false); + const { setIsPrivacyDialogOpen } = useConsentManager(); + const { selectedToy, setSelectedToy } = useCursorToys(); + + return ( +
+ setOpen(!open)} /> + + {open && ( + +
+

Site settings

+
+
+ +
+

Cursor Toys

+
+ + + + + +
+
+
+
+ )} +
+ {children} +
+ ); +} diff --git a/src/components/SplashCursor.tsx b/src/components/SplashCursor.tsx index 06e41e2..6d1610a 100644 --- a/src/components/SplashCursor.tsx +++ b/src/components/SplashCursor.tsx @@ -1,5 +1,5 @@ -'use client'; -import React, { useEffect, useRef } from 'react'; +"use client"; +import React, { useEffect, useRef } from "react"; interface ColorRGB { r: number; @@ -48,7 +48,7 @@ function pointerPrototype(): Pointer { deltaY: 0, down: false, moved: false, - color: { r: 0, g: 0, b: 0 } + color: { r: 0, g: 0, b: 0 }, }; } @@ -66,7 +66,7 @@ export default function SplashCursor({ SHADING = true, COLOR_UPDATE_SPEED = 10, BACK_COLOR = { r: 0.5, g: 0, b: 0 }, - TRANSPARENT = true + TRANSPARENT = true, }: SplashCursorProps) { const canvasRef = useRef(null); @@ -91,7 +91,7 @@ export default function SplashCursor({ COLOR_UPDATE_SPEED: COLOR_UPDATE_SPEED!, PAUSED: false, BACK_COLOR, - TRANSPARENT + TRANSPARENT, }; const { gl, ext } = getWebGLContext(canvas); @@ -108,31 +108,41 @@ export default function SplashCursor({ depth: false, stencil: false, antialias: false, - preserveDrawingBuffer: false + preserveDrawingBuffer: false, }; - let gl = canvas.getContext('webgl2', params) as WebGL2RenderingContext | null; + let gl = canvas.getContext( + "webgl2", + params, + ) as WebGL2RenderingContext | null; if (!gl) { - gl = (canvas.getContext('webgl', params) || - canvas.getContext('experimental-webgl', params)) as WebGL2RenderingContext | null; + gl = (canvas.getContext("webgl", params) || + canvas.getContext( + "experimental-webgl", + params, + )) as WebGL2RenderingContext | null; } if (!gl) { - throw new Error('Unable to initialize WebGL.'); + throw new Error("Unable to initialize WebGL."); } - const isWebGL2 = 'drawBuffers' in gl; + const isWebGL2 = "drawBuffers" in gl; let supportLinearFiltering = false; let halfFloat = null; if (isWebGL2) { - (gl as WebGL2RenderingContext).getExtension('EXT_color_buffer_float'); - supportLinearFiltering = !!(gl as WebGL2RenderingContext).getExtension('OES_texture_float_linear'); + (gl as WebGL2RenderingContext).getExtension("EXT_color_buffer_float"); + supportLinearFiltering = !!(gl as WebGL2RenderingContext).getExtension( + "OES_texture_float_linear", + ); } else { - halfFloat = gl.getExtension('OES_texture_half_float'); - supportLinearFiltering = !!gl.getExtension('OES_texture_half_float_linear'); + halfFloat = gl.getExtension("OES_texture_half_float"); + supportLinearFiltering = !!gl.getExtension( + "OES_texture_half_float_linear", + ); } gl.clearColor(0, 0, 0, 1); @@ -146,18 +156,23 @@ export default function SplashCursor({ let formatR: any; if (isWebGL2) { - formatRGBA = getSupportedFormat(gl, (gl as WebGL2RenderingContext).RGBA16F, gl.RGBA, halfFloatTexType); + formatRGBA = getSupportedFormat( + gl, + (gl as WebGL2RenderingContext).RGBA16F, + gl.RGBA, + halfFloatTexType, + ); formatRG = getSupportedFormat( gl, (gl as WebGL2RenderingContext).RG16F, (gl as WebGL2RenderingContext).RG, - halfFloatTexType + halfFloatTexType, ); formatR = getSupportedFormat( gl, (gl as WebGL2RenderingContext).R16F, (gl as WebGL2RenderingContext).RED, - halfFloatTexType + halfFloatTexType, ); } else { formatRGBA = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType); @@ -172,8 +187,8 @@ export default function SplashCursor({ formatRG, formatR, halfFloatTexType, - supportLinearFiltering - } + supportLinearFiltering, + }, }; } @@ -181,10 +196,10 @@ export default function SplashCursor({ gl: WebGLRenderingContext | WebGL2RenderingContext, internalFormat: number, format: number, - type: number + type: number, ): { internalFormat: number; format: number } | null { if (!supportRenderTextureFormat(gl, internalFormat, format, type)) { - if ('drawBuffers' in gl) { + if ("drawBuffers" in gl) { const gl2 = gl as WebGL2RenderingContext; switch (internalFormat) { case gl2.R16F: @@ -204,7 +219,7 @@ export default function SplashCursor({ gl: WebGLRenderingContext | WebGL2RenderingContext, internalFormat: number, format: number, - type: number + type: number, ) { const texture = gl.createTexture(); if (!texture) return false; @@ -214,13 +229,29 @@ export default function SplashCursor({ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 4, 4, 0, format, type, null); + gl.texImage2D( + gl.TEXTURE_2D, + 0, + internalFormat, + 4, + 4, + 0, + format, + type, + null, + ); const fbo = gl.createFramebuffer(); if (!fbo) return false; gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); + gl.framebufferTexture2D( + gl.FRAMEBUFFER, + gl.COLOR_ATTACHMENT0, + gl.TEXTURE_2D, + texture, + 0, + ); const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER); return status === gl.FRAMEBUFFER_COMPLETE; } @@ -237,14 +268,18 @@ export default function SplashCursor({ function addKeywords(source: string, keywords: string[] | null) { if (!keywords) return source; - let keywordsString = ''; + let keywordsString = ""; for (const keyword of keywords) { keywordsString += `#define ${keyword}\n`; } return keywordsString + source; } - function compileShader(type: number, source: string, keywords: string[] | null = null): WebGLShader | null { + function compileShader( + type: number, + source: string, + keywords: string[] | null = null, + ): WebGLShader | null { const shaderSource = addKeywords(source, keywords); const shader = gl.createShader(type); if (!shader) return null; @@ -256,7 +291,10 @@ export default function SplashCursor({ return shader; } - function createProgram(vertexShader: WebGLShader | null, fragmentShader: WebGLShader | null): WebGLProgram | null { + function createProgram( + vertexShader: WebGLShader | null, + fragmentShader: WebGLShader | null, + ): WebGLProgram | null { if (!vertexShader || !fragmentShader) return null; const program = gl.createProgram(); if (!program) return null; @@ -275,7 +313,10 @@ export default function SplashCursor({ for (let i = 0; i < uniformCount; i++) { const uniformInfo = gl.getActiveUniform(program, i); if (uniformInfo) { - uniforms[uniformInfo.name] = gl.getUniformLocation(program, uniformInfo.name); + uniforms[uniformInfo.name] = gl.getUniformLocation( + program, + uniformInfo.name, + ); } } return uniforms; @@ -285,7 +326,10 @@ export default function SplashCursor({ program: WebGLProgram | null; uniforms: Record; - constructor(vertexShader: WebGLShader | null, fragmentShader: WebGLShader | null) { + constructor( + vertexShader: WebGLShader | null, + fragmentShader: WebGLShader | null, + ) { this.program = createProgram(vertexShader, fragmentShader); this.uniforms = this.program ? getUniforms(this.program) : {}; } @@ -302,7 +346,10 @@ export default function SplashCursor({ activeProgram: WebGLProgram | null; uniforms: Record; - constructor(vertexShader: WebGLShader | null, fragmentShaderSource: string) { + constructor( + vertexShader: WebGLShader | null, + fragmentShaderSource: string, + ) { this.vertexShader = vertexShader; this.fragmentShaderSource = fragmentShaderSource; this.programs = {}; @@ -317,7 +364,11 @@ export default function SplashCursor({ } let program = this.programs[hash]; if (program == null) { - const fragmentShader = compileShader(gl.FRAGMENT_SHADER, this.fragmentShaderSource, keywords); + const fragmentShader = compileShader( + gl.FRAGMENT_SHADER, + this.fragmentShaderSource, + keywords, + ); program = createProgram(this.vertexShader, fragmentShader); this.programs[hash] = program; } @@ -355,7 +406,7 @@ export default function SplashCursor({ vB = vUv - vec2(0.0, texelSize.y); gl_Position = vec4(aPosition, 0.0, 1.0); } - ` + `, ); const copyShader = compileShader( @@ -369,7 +420,7 @@ export default function SplashCursor({ void main () { gl_FragColor = texture2D(uTexture, vUv); } - ` + `, ); const clearShader = compileShader( @@ -384,7 +435,7 @@ export default function SplashCursor({ void main () { gl_FragColor = value * texture2D(uTexture, vUv); } - ` + `, ); const displayShaderSource = ` @@ -447,7 +498,7 @@ export default function SplashCursor({ vec3 base = texture2D(uTarget, vUv).xyz; gl_FragColor = vec4(base + splat, 1.0); } - ` + `, ); const advectionShader = compileShader( @@ -488,7 +539,7 @@ export default function SplashCursor({ gl_FragColor = result / decay; } `, - ext.supportLinearFiltering ? null : ['MANUAL_FILTERING'] + ext.supportLinearFiltering ? null : ["MANUAL_FILTERING"], ); const divergenceShader = compileShader( @@ -518,7 +569,7 @@ export default function SplashCursor({ float div = 0.5 * (R - L + T - B); gl_FragColor = vec4(div, 0.0, 0.0, 1.0); } - ` + `, ); const curlShader = compileShader( @@ -541,7 +592,7 @@ export default function SplashCursor({ float vorticity = R - L - T + B; gl_FragColor = vec4(0.5 * vorticity, 0.0, 0.0, 1.0); } - ` + `, ); const vorticityShader = compileShader( @@ -576,7 +627,7 @@ export default function SplashCursor({ velocity = min(max(velocity, -1000.0), 1000.0); gl_FragColor = vec4(velocity, 0.0, 1.0); } - ` + `, ); const pressureShader = compileShader( @@ -602,7 +653,7 @@ export default function SplashCursor({ float pressure = (L + R + B + T - divergence) * 0.25; gl_FragColor = vec4(pressure, 0.0, 0.0, 1.0); } - ` + `, ); const gradientSubtractShader = compileShader( @@ -627,16 +678,24 @@ export default function SplashCursor({ velocity.xy -= vec2(R - L, T - B); gl_FragColor = vec4(velocity, 0.0, 1.0); } - ` + `, ); const blit = (() => { const buffer = gl.createBuffer()!; gl.bindBuffer(gl.ARRAY_BUFFER, buffer); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, -1, 1, 1, 1, 1, -1]), gl.STATIC_DRAW); + gl.bufferData( + gl.ARRAY_BUFFER, + new Float32Array([-1, -1, -1, 1, 1, 1, 1, -1]), + gl.STATIC_DRAW, + ); const elemBuffer = gl.createBuffer()!; gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elemBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 0, 2, 3]), gl.STATIC_DRAW); + gl.bufferData( + gl.ELEMENT_ARRAY_BUFFER, + new Uint16Array([0, 1, 2, 0, 2, 3]), + gl.STATIC_DRAW, + ); gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(0); @@ -691,10 +750,20 @@ export default function SplashCursor({ const curlProgram = new Program(baseVertexShader, curlShader); const vorticityProgram = new Program(baseVertexShader, vorticityShader); const pressureProgram = new Program(baseVertexShader, pressureShader); - const gradienSubtractProgram = new Program(baseVertexShader, gradientSubtractShader); + const gradienSubtractProgram = new Program( + baseVertexShader, + gradientSubtractShader, + ); const displayMaterial = new Material(baseVertexShader, displayShaderSource); - function createFBO(w: number, h: number, internalFormat: number, format: number, type: number, param: number): FBO { + function createFBO( + w: number, + h: number, + internalFormat: number, + format: number, + type: number, + param: number, + ): FBO { gl.activeTexture(gl.TEXTURE0); const texture = gl.createTexture()!; gl.bindTexture(gl.TEXTURE_2D, texture); @@ -702,10 +771,26 @@ export default function SplashCursor({ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, param); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, w, h, 0, format, type, null); + gl.texImage2D( + gl.TEXTURE_2D, + 0, + internalFormat, + w, + h, + 0, + format, + type, + null, + ); const fbo = gl.createFramebuffer()!; gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); + gl.framebufferTexture2D( + gl.FRAMEBUFFER, + gl.COLOR_ATTACHMENT0, + gl.TEXTURE_2D, + texture, + 0, + ); gl.viewport(0, 0, w, h); gl.clear(gl.COLOR_BUFFER_BIT); @@ -723,7 +808,7 @@ export default function SplashCursor({ gl.activeTexture(gl.TEXTURE0 + id); gl.bindTexture(gl.TEXTURE_2D, texture); return id; - } + }, }; } @@ -733,7 +818,7 @@ export default function SplashCursor({ internalFormat: number, format: number, type: number, - param: number + param: number, ): DoubleFBO { const fbo1 = createFBO(w, h, internalFormat, format, type, param); const fbo2 = createFBO(w, h, internalFormat, format, type, param); @@ -748,7 +833,7 @@ export default function SplashCursor({ const tmp = this.read; this.read = this.write; this.write = tmp; - } + }, }; } @@ -759,11 +844,12 @@ export default function SplashCursor({ internalFormat: number, format: number, type: number, - param: number + param: number, ) { const newFBO = createFBO(w, h, internalFormat, format, type, param); copyProgram.bind(); - if (copyProgram.uniforms.uTexture) gl.uniform1i(copyProgram.uniforms.uTexture, target.attach(0)); + if (copyProgram.uniforms.uTexture) + gl.uniform1i(copyProgram.uniforms.uTexture, target.attach(0)); blit(newFBO, false); return newFBO; } @@ -775,10 +861,18 @@ export default function SplashCursor({ internalFormat: number, format: number, type: number, - param: number + param: number, ) { if (target.width === w && target.height === h) return target; - target.read = resizeFBO(target.read, w, h, internalFormat, format, type, param); + target.read = resizeFBO( + target.read, + w, + h, + internalFormat, + format, + type, + param, + ); target.write = createFBO(w, h, internalFormat, format, type, param); target.width = w; target.height = h; @@ -799,13 +893,35 @@ export default function SplashCursor({ gl.disable(gl.BLEND); if (!dye) { - dye = createDoubleFBO(dyeRes.width, dyeRes.height, rgba.internalFormat, rgba.format, texType, filtering); + dye = createDoubleFBO( + dyeRes.width, + dyeRes.height, + rgba.internalFormat, + rgba.format, + texType, + filtering, + ); } else { - dye = resizeDoubleFBO(dye, dyeRes.width, dyeRes.height, rgba.internalFormat, rgba.format, texType, filtering); + dye = resizeDoubleFBO( + dye, + dyeRes.width, + dyeRes.height, + rgba.internalFormat, + rgba.format, + texType, + filtering, + ); } if (!velocity) { - velocity = createDoubleFBO(simRes.width, simRes.height, rg.internalFormat, rg.format, texType, filtering); + velocity = createDoubleFBO( + simRes.width, + simRes.height, + rg.internalFormat, + rg.format, + texType, + filtering, + ); } else { velocity = resizeDoubleFBO( velocity, @@ -814,18 +930,39 @@ export default function SplashCursor({ rg.internalFormat, rg.format, texType, - filtering + filtering, ); } - divergence = createFBO(simRes.width, simRes.height, r.internalFormat, r.format, texType, gl.NEAREST); - curl = createFBO(simRes.width, simRes.height, r.internalFormat, r.format, texType, gl.NEAREST); - pressure = createDoubleFBO(simRes.width, simRes.height, r.internalFormat, r.format, texType, gl.NEAREST); + divergence = createFBO( + simRes.width, + simRes.height, + r.internalFormat, + r.format, + texType, + gl.NEAREST, + ); + curl = createFBO( + simRes.width, + simRes.height, + r.internalFormat, + r.format, + texType, + gl.NEAREST, + ); + pressure = createDoubleFBO( + simRes.width, + simRes.height, + r.internalFormat, + r.format, + texType, + gl.NEAREST, + ); } function updateKeywords() { const displayKeywords: string[] = []; - if (config.SHADING) displayKeywords.push('SHADING'); + if (config.SHADING) displayKeywords.push("SHADING"); displayMaterial.setKeywords(displayKeywords); } @@ -886,7 +1023,7 @@ export default function SplashCursor({ colorUpdateTimer += dt * config.COLOR_UPDATE_SPEED; if (colorUpdateTimer >= 1) { colorUpdateTimer = wrap(colorUpdateTimer, 0, 1); - pointers.forEach(p => { + pointers.forEach((p) => { p.color = generateColor(); }); } @@ -906,7 +1043,11 @@ export default function SplashCursor({ curlProgram.bind(); if (curlProgram.uniforms.texelSize) { - gl.uniform2f(curlProgram.uniforms.texelSize, velocity.texelSizeX, velocity.texelSizeY); + gl.uniform2f( + curlProgram.uniforms.texelSize, + velocity.texelSizeX, + velocity.texelSizeY, + ); } if (curlProgram.uniforms.uVelocity) { gl.uniform1i(curlProgram.uniforms.uVelocity, velocity.read.attach(0)); @@ -915,10 +1056,17 @@ export default function SplashCursor({ vorticityProgram.bind(); if (vorticityProgram.uniforms.texelSize) { - gl.uniform2f(vorticityProgram.uniforms.texelSize, velocity.texelSizeX, velocity.texelSizeY); + gl.uniform2f( + vorticityProgram.uniforms.texelSize, + velocity.texelSizeX, + velocity.texelSizeY, + ); } if (vorticityProgram.uniforms.uVelocity) { - gl.uniform1i(vorticityProgram.uniforms.uVelocity, velocity.read.attach(0)); + gl.uniform1i( + vorticityProgram.uniforms.uVelocity, + velocity.read.attach(0), + ); } if (vorticityProgram.uniforms.uCurl) { gl.uniform1i(vorticityProgram.uniforms.uCurl, curl.attach(1)); @@ -934,10 +1082,17 @@ export default function SplashCursor({ divergenceProgram.bind(); if (divergenceProgram.uniforms.texelSize) { - gl.uniform2f(divergenceProgram.uniforms.texelSize, velocity.texelSizeX, velocity.texelSizeY); + gl.uniform2f( + divergenceProgram.uniforms.texelSize, + velocity.texelSizeX, + velocity.texelSizeY, + ); } if (divergenceProgram.uniforms.uVelocity) { - gl.uniform1i(divergenceProgram.uniforms.uVelocity, velocity.read.attach(0)); + gl.uniform1i( + divergenceProgram.uniforms.uVelocity, + velocity.read.attach(0), + ); } blit(divergence); @@ -953,14 +1108,24 @@ export default function SplashCursor({ pressureProgram.bind(); if (pressureProgram.uniforms.texelSize) { - gl.uniform2f(pressureProgram.uniforms.texelSize, velocity.texelSizeX, velocity.texelSizeY); + gl.uniform2f( + pressureProgram.uniforms.texelSize, + velocity.texelSizeX, + velocity.texelSizeY, + ); } if (pressureProgram.uniforms.uDivergence) { - gl.uniform1i(pressureProgram.uniforms.uDivergence, divergence.attach(0)); + gl.uniform1i( + pressureProgram.uniforms.uDivergence, + divergence.attach(0), + ); } for (let i = 0; i < config.PRESSURE_ITERATIONS; i++) { if (pressureProgram.uniforms.uPressure) { - gl.uniform1i(pressureProgram.uniforms.uPressure, pressure.read.attach(1)); + gl.uniform1i( + pressureProgram.uniforms.uPressure, + pressure.read.attach(1), + ); } blit(pressure.write); pressure.swap(); @@ -968,23 +1133,44 @@ export default function SplashCursor({ gradienSubtractProgram.bind(); if (gradienSubtractProgram.uniforms.texelSize) { - gl.uniform2f(gradienSubtractProgram.uniforms.texelSize, velocity.texelSizeX, velocity.texelSizeY); + gl.uniform2f( + gradienSubtractProgram.uniforms.texelSize, + velocity.texelSizeX, + velocity.texelSizeY, + ); } if (gradienSubtractProgram.uniforms.uPressure) { - gl.uniform1i(gradienSubtractProgram.uniforms.uPressure, pressure.read.attach(0)); + gl.uniform1i( + gradienSubtractProgram.uniforms.uPressure, + pressure.read.attach(0), + ); } if (gradienSubtractProgram.uniforms.uVelocity) { - gl.uniform1i(gradienSubtractProgram.uniforms.uVelocity, velocity.read.attach(1)); + gl.uniform1i( + gradienSubtractProgram.uniforms.uVelocity, + velocity.read.attach(1), + ); } blit(velocity.write); velocity.swap(); advectionProgram.bind(); if (advectionProgram.uniforms.texelSize) { - gl.uniform2f(advectionProgram.uniforms.texelSize, velocity.texelSizeX, velocity.texelSizeY); + gl.uniform2f( + advectionProgram.uniforms.texelSize, + velocity.texelSizeX, + velocity.texelSizeY, + ); } - if (!ext.supportLinearFiltering && advectionProgram.uniforms.dyeTexelSize) { - gl.uniform2f(advectionProgram.uniforms.dyeTexelSize, velocity.texelSizeX, velocity.texelSizeY); + if ( + !ext.supportLinearFiltering && + advectionProgram.uniforms.dyeTexelSize + ) { + gl.uniform2f( + advectionProgram.uniforms.dyeTexelSize, + velocity.texelSizeX, + velocity.texelSizeY, + ); } const velocityId = velocity.read.attach(0); if (advectionProgram.uniforms.uVelocity) { @@ -997,22 +1183,38 @@ export default function SplashCursor({ gl.uniform1f(advectionProgram.uniforms.dt, dt); } if (advectionProgram.uniforms.dissipation) { - gl.uniform1f(advectionProgram.uniforms.dissipation, config.VELOCITY_DISSIPATION); + gl.uniform1f( + advectionProgram.uniforms.dissipation, + config.VELOCITY_DISSIPATION, + ); } blit(velocity.write); velocity.swap(); - if (!ext.supportLinearFiltering && advectionProgram.uniforms.dyeTexelSize) { - gl.uniform2f(advectionProgram.uniforms.dyeTexelSize, dye.texelSizeX, dye.texelSizeY); + if ( + !ext.supportLinearFiltering && + advectionProgram.uniforms.dyeTexelSize + ) { + gl.uniform2f( + advectionProgram.uniforms.dyeTexelSize, + dye.texelSizeX, + dye.texelSizeY, + ); } if (advectionProgram.uniforms.uVelocity) { - gl.uniform1i(advectionProgram.uniforms.uVelocity, velocity.read.attach(0)); + gl.uniform1i( + advectionProgram.uniforms.uVelocity, + velocity.read.attach(0), + ); } if (advectionProgram.uniforms.uSource) { gl.uniform1i(advectionProgram.uniforms.uSource, dye.read.attach(1)); } if (advectionProgram.uniforms.dissipation) { - gl.uniform1f(advectionProgram.uniforms.dissipation, config.DENSITY_DISSIPATION); + gl.uniform1f( + advectionProgram.uniforms.dissipation, + config.DENSITY_DISSIPATION, + ); } blit(dye.write); dye.swap(); @@ -1053,13 +1255,22 @@ export default function SplashCursor({ splat(pointer.texcoordX, pointer.texcoordY, dx, dy, color); } - function splat(x: number, y: number, dx: number, dy: number, color: ColorRGB) { + function splat( + x: number, + y: number, + dx: number, + dy: number, + color: ColorRGB, + ) { splatProgram.bind(); if (splatProgram.uniforms.uTarget) { gl.uniform1i(splatProgram.uniforms.uTarget, velocity.read.attach(0)); } if (splatProgram.uniforms.aspectRatio) { - gl.uniform1f(splatProgram.uniforms.aspectRatio, canvas!.width / canvas!.height); + gl.uniform1f( + splatProgram.uniforms.aspectRatio, + canvas!.width / canvas!.height, + ); } if (splatProgram.uniforms.point) { gl.uniform2f(splatProgram.uniforms.point, x, y); @@ -1068,7 +1279,10 @@ export default function SplashCursor({ gl.uniform3f(splatProgram.uniforms.color, dx, dy, 0); } if (splatProgram.uniforms.radius) { - gl.uniform1f(splatProgram.uniforms.radius, correctRadius(config.SPLAT_RADIUS / 100)!); + gl.uniform1f( + splatProgram.uniforms.radius, + correctRadius(config.SPLAT_RADIUS / 100)!, + ); } blit(velocity.write); velocity.swap(); @@ -1089,7 +1303,12 @@ export default function SplashCursor({ return radius; } - function updatePointerDownData(pointer: Pointer, id: number, posX: number, posY: number) { + function updatePointerDownData( + pointer: Pointer, + id: number, + posX: number, + posY: number, + ) { pointer.id = id; pointer.down = true; pointer.moved = false; @@ -1102,14 +1321,24 @@ export default function SplashCursor({ pointer.color = generateColor(); } - function updatePointerMoveData(pointer: Pointer, posX: number, posY: number, color: ColorRGB) { + function updatePointerMoveData( + pointer: Pointer, + posX: number, + posY: number, + color: ColorRGB, + ) { pointer.prevTexcoordX = pointer.texcoordX; pointer.prevTexcoordY = pointer.texcoordY; pointer.texcoordX = posX / canvas!.width; pointer.texcoordY = 1 - posY / canvas!.height; - pointer.deltaX = correctDeltaX(pointer.texcoordX - pointer.prevTexcoordX)!; - pointer.deltaY = correctDeltaY(pointer.texcoordY - pointer.prevTexcoordY)!; - pointer.moved = Math.abs(pointer.deltaX) > 0 || Math.abs(pointer.deltaY) > 0; + pointer.deltaX = correctDeltaX( + pointer.texcoordX - pointer.prevTexcoordX, + )!; + pointer.deltaY = correctDeltaY( + pointer.texcoordY - pointer.prevTexcoordY, + )!; + pointer.moved = + Math.abs(pointer.deltaX) > 0 || Math.abs(pointer.deltaY) > 0; pointer.color = color; } @@ -1188,7 +1417,7 @@ export default function SplashCursor({ return ((value - min) % range) + min; } - window.addEventListener('mousedown', e => { + window.addEventListener("mousedown", (e) => { const pointer = pointers[0]; const posX = scaleByPixelRatio(e.clientX); const posY = scaleByPixelRatio(e.clientY); @@ -1203,11 +1432,11 @@ export default function SplashCursor({ const color = generateColor(); updateFrame(); updatePointerMoveData(pointer, posX, posY, color); - document.body.removeEventListener('mousemove', handleFirstMouseMove); + document.body.removeEventListener("mousemove", handleFirstMouseMove); } - document.body.addEventListener('mousemove', handleFirstMouseMove); + document.body.addEventListener("mousemove", handleFirstMouseMove); - window.addEventListener('mousemove', e => { + window.addEventListener("mousemove", (e) => { const pointer = pointers[0]; const posX = scaleByPixelRatio(e.clientX); const posY = scaleByPixelRatio(e.clientY); @@ -1224,13 +1453,13 @@ export default function SplashCursor({ updateFrame(); updatePointerDownData(pointer, touches[i].identifier, posX, posY); } - document.body.removeEventListener('touchstart', handleFirstTouchStart); + document.body.removeEventListener("touchstart", handleFirstTouchStart); } - document.body.addEventListener('touchstart', handleFirstTouchStart); + document.body.addEventListener("touchstart", handleFirstTouchStart); window.addEventListener( - 'touchstart', - e => { + "touchstart", + (e) => { const touches = e.targetTouches; const pointer = pointers[0]; for (let i = 0; i < touches.length; i++) { @@ -1239,12 +1468,12 @@ export default function SplashCursor({ updatePointerDownData(pointer, touches[i].identifier, posX, posY); } }, - false + false, ); window.addEventListener( - 'touchmove', - e => { + "touchmove", + (e) => { const touches = e.targetTouches; const pointer = pointers[0]; for (let i = 0; i < touches.length; i++) { @@ -1253,10 +1482,10 @@ export default function SplashCursor({ updatePointerMoveData(pointer, posX, posY, pointer.color); } }, - false + false, ); - window.addEventListener('touchend', e => { + window.addEventListener("touchend", (e) => { const touches = e.changedTouches; const pointer = pointers[0]; for (let i = 0; i < touches.length; i++) { @@ -1277,12 +1506,16 @@ export default function SplashCursor({ SHADING, COLOR_UPDATE_SPEED, BACK_COLOR, - TRANSPARENT + TRANSPARENT, ]); return (
- +
); } diff --git a/src/components/TargetCursor.tsx b/src/components/TargetCursor.tsx index 4d8ee3d..dc188ee 100644 --- a/src/components/TargetCursor.tsx +++ b/src/components/TargetCursor.tsx @@ -1,5 +1,5 @@ -import React, { useEffect, useRef, useCallback, useMemo } from 'react'; -import { gsap } from 'gsap'; +import React, { useEffect, useRef, useCallback, useMemo } from "react"; +import { gsap } from "gsap"; export interface TargetCursorProps { targetSelector?: string; @@ -8,9 +8,9 @@ export interface TargetCursorProps { } const TargetCursor: React.FC = ({ - targetSelector = '.cursor-target', + targetSelector = ".cursor-target", spinDuration = 2, - hideDefaultCursor = true + hideDefaultCursor = true, }) => { const cursorRef = useRef(null); const cornersRef = useRef>(null); @@ -20,9 +20,9 @@ const TargetCursor: React.FC = ({ () => ({ borderWidth: 3, cornerSize: 12, - parallaxStrength: 0.00005 + parallaxStrength: 0.00005, }), - [] + [], ); const moveCursor = useCallback((x: number, y: number) => { @@ -31,7 +31,7 @@ const TargetCursor: React.FC = ({ x, y, duration: 0.1, - ease: 'power3.out' + ease: "power3.out", }); }, []); @@ -40,11 +40,13 @@ const TargetCursor: React.FC = ({ const originalCursor = document.body.style.cursor; if (hideDefaultCursor) { - document.body.style.cursor = 'none'; + document.body.style.cursor = "none"; } const cursor = cursorRef.current; - cornersRef.current = cursor.querySelectorAll('.target-cursor-corner'); + cornersRef.current = cursor.querySelectorAll( + ".target-cursor-corner", + ); let activeTarget: Element | null = null; let currentTargetMove: ((ev: Event) => void) | null = null; @@ -54,10 +56,10 @@ const TargetCursor: React.FC = ({ const cleanupTarget = (target: Element) => { if (currentTargetMove) { - target.removeEventListener('mousemove', currentTargetMove); + target.removeEventListener("mousemove", currentTargetMove); } if (currentLeaveHandler) { - target.removeEventListener('mouseleave', currentLeaveHandler); + target.removeEventListener("mouseleave", currentLeaveHandler); } currentTargetMove = null; currentLeaveHandler = null; @@ -67,33 +69,36 @@ const TargetCursor: React.FC = ({ xPercent: -50, yPercent: -50, x: window.innerWidth / 2, - y: window.innerHeight / 2 + y: window.innerHeight / 2, }); const createSpinTimeline = () => { if (spinTl.current) { spinTl.current.kill(); } - spinTl.current = gsap - .timeline({ repeat: -1 }) - .to(cursor, { rotation: '+=360', duration: spinDuration, ease: 'none' }); + spinTl.current = gsap.timeline({ repeat: -1 }).to(cursor, { + rotation: "+=360", + duration: spinDuration, + ease: "none", + }); }; createSpinTimeline(); const moveHandler = (e: MouseEvent) => moveCursor(e.clientX, e.clientY); - window.addEventListener('mousemove', moveHandler); + window.addEventListener("mousemove", moveHandler); const scrollHandler = () => { if (!activeTarget || !cursorRef.current) return; - const mouseX = gsap.getProperty(cursorRef.current, 'x') as number; - const mouseY = gsap.getProperty(cursorRef.current, 'y') as number; + const mouseX = gsap.getProperty(cursorRef.current, "x") as number; + const mouseY = gsap.getProperty(cursorRef.current, "y") as number; const elementUnderMouse = document.elementFromPoint(mouseX, mouseY); const isStillOverTarget = elementUnderMouse && - (elementUnderMouse === activeTarget || elementUnderMouse.closest(targetSelector) === activeTarget); + (elementUnderMouse === activeTarget || + elementUnderMouse.closest(targetSelector) === activeTarget); if (!isStillOverTarget) { if (currentLeaveHandler) { @@ -102,8 +107,8 @@ const TargetCursor: React.FC = ({ } }; - window.addEventListener('scroll', scrollHandler, { passive: true }); - window.addEventListener('mousemove', moveHandler); + window.addEventListener("scroll", scrollHandler, { passive: true }); + window.addEventListener("mousemove", moveHandler); const mouseDownHandler = (): void => { if (!dotRef.current) return; @@ -117,8 +122,8 @@ const TargetCursor: React.FC = ({ gsap.to(cursorRef.current, { scale: 1, duration: 0.2 }); }; - window.addEventListener('mousedown', mouseDownHandler); - window.addEventListener('mouseup', mouseUpHandler); + window.addEventListener("mousedown", mouseDownHandler); + window.addEventListener("mouseup", mouseUpHandler); const enterHandler = (e: MouseEvent) => { const directTarget = e.target as Element; @@ -148,10 +153,10 @@ const TargetCursor: React.FC = ({ activeTarget = target; const corners = Array.from(cornersRef.current); - corners.forEach(corner => { + corners.forEach((corner) => { gsap.killTweensOf(corner); }); - gsap.killTweensOf(cursorRef.current, 'rotation'); + gsap.killTweensOf(cursorRef.current, "rotation"); spinTl.current?.pause(); gsap.set(cursorRef.current, { rotation: 0 }); @@ -169,19 +174,19 @@ const TargetCursor: React.FC = ({ let tlOffset = { x: rect.left - cursorCenterX - borderWidth, - y: rect.top - cursorCenterY - borderWidth + y: rect.top - cursorCenterY - borderWidth, }; let trOffset = { x: rect.right - cursorCenterX + borderWidth - cornerSize, - y: rect.top - cursorCenterY - borderWidth + y: rect.top - cursorCenterY - borderWidth, }; let brOffset = { x: rect.right - cursorCenterX + borderWidth - cornerSize, - y: rect.bottom - cursorCenterY + borderWidth - cornerSize + y: rect.bottom - cursorCenterY + borderWidth - cornerSize, }; let blOffset = { x: rect.left - cursorCenterX - borderWidth, - y: rect.bottom - cursorCenterY + borderWidth - cornerSize + y: rect.bottom - cursorCenterY + borderWidth - cornerSize, }; if (mouseX !== undefined && mouseY !== undefined) { @@ -211,9 +216,9 @@ const TargetCursor: React.FC = ({ x: offsets[index].x, y: offsets[index].y, duration: 0.2, - ease: 'power2.out' + ease: "power2.out", }, - 0 + 0, ); }); }; @@ -248,7 +253,7 @@ const TargetCursor: React.FC = ({ { x: -cornerSize * 1.5, y: -cornerSize * 1.5 }, { x: cornerSize * 0.5, y: -cornerSize * 1.5 }, { x: cornerSize * 0.5, y: cornerSize * 0.5 }, - { x: -cornerSize * 1.5, y: cornerSize * 0.5 } + { x: -cornerSize * 1.5, y: cornerSize * 0.5 }, ]; const tl = gsap.timeline(); @@ -259,30 +264,37 @@ const TargetCursor: React.FC = ({ x: positions[index].x, y: positions[index].y, duration: 0.3, - ease: 'power3.out' + ease: "power3.out", }, - 0 + 0, ); }); } resumeTimeout = setTimeout(() => { if (!activeTarget && cursorRef.current && spinTl.current) { - const currentRotation = gsap.getProperty(cursorRef.current, 'rotation') as number; + const currentRotation = gsap.getProperty( + cursorRef.current, + "rotation", + ) as number; const normalizedRotation = currentRotation % 360; spinTl.current.kill(); spinTl.current = gsap .timeline({ repeat: -1 }) - .to(cursorRef.current, { rotation: '+=360', duration: spinDuration, ease: 'none' }); + .to(cursorRef.current, { + rotation: "+=360", + duration: spinDuration, + ease: "none", + }); gsap.to(cursorRef.current, { rotation: normalizedRotation + 360, duration: spinDuration * (1 - normalizedRotation / 360), - ease: 'none', + ease: "none", onComplete: () => { spinTl.current?.restart(); - } + }, }); } resumeTimeout = null; @@ -294,16 +306,16 @@ const TargetCursor: React.FC = ({ currentTargetMove = targetMove; currentLeaveHandler = leaveHandler; - target.addEventListener('mousemove', targetMove); - target.addEventListener('mouseleave', leaveHandler); + target.addEventListener("mousemove", targetMove); + target.addEventListener("mouseleave", leaveHandler); }; - window.addEventListener('mouseover', enterHandler, { passive: true }); + window.addEventListener("mouseover", enterHandler, { passive: true }); return () => { - window.removeEventListener('mousemove', moveHandler); - window.removeEventListener('mouseover', enterHandler); - window.removeEventListener('scroll', scrollHandler); + window.removeEventListener("mousemove", moveHandler); + window.removeEventListener("mouseover", enterHandler); + window.removeEventListener("scroll", scrollHandler); if (activeTarget) { cleanupTarget(activeTarget); @@ -319,9 +331,11 @@ const TargetCursor: React.FC = ({ if (spinTl.current.isActive()) { spinTl.current.kill(); - spinTl.current = gsap - .timeline({ repeat: -1 }) - .to(cursorRef.current, { rotation: '+=360', duration: spinDuration, ease: 'none' }); + spinTl.current = gsap.timeline({ repeat: -1 }).to(cursorRef.current, { + rotation: "+=360", + duration: spinDuration, + ease: "none", + }); } }, [spinDuration]); @@ -329,28 +343,28 @@ const TargetCursor: React.FC = ({
); diff --git a/src/components/animate-ui/components/buttons/button.tsx b/src/components/animate-ui/components/buttons/button.tsx new file mode 100644 index 0000000..fd8d38c --- /dev/null +++ b/src/components/animate-ui/components/buttons/button.tsx @@ -0,0 +1,57 @@ +"use client"; + +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { + Button as ButtonPrimitive, + type ButtonProps as ButtonPrimitiveProps, +} from "@/components/animate-ui/primitives/buttons/button"; +import { cn } from "@/lib/utils"; + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[box-shadow,_color,_background-color,_border-color,_outline-color,_text-decoration-color,_fill,_stroke] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", + accent: "bg-accent text-accent-foreground shadow-xs hover:bg-accent/90", + destructive: + "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", + ghost: + "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2 has-[>svg]:px-3", + sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", + lg: "h-10 rounded-md px-6 has-[>svg]:px-4", + icon: "size-9", + "icon-sm": "size-8 rounded-md", + "icon-lg": "size-10 rounded-md", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +); + +type ButtonProps = ButtonPrimitiveProps & VariantProps; + +function Button({ className, variant, size, ...props }: ButtonProps) { + return ( + + ); +} + +export { Button, buttonVariants, type ButtonProps }; diff --git a/src/components/animate-ui/icons/icon.tsx b/src/components/animate-ui/icons/icon.tsx new file mode 100644 index 0000000..5e59d2b --- /dev/null +++ b/src/components/animate-ui/icons/icon.tsx @@ -0,0 +1,658 @@ +"use client"; + +import * as React from "react"; +import { + motion, + useAnimation, + type SVGMotionProps, + type UseInViewOptions, + type LegacyAnimationControls, + type Variants, + type HTMLMotionProps, +} from "motion/react"; + +import { cn } from "@/lib/utils"; +import { useIsInView } from "@/hooks/use-is-in-view"; +import { + Slot, + type WithAsChild, +} from "@/components/animate-ui/primitives/animate/slot"; + +const staticAnimations = { + path: { + initial: { pathLength: 1 }, + animate: { + pathLength: [0.05, 1], + transition: { + duration: 0.8, + ease: "easeInOut", + }, + }, + } as Variants, + "path-loop": { + initial: { pathLength: 1 }, + animate: { + pathLength: [1, 0.05, 1], + transition: { + duration: 1.6, + ease: "easeInOut", + }, + }, + } as Variants, +} as const; + +type StaticAnimations = keyof typeof staticAnimations; +type TriggerProp = boolean | StaticAnimations | T; +type Trigger = TriggerProp; + +type AnimateIconContextValue = { + controls: LegacyAnimationControls | undefined; + animation: StaticAnimations | string; + loop: boolean; + loopDelay: number; + active: boolean; + animate?: Trigger; + initialOnAnimateEnd?: boolean; + completeOnStop?: boolean; + persistOnAnimateEnd?: boolean; + delay?: number; +}; + +type DefaultIconProps = { + animate?: TriggerProp; + animateOnHover?: TriggerProp; + animateOnTap?: TriggerProp; + animateOnView?: TriggerProp; + animateOnViewMargin?: UseInViewOptions["margin"]; + animateOnViewOnce?: boolean; + animation?: T | StaticAnimations; + loop?: boolean; + loopDelay?: number; + initialOnAnimateEnd?: boolean; + completeOnStop?: boolean; + persistOnAnimateEnd?: boolean; + delay?: number; +}; + +type AnimateIconProps = WithAsChild< + HTMLMotionProps<"span"> & + DefaultIconProps & { + children: React.ReactNode; + asChild?: boolean; + } +>; + +type IconProps = DefaultIconProps & + Omit, "animate"> & { + size?: number; + }; + +type IconWrapperProps = IconProps & { + icon: React.ComponentType>; +}; + +const AnimateIconContext = React.createContext( + null, +); + +function useAnimateIconContext() { + const context = React.useContext(AnimateIconContext); + if (!context) + return { + controls: undefined, + animation: "default", + loop: undefined, + loopDelay: undefined, + active: undefined, + animate: undefined, + initialOnAnimateEnd: undefined, + completeOnStop: undefined, + persistOnAnimateEnd: undefined, + delay: undefined, + }; + return context; +} + +function composeEventHandlers>( + theirs?: (event: E) => void, + ours?: (event: E) => void, +) { + return (event: E) => { + theirs?.(event); + ours?.(event); + }; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type AnyProps = Record; + +function AnimateIcon({ + asChild = false, + animate = false, + animateOnHover = false, + animateOnTap = false, + animateOnView = false, + animateOnViewMargin = "0px", + animateOnViewOnce = true, + animation = "default", + loop = false, + loopDelay = 0, + initialOnAnimateEnd = false, + completeOnStop = false, + persistOnAnimateEnd = false, + delay = 0, + children, + ...props +}: AnimateIconProps) { + const controls = useAnimation(); + + const [localAnimate, setLocalAnimate] = React.useState(() => { + if (animate === undefined || animate === false) return false; + return delay <= 0; + }); + const [currentAnimation, setCurrentAnimation] = React.useState< + string | StaticAnimations + >(typeof animate === "string" ? animate : animation); + const [status, setStatus] = React.useState<"initial" | "animate">("initial"); + + const delayRef = React.useRef | null>(null); + const loopDelayRef = React.useRef | null>(null); + const isAnimateInProgressRef = React.useRef(false); + const animateEndPromiseRef = React.useRef | null>(null); + const resolveAnimateEndRef = React.useRef<(() => void) | null>(null); + const activeRef = React.useRef(localAnimate); + + const runGenRef = React.useRef(0); + const cancelledRef = React.useRef(false); + + const bumpGeneration = React.useCallback(() => { + runGenRef.current++; + }, []); + + const startAnimation = React.useCallback( + (trigger: TriggerProp) => { + const next = typeof trigger === "string" ? trigger : animation; + bumpGeneration(); + if (delayRef.current) { + clearTimeout(delayRef.current); + delayRef.current = null; + } + setCurrentAnimation(next); + if (delay > 0) { + setLocalAnimate(false); + delayRef.current = setTimeout(() => { + setLocalAnimate(true); + }, delay); + } else { + setLocalAnimate(true); + } + }, + [animation, delay, bumpGeneration], + ); + + const stopAnimation = React.useCallback(() => { + bumpGeneration(); + if (delayRef.current) { + clearTimeout(delayRef.current); + delayRef.current = null; + } + if (loopDelayRef.current) { + clearTimeout(loopDelayRef.current); + loopDelayRef.current = null; + } + setLocalAnimate(false); + }, [bumpGeneration]); + + React.useEffect(() => { + activeRef.current = localAnimate; + }, [localAnimate]); + + React.useEffect(() => { + if (animate === undefined) return; + setCurrentAnimation(typeof animate === "string" ? animate : animation); + if (animate) startAnimation(animate as TriggerProp); + else stopAnimation(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [animate]); + + React.useEffect(() => { + return () => { + if (delayRef.current) clearTimeout(delayRef.current); + if (loopDelayRef.current) clearTimeout(loopDelayRef.current); + }; + }, []); + + const viewOuterRef = React.useRef(null); + const { ref: inViewRef, isInView } = useIsInView(viewOuterRef, { + inView: !!animateOnView, + inViewOnce: animateOnViewOnce, + inViewMargin: animateOnViewMargin, + }); + + const startAnim = React.useCallback( + async (anim: "initial" | "animate", method: "start" | "set" = "start") => { + try { + await controls[method](anim); + setStatus(anim); + } catch { + return; + } + }, + [controls], + ); + + React.useEffect(() => { + if (!animateOnView) return; + if (isInView) startAnimation(animateOnView); + else stopAnimation(); + }, [isInView, animateOnView, startAnimation, stopAnimation]); + + React.useEffect(() => { + const gen = ++runGenRef.current; + cancelledRef.current = false; + + async function run() { + if (cancelledRef.current || gen !== runGenRef.current) { + await startAnim("initial"); + return; + } + + if (!localAnimate) { + if ( + completeOnStop && + isAnimateInProgressRef.current && + animateEndPromiseRef.current + ) { + try { + await animateEndPromiseRef.current; + } catch { + // noop + } + } + if (!persistOnAnimateEnd) { + if (cancelledRef.current || gen !== runGenRef.current) { + await startAnim("initial"); + return; + } + await startAnim("initial"); + } + return; + } + + if (loop) { + if (cancelledRef.current || gen !== runGenRef.current) { + await startAnim("initial"); + return; + } + await startAnim("initial", "set"); + } + + isAnimateInProgressRef.current = true; + animateEndPromiseRef.current = new Promise((resolve) => { + resolveAnimateEndRef.current = resolve; + }); + + if (cancelledRef.current || gen !== runGenRef.current) { + isAnimateInProgressRef.current = false; + resolveAnimateEndRef.current?.(); + resolveAnimateEndRef.current = null; + animateEndPromiseRef.current = null; + await startAnim("initial"); + return; + } + + await startAnim("animate"); + + if (cancelledRef.current || gen !== runGenRef.current) { + isAnimateInProgressRef.current = false; + resolveAnimateEndRef.current?.(); + resolveAnimateEndRef.current = null; + animateEndPromiseRef.current = null; + await startAnim("initial"); + return; + } + + isAnimateInProgressRef.current = false; + resolveAnimateEndRef.current?.(); + resolveAnimateEndRef.current = null; + animateEndPromiseRef.current = null; + + if (initialOnAnimateEnd) { + if (cancelledRef.current || gen !== runGenRef.current) { + await startAnim("initial"); + return; + } + await startAnim("initial", "set"); + } + + if (loop) { + if (loopDelay > 0) { + await new Promise((resolve) => { + loopDelayRef.current = setTimeout(() => { + loopDelayRef.current = null; + resolve(); + }, loopDelay); + }); + + if (cancelledRef.current || gen !== runGenRef.current) { + await startAnim("initial"); + return; + } + if (!activeRef.current) { + if (status !== "initial" && !persistOnAnimateEnd) + await startAnim("initial"); + return; + } + } else { + if (!activeRef.current) { + if (status !== "initial" && !persistOnAnimateEnd) + await startAnim("initial"); + return; + } + } + if (cancelledRef.current || gen !== runGenRef.current) { + await startAnim("initial"); + return; + } + await run(); + } + } + + void run(); + + return () => { + cancelledRef.current = true; + if (delayRef.current) { + clearTimeout(delayRef.current); + delayRef.current = null; + } + if (loopDelayRef.current) { + clearTimeout(loopDelayRef.current); + loopDelayRef.current = null; + } + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [localAnimate, controls]); + + const childProps = ( + React.isValidElement(children) ? (children as React.ReactElement).props : {} + ) as AnyProps; + + const handleMouseEnter = composeEventHandlers>( + childProps.onMouseEnter, + () => { + if (animateOnHover) startAnimation(animateOnHover); + }, + ); + + const handleMouseLeave = composeEventHandlers>( + childProps.onMouseLeave, + () => { + if (animateOnHover || animateOnTap) stopAnimation(); + }, + ); + + const handlePointerDown = composeEventHandlers< + React.PointerEvent + >(childProps.onPointerDown, () => { + if (animateOnTap) startAnimation(animateOnTap); + }); + + const handlePointerUp = composeEventHandlers>( + childProps.onPointerUp, + () => { + if (animateOnTap) stopAnimation(); + }, + ); + + const content = asChild ? ( + + {children} + + ) : ( + + {children} + + ); + + return ( + + {content} + + ); +} + +const pathClassName = + "[&_[stroke-dasharray='1px_1px']]:![stroke-dasharray:1px_0px]"; + +function IconWrapper({ + size = 28, + animation: animationProp, + animate, + animateOnHover, + animateOnTap, + animateOnView, + animateOnViewMargin, + animateOnViewOnce, + icon: IconComponent, + loop, + loopDelay, + persistOnAnimateEnd, + initialOnAnimateEnd, + delay, + completeOnStop, + className, + ...props +}: IconWrapperProps) { + const context = React.useContext(AnimateIconContext); + + if (context) { + const { + controls, + animation: parentAnimation, + loop: parentLoop, + loopDelay: parentLoopDelay, + active: parentActive, + animate: parentAnimate, + persistOnAnimateEnd: parentPersistOnAnimateEnd, + initialOnAnimateEnd: parentInitialOnAnimateEnd, + delay: parentDelay, + completeOnStop: parentCompleteOnStop, + } = context; + + const hasOverrides = + animate !== undefined || + animateOnHover !== undefined || + animateOnTap !== undefined || + animateOnView !== undefined || + loop !== undefined || + loopDelay !== undefined || + initialOnAnimateEnd !== undefined || + persistOnAnimateEnd !== undefined || + delay !== undefined || + completeOnStop !== undefined; + + if (hasOverrides) { + const inheritedAnimate: Trigger = parentActive + ? (animationProp ?? parentAnimation ?? "default") + : false; + + const finalAnimate: Trigger = (animate ?? + parentAnimate ?? + inheritedAnimate) as Trigger; + + return ( + + + + ); + } + + const animationToUse = animationProp ?? parentAnimation; + const loopToUse = parentLoop; + const loopDelayToUse = parentLoopDelay; + + return ( + + + + ); + } + + if ( + animate !== undefined || + animateOnHover !== undefined || + animateOnTap !== undefined || + animateOnView !== undefined || + animationProp !== undefined + ) { + return ( + + + + ); + } + + return ( + + ); +} + +function getVariants< + V extends { default: T; [key: string]: T }, + T extends Record, +>(animations: V): T { + // eslint-disable-next-line react-hooks/rules-of-hooks + const { animation: animationType } = useAnimateIconContext(); + + let result: T; + + if (animationType in staticAnimations) { + const variant = staticAnimations[animationType as StaticAnimations]; + result = {} as T; + for (const key in animations.default) { + if ( + (animationType === "path" || animationType === "path-loop") && + key.includes("group") + ) + continue; + result[key] = variant as T[Extract]; + } + } else { + result = (animations[animationType as keyof V] as T) ?? animations.default; + } + + return result; +} + +export { + pathClassName, + staticAnimations, + AnimateIcon, + IconWrapper, + useAnimateIconContext, + getVariants, + type IconProps, + type IconWrapperProps, + type AnimateIconProps, + type AnimateIconContextValue, +}; diff --git a/src/components/animate-ui/icons/settings.tsx b/src/components/animate-ui/icons/settings.tsx new file mode 100644 index 0000000..cf2c1ae --- /dev/null +++ b/src/components/animate-ui/icons/settings.tsx @@ -0,0 +1,97 @@ +"use client"; + +import * as React from "react"; +import { motion, type Variants } from "motion/react"; + +import { + getVariants, + useAnimateIconContext, + IconWrapper, + type IconProps, +} from "@/components/animate-ui/icons/icon"; + +type SettingsProps = IconProps; + +const animations = { + default: { + group: { + initial: { + rotate: 0, + }, + animate: { + rotate: [0, 90, 180], + transition: { + duration: 1.25, + ease: "easeInOut", + }, + }, + }, + path: {}, + circle: {}, + } satisfies Record, + rotate: { + group: { + initial: { + rotate: 0, + }, + animate: { + rotate: 360, + transition: { + duration: 2, + ease: "linear", + }, + }, + }, + path: {}, + circle: {}, + } satisfies Record, +} as const; + +function IconComponent({ size, ...props }: SettingsProps) { + const { controls } = useAnimateIconContext(); + const variants = getVariants(animations); + + return ( + + + + + + + ); +} + +function Settings(props: SettingsProps) { + return ; +} + +export { + animations, + Settings, + Settings as SettingsIcon, + type SettingsProps, + type SettingsProps as SettingsIconProps, +}; diff --git a/src/components/animate-ui/primitives/animate/slot.tsx b/src/components/animate-ui/primitives/animate/slot.tsx new file mode 100644 index 0000000..4f1973c --- /dev/null +++ b/src/components/animate-ui/primitives/animate/slot.tsx @@ -0,0 +1,97 @@ +"use client"; + +import * as React from "react"; +import { motion, isMotionComponent, type HTMLMotionProps } from "motion/react"; +import { cn } from "@/lib/utils"; + +type AnyProps = Record; + +type DOMMotionProps = Omit< + HTMLMotionProps, + "ref" +> & { ref?: React.Ref }; + +type WithAsChild = + | (Base & { asChild: true; children: React.ReactElement }) + | (Base & { asChild?: false | undefined }); + +type SlotProps = { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + children?: any; +} & DOMMotionProps; + +function mergeRefs( + ...refs: (React.Ref | undefined)[] +): React.RefCallback { + return (node) => { + refs.forEach((ref) => { + if (!ref) return; + if (typeof ref === "function") { + ref(node); + } else { + (ref as React.RefObject).current = node; + } + }); + }; +} + +function mergeProps( + childProps: AnyProps, + slotProps: DOMMotionProps, +): AnyProps { + const merged: AnyProps = { ...childProps, ...slotProps }; + + if (childProps.className || slotProps.className) { + merged.className = cn( + childProps.className as string, + slotProps.className as string, + ); + } + + if (childProps.style || slotProps.style) { + merged.style = { + ...(childProps.style as React.CSSProperties), + ...(slotProps.style as React.CSSProperties), + }; + } + + return merged; +} + +function Slot({ + children, + ref, + ...props +}: SlotProps) { + const isAlreadyMotion = + typeof children.type === "object" && + children.type !== null && + isMotionComponent(children.type); + + const Base = React.useMemo( + () => + isAlreadyMotion + ? (children.type as React.ElementType) + : motion.create(children.type as React.ElementType), + [isAlreadyMotion, children.type], + ); + + if (!React.isValidElement(children)) return null; + + const { ref: childRef, ...childProps } = children.props as AnyProps; + + const mergedProps = mergeProps(childProps, props); + + return ( + //@ts-ignore + , ref)} /> + ); +} + +export { + Slot, + type SlotProps, + type WithAsChild, + type DOMMotionProps, + type AnyProps, +}; diff --git a/src/components/animate-ui/primitives/buttons/button.tsx b/src/components/animate-ui/primitives/buttons/button.tsx new file mode 100644 index 0000000..da70bac --- /dev/null +++ b/src/components/animate-ui/primitives/buttons/button.tsx @@ -0,0 +1,35 @@ +"use client"; + +import * as React from "react"; +import { motion, type HTMLMotionProps } from "motion/react"; + +import { + Slot, + type WithAsChild, +} from "@/components/animate-ui/primitives/animate/slot"; + +type ButtonProps = WithAsChild< + HTMLMotionProps<"button"> & { + hoverScale?: number; + tapScale?: number; + } +>; + +function Button({ + hoverScale = 1.05, + tapScale = 0.95, + asChild = false, + ...props +}: ButtonProps) { + const Component = asChild ? Slot : motion.button; + + return ( + + ); +} + +export { Button, type ButtonProps }; diff --git a/src/components/animate-ui/primitives/radix/radio-group.tsx b/src/components/animate-ui/primitives/radix/radio-group.tsx new file mode 100644 index 0000000..db44838 --- /dev/null +++ b/src/components/animate-ui/primitives/radix/radio-group.tsx @@ -0,0 +1,130 @@ +"use client"; + +import * as React from "react"; +import { RadioGroup as RadioGroupPrimitive } from "radix-ui"; +import { AnimatePresence, motion, type HTMLMotionProps } from "motion/react"; + +import { getStrictContext } from "@/lib/get-strict-context"; +import { useControlledState } from "@/hooks/use-controlled-state"; + +type RadioGroupContextType = { + value: string; + setValue: (value: string) => void; +}; + +type RadioGroupItemContextType = { + isChecked: boolean; + setIsChecked: (isChecked: boolean) => void; +}; + +const [RadioGroupProvider, useRadioGroup] = + getStrictContext("RadioGroupContext"); + +const [RadioGroupItemProvider, useRadioGroupItem] = + getStrictContext("RadioGroupItemContext"); + +type RadioGroupProps = React.ComponentProps; + +function RadioGroup(props: RadioGroupProps) { + const [value, setValue] = useControlledState({ + value: props.value ?? undefined, + defaultValue: props.defaultValue, + onChange: props.onValueChange, + }); + + return ( + + + + ); +} + +type RadioGroupIndicatorProps = Omit< + React.ComponentProps, + "asChild" | "forceMount" +> & + HTMLMotionProps<"div">; + +function RadioGroupIndicator({ + transition = { type: "spring", stiffness: 200, damping: 16 }, + ...props +}: RadioGroupIndicatorProps) { + const { isChecked } = useRadioGroupItem(); + + return ( + + {isChecked && ( + + + + )} + + ); +} + +type RadioGroupItemProps = Omit< + React.ComponentProps, + "asChild" +> & + HTMLMotionProps<"button">; + +function RadioGroupItem({ + value: valueProps, + disabled, + required, + ...props +}: RadioGroupItemProps) { + const { value } = useRadioGroup(); + const [isChecked, setIsChecked] = React.useState(value === valueProps); + + React.useEffect(() => { + setIsChecked(value === valueProps); + }, [value, valueProps]); + + return ( + + + + + + ); +} + +export { + RadioGroup, + RadioGroupItem, + RadioGroupIndicator, + useRadioGroup, + useRadioGroupItem, + type RadioGroupProps, + type RadioGroupItemProps, + type RadioGroupIndicatorProps, + type RadioGroupContextType, + type RadioGroupItemContextType, +}; diff --git a/src/app/consent-manager.tsx b/src/components/consent-manager.tsx similarity index 100% rename from src/app/consent-manager.tsx rename to src/components/consent-manager.tsx diff --git a/src/contexts/CursorToysContext.tsx b/src/contexts/CursorToysContext.tsx new file mode 100644 index 0000000..ef05a8e --- /dev/null +++ b/src/contexts/CursorToysContext.tsx @@ -0,0 +1,44 @@ +"use client"; +import { createContext, useContext, useState, ReactNode } from "react"; + +type SelectedToy = "none" | "spark" | "splash" | "custom" | "target"; + +interface CursorToysContextType { + selectedToy: SelectedToy; + setSelectedToy: (value: SelectedToy) => void; +} + +const CursorToysContext = createContext( + undefined, +); + +export const CursorToysProvider = ({ children }: { children: ReactNode }) => { + const [selectedToy, setSelectedToyState] = useState(() => { + if (typeof window !== "undefined") { + const stored = localStorage.getItem("cursorToy") as SelectedToy; + return stored && + ["none", "spark", "splash", "custom", "target"].includes(stored) + ? stored + : "none"; + } + return "none"; + }); + + const setSelectedToy = (value: SelectedToy) => { + setSelectedToyState(value); + localStorage.setItem("cursorToy", value); + }; + + return ( + + {children} + + ); +}; + +export const useCursorToys = () => { + const context = useContext(CursorToysContext); + if (!context) + throw new Error("useCursorToys must be used within CursorToysProvider"); + return context; +}; diff --git a/src/hooks/use-controlled-state.tsx b/src/hooks/use-controlled-state.tsx new file mode 100644 index 0000000..1417946 --- /dev/null +++ b/src/hooks/use-controlled-state.tsx @@ -0,0 +1,33 @@ +import * as React from "react"; + +interface CommonControlledStateProps { + value?: T; + defaultValue?: T; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function useControlledState( + props: CommonControlledStateProps & { + onChange?: (value: T, ...args: Rest) => void; + }, +): readonly [T, (next: T, ...args: Rest) => void] { + const { value, defaultValue, onChange } = props; + + const [state, setInternalState] = React.useState( + value !== undefined ? value : (defaultValue as T), + ); + + React.useEffect(() => { + if (value !== undefined) setInternalState(value); + }, [value]); + + const setState = React.useCallback( + (next: T, ...args: Rest) => { + setInternalState(next); + onChange?.(next, ...args); + }, + [onChange], + ); + + return [state, setState] as const; +} diff --git a/src/hooks/use-is-in-view.tsx b/src/hooks/use-is-in-view.tsx new file mode 100644 index 0000000..b15a16a --- /dev/null +++ b/src/hooks/use-is-in-view.tsx @@ -0,0 +1,25 @@ +import * as React from "react"; +import { useInView, type UseInViewOptions } from "motion/react"; + +interface UseIsInViewOptions { + inView?: boolean; + inViewOnce?: boolean; + inViewMargin?: UseInViewOptions["margin"]; +} + +function useIsInView( + ref: React.Ref, + options: UseIsInViewOptions = {}, +) { + const { inView, inViewOnce = false, inViewMargin = "0px" } = options; + const localRef = React.useRef(null); + React.useImperativeHandle(ref, () => localRef.current as T); + const inViewResult = useInView(localRef, { + once: inViewOnce, + margin: inViewMargin, + }); + const isInView = !inView || inViewResult; + return { ref: localRef, isInView }; +} + +export { useIsInView, type UseIsInViewOptions }; diff --git a/src/interfaces/CursorToys.ts b/src/interfaces/CursorToys.ts new file mode 100644 index 0000000..117b6df --- /dev/null +++ b/src/interfaces/CursorToys.ts @@ -0,0 +1,6 @@ +import { ReactNode } from "react"; + +export interface ICursorToys { + children?: ReactNode; + selectedToy?: "none" | "spark" | "splash" | "custom" | "target"; +} diff --git a/src/lib/get-strict-context.tsx b/src/lib/get-strict-context.tsx new file mode 100644 index 0000000..7bbe8d1 --- /dev/null +++ b/src/lib/get-strict-context.tsx @@ -0,0 +1,36 @@ +import * as React from "react"; + +function getStrictContext( + name?: string, +): readonly [ + ({ + value, + children, + }: { + value: T; + children?: React.ReactNode; + }) => React.JSX.Element, + () => T, +] { + const Context = React.createContext(undefined); + + const Provider = ({ + value, + children, + }: { + value: T; + children?: React.ReactNode; + }) => {children}; + + const useSafeContext = () => { + const ctx = React.useContext(Context); + if (ctx === undefined) { + throw new Error(`useContext must be used within ${name ?? "a Provider"}`); + } + return ctx; + }; + + return [Provider, useSafeContext] as const; +} + +export { getStrictContext }; diff --git a/tsconfig.json b/tsconfig.json index 5f6ae26..f3c0d66 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,7 @@ { "compilerOptions": { "target": "ES2017", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": false, @@ -34,7 +30,5 @@ "**/*.ts", "**/*.tsx" ], - "exclude": [ - "node_modules" - ] + "exclude": ["node_modules"] } From 10faa413fe07bb973a1a40150f781948d62c9107 Mon Sep 17 00:00:00 2001 From: maamokun Date: Thu, 30 Oct 2025 15:44:52 +0900 Subject: [PATCH 08/10] feat: i18n redirects --- src/public/_redirects | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/public/_redirects diff --git a/src/public/_redirects b/src/public/_redirects new file mode 100644 index 0000000..33d8f1c --- /dev/null +++ b/src/public/_redirects @@ -0,0 +1,23 @@ +# Redirect root to English +/ /en 302 + +# Don't redirect existing locale paths +/en /en 200 +/ja /ja 200 +/en.txt /en.txt 200 +/ja.txt /ja.txt 200 +/en/* /en/:splat 200 +/ja/* /ja/:splat 200 + +# Static assets and special paths that should not be redirected +/_next/* /_next/:splat 200 +/.well-known/* /.well-known/:splat 200 +/img/* /img/:splat 200 +/robots.txt /robots.txt 200 +/ads.txt /ads.txt 200 +/sitemap.xml /sitemap.xml 200 +/sitemap-0.xml /sitemap-0.xml 200 +/favicon.ico /favicon.ico 200 + +# Redirect all other paths to English version +/* /ja/:splat 302 \ No newline at end of file From 4a06599ed2a96ff649c18ec7cbe78320aafcd1a6 Mon Sep 17 00:00:00 2001 From: maamokun Date: Thu, 30 Oct 2025 15:45:04 +0900 Subject: [PATCH 09/10] feat: i18n redirects --- src/public/_redirects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/public/_redirects b/src/public/_redirects index 33d8f1c..e6a59c6 100644 --- a/src/public/_redirects +++ b/src/public/_redirects @@ -20,4 +20,4 @@ /favicon.ico /favicon.ico 200 # Redirect all other paths to English version -/* /ja/:splat 302 \ No newline at end of file +/* /en/:splat 302 \ No newline at end of file From 5636047568e59484b8c148249b9f953ab7695faf Mon Sep 17 00:00:00 2001 From: maamokun Date: Thu, 30 Oct 2025 22:45:15 +0900 Subject: [PATCH 10/10] WIP: homepage --- bun.lock | 6 +- components.json | 3 +- package.json | 2 +- src/app/[locale]/page.tsx | 292 +++++++++++- src/app/[locale]/template.tsx | 4 +- src/components/BubbleMenu.tsx | 430 ++++++++++++++++++ src/components/CustomCursor.tsx | 49 +- src/components/SettingsController.tsx | 25 +- src/components/SpotlightCard.tsx | 71 +++ .../fancy/blocks/marquee-along-svg-path.tsx | 409 +++++++++++++++++ .../fancy/blocks/simple-marquee.tsx | 273 +++++++++++ .../fancy/text/basic-number-ticker.tsx | 107 +++++ .../ui/src/components/ui/button.tsx | 59 +++ src/components/vrm.tsx | 84 +++- src/lib/src/lib/utils.ts | 6 + src/messages/en.json | 62 ++- tsconfig.json | 4 +- 17 files changed, 1854 insertions(+), 32 deletions(-) create mode 100644 src/components/BubbleMenu.tsx create mode 100644 src/components/SpotlightCard.tsx create mode 100644 src/components/fancy/blocks/marquee-along-svg-path.tsx create mode 100644 src/components/fancy/blocks/simple-marquee.tsx create mode 100644 src/components/fancy/text/basic-number-ticker.tsx create mode 100644 src/components/ui/src/components/ui/button.tsx create mode 100644 src/lib/src/lib/utils.ts diff --git a/bun.lock b/bun.lock index 018ab31..a42ebf8 100644 --- a/bun.lock +++ b/bun.lock @@ -36,7 +36,7 @@ "shiki": "^1.24.4", "sonner": "^1.7.1", "tailwind-merge": "^3.3.1", - "tailwind-variants": "^0.3.0", + "tailwind-variants": "^3.1.1", "tailwindcss-animate": "^1.0.7", "three": "^0.180.0", "tw-animate-css": "^1.4.0", @@ -1036,7 +1036,7 @@ "tailwind-merge": ["tailwind-merge@3.3.1", "", {}, "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g=="], - "tailwind-variants": ["tailwind-variants@0.3.1", "", { "dependencies": { "tailwind-merge": "2.5.4" }, "peerDependencies": { "tailwindcss": "*" } }, "sha512-krn67M3FpPwElg4FsZrOQd0U26o7UDH/QOkK8RNaiCCrr052f6YJPBUfNKnPo/s/xRzNPtv1Mldlxsg8Tb46BQ=="], + "tailwind-variants": ["tailwind-variants@3.1.1", "", { "peerDependencies": { "tailwind-merge": ">=3.0.0", "tailwindcss": "*" }, "optionalPeers": ["tailwind-merge"] }, "sha512-ftLXe3krnqkMHsuBTEmaVUXYovXtPyTK7ckEfDRXS8PBZx0bAUas+A0jYxuKA5b8qg++wvQ3d2MQ7l/xeZxbZQ=="], "tailwindcss": ["tailwindcss@4.1.16", "", {}, "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA=="], @@ -1264,8 +1264,6 @@ "swetrix/@types/node": ["@types/node@14.18.63", "", {}, "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ=="], - "tailwind-variants/tailwind-merge": ["tailwind-merge@2.5.4", "", {}, "sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q=="], - "three-stdlib/fflate": ["fflate@0.6.10", "", {}, "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg=="], "tunnel-rat/zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="], diff --git a/components.json b/components.json index c1ada72..48e56a9 100644 --- a/components.json +++ b/components.json @@ -19,6 +19,7 @@ "hooks": "@/hooks" }, "registries": { - "@animate-ui": "https://animate-ui.com/r/{name}.json" + "@animate-ui": "https://animate-ui.com/r/{name}.json", + "@fancy": "https://fancycomponents.dev/r/{name}.json" } } diff --git a/package.json b/package.json index 7ef1adf..1a6e8a3 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "shiki": "^1.24.4", "sonner": "^1.7.1", "tailwind-merge": "^3.3.1", - "tailwind-variants": "^0.3.0", + "tailwind-variants": "^3.1.1", "tailwindcss-animate": "^1.0.7", "three": "^0.180.0", "tw-animate-css": "^1.4.0" diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx index 31d3ff9..a072dcd 100644 --- a/src/app/[locale]/page.tsx +++ b/src/app/[locale]/page.tsx @@ -1,5 +1,20 @@ import { Button } from "@/components/animate-ui/components/buttons/button"; +import SpotlightCard from "@/components/SpotlightCard"; import { setRequestLocale, getTranslations } from "next-intl/server"; +import Image from "next/image"; +import Link from "next/link"; +import NumberTicker from "@/components/fancy/text/basic-number-ticker"; +import Marquee from "@/components/fancy/blocks/simple-marquee"; +import { VRM } from "@/components/vrm"; + +import { TbBrandOpenSource, TbWallet, TbPigMoney } from "react-icons/tb"; + +import mikan from "@/assets/img/mikan.png"; +import HeartMascot from "@/assets/img/MDHeart.png"; +import NeodyLogo from "@/assets/img/NeodyLogo.png"; +import RTLogo from "@/assets/img/rt.png"; +import KuronekoLogo from "@/assets/img/kuroneko.png"; +import TakasumiLogo from "@/assets/img/takasumi.png"; export default async function IndexPage(params: Promise<{ locale: string }>) { const { locale } = await params; @@ -8,8 +23,279 @@ export default async function IndexPage(params: Promise<{ locale: string }>) { const t = await getTranslations("home"); return ( - <> - - +
+
+
+ +
+ +

+ Backed by my own pocket money +

+
+ +
+

+ {t("creating-cool")} +

+
+

+ {t("makeLifeEasier")} +

+

+ {t("mainBlurb1")} +

+

{t("mainBlurb2")}

+
+ + + + + + +
+
+
+ +
+
+ +
+
+

+ {t("infoTitle")} +

+

+ {t("infoBlurb")} +

+
+ +
+
+ {"Mascot + +
+

+ {t("OSSonOSS")} +

+

+ {t("OSSonOSSBlurb")} +

+
+

{t("partOfPage")}

+
+ + + + +
+ + {"Mascot +
+

+ {t("SimpleNCheap")} +

+

+ {t("SimpleNCheapBlurb")} +

+
+ +
+
+

~$

+ +
+ {t("monthlyCost")} +
+
+ +
+
+

0

+
+ {t("MAUBilled")} +
+
+
+

+ {t("despite")} +

+
+ +
+
+ +

+TB

+
+ {t("monthlyBandwidth")} +
+
+ +
+
+ +

+

+
+ {t("mainServices")} +
+
+ +
+
+ +

%

+
+ {t("monthlyUptime")} +
+
+
+ + + + +
+ {"Mikan"} +
+

+ {t("SelfFunded")} +

+

+ {t("SelfFundedBlurb")} +

+ +
+ {"Mascot +
+

+ {t("WorkWithBest")} +

+

+ {t("WorkWithBestBlurb")} +

+ + + + {"Neody"} + + + {"RT"} + + + {"Kuroneko"} + + + {"Takasumi"} + + + + + + + +
+ +

+ {t("NoWait")} +

+

+ {t("NoWaitBlurb")} +

+ + + +
+
+
); } diff --git a/src/app/[locale]/template.tsx b/src/app/[locale]/template.tsx index d79ca9c..07b32d7 100644 --- a/src/app/[locale]/template.tsx +++ b/src/app/[locale]/template.tsx @@ -9,7 +9,9 @@ export default function PagesLayout({ children }: { children: ReactNode }) { return ( - {children} +
+ {children} +
); diff --git a/src/components/BubbleMenu.tsx b/src/components/BubbleMenu.tsx new file mode 100644 index 0000000..0bba8d8 --- /dev/null +++ b/src/components/BubbleMenu.tsx @@ -0,0 +1,430 @@ +import type { CSSProperties, ReactNode } from "react"; +import { useEffect, useRef, useState } from "react"; +import { gsap } from "gsap"; + +type MenuItem = { + label: string; + href: string; + ariaLabel?: string; + rotation?: number; + hoverStyles?: { + bgColor?: string; + textColor?: string; + }; +}; + +export type BubbleMenuProps = { + logo: ReactNode | string; + onMenuClick?: (open: boolean) => void; + className?: string; + style?: CSSProperties; + menuAriaLabel?: string; + menuBg?: string; + menuContentColor?: string; + useFixedPosition?: boolean; + items?: MenuItem[]; + animationEase?: string; + animationDuration?: number; + staggerDelay?: number; +}; + +const DEFAULT_ITEMS: MenuItem[] = [ + { + label: "home", + href: "#", + ariaLabel: "Home", + rotation: -8, + hoverStyles: { bgColor: "#3b82f6", textColor: "#ffffff" }, + }, + { + label: "about", + href: "#", + ariaLabel: "About", + rotation: 8, + hoverStyles: { bgColor: "#10b981", textColor: "#ffffff" }, + }, + { + label: "projects", + href: "#", + ariaLabel: "Documentation", + rotation: 8, + hoverStyles: { bgColor: "#f59e0b", textColor: "#ffffff" }, + }, + { + label: "blog", + href: "#", + ariaLabel: "Blog", + rotation: 8, + hoverStyles: { bgColor: "#ef4444", textColor: "#ffffff" }, + }, + { + label: "contact", + href: "#", + ariaLabel: "Contact", + rotation: -8, + hoverStyles: { bgColor: "#8b5cf6", textColor: "#ffffff" }, + }, +]; + +export default function BubbleMenu({ + logo, + onMenuClick, + className, + style, + menuAriaLabel = "Toggle menu", + menuBg = "#fff", + menuContentColor = "#111", + useFixedPosition = false, + items, + animationEase = "back.out(1.5)", + animationDuration = 0.5, + staggerDelay = 0.12, +}: BubbleMenuProps) { + const [isMenuOpen, setIsMenuOpen] = useState(false); + const [showOverlay, setShowOverlay] = useState(false); + + const overlayRef = useRef(null); + const bubblesRef = useRef([]); + const labelRefs = useRef([]); + + const menuItems = items?.length ? items : DEFAULT_ITEMS; + + const containerClassName = [ + "bubble-menu", + useFixedPosition ? "fixed" : "absolute", + "left-0 right-0 top-8", + "flex items-center justify-between", + "gap-4 px-8", + "pointer-events-none", + "z-[1001]", + className, + ] + .filter(Boolean) + .join(" "); + + const handleToggle = () => { + const nextState = !isMenuOpen; + if (nextState) setShowOverlay(true); + setIsMenuOpen(nextState); + onMenuClick?.(nextState); + }; + + useEffect(() => { + const overlay = overlayRef.current; + const bubbles = bubblesRef.current.filter(Boolean); + const labels = labelRefs.current.filter(Boolean); + if (!overlay || !bubbles.length) return; + + if (isMenuOpen) { + gsap.set(overlay, { display: "flex" }); + gsap.killTweensOf([...bubbles, ...labels]); + gsap.set(bubbles, { scale: 0, transformOrigin: "50% 50%" }); + gsap.set(labels, { y: 24, autoAlpha: 0 }); + + bubbles.forEach((bubble, i) => { + const delay = i * staggerDelay + gsap.utils.random(-0.05, 0.05); + const tl = gsap.timeline({ delay }); + tl.to(bubble, { + scale: 1, + duration: animationDuration, + ease: animationEase, + }); + if (labels[i]) { + tl.to( + labels[i], + { + y: 0, + autoAlpha: 1, + duration: animationDuration, + ease: "power3.out", + }, + "-=" + animationDuration * 0.9, + ); + } + }); + } else if (showOverlay) { + gsap.killTweensOf([...bubbles, ...labels]); + gsap.to(labels, { + y: 24, + autoAlpha: 0, + duration: 0.2, + ease: "power3.in", + }); + gsap.to(bubbles, { + scale: 0, + duration: 0.2, + ease: "power3.in", + onComplete: () => { + gsap.set(overlay, { display: "none" }); + setShowOverlay(false); + }, + }); + } + }, [isMenuOpen, showOverlay, animationEase, animationDuration, staggerDelay]); + + useEffect(() => { + const handleResize = () => { + if (isMenuOpen) { + const bubbles = bubblesRef.current.filter(Boolean); + const isDesktop = window.innerWidth >= 900; + bubbles.forEach((bubble, i) => { + const item = menuItems[i]; + if (bubble && item) { + const rotation = isDesktop ? (item.rotation ?? 0) : 0; + gsap.set(bubble, { rotation }); + } + }); + } + }; + window.addEventListener("resize", handleResize); + return () => window.removeEventListener("resize", handleResize); + }, [isMenuOpen, menuItems]); + + return ( + <> + {/* Workaround for silly Tailwind capabilities */} + + + + + {showOverlay && ( + + )} + + ); +} diff --git a/src/components/CustomCursor.tsx b/src/components/CustomCursor.tsx index a24d352..c70ef6d 100644 --- a/src/components/CustomCursor.tsx +++ b/src/components/CustomCursor.tsx @@ -1,34 +1,61 @@ "use client"; -import { useEffect, useState } from "react"; +import { useEffect, useRef } from "react"; import Mikan from "@/assets/img/mikan.png"; import Image from "next/image"; export default function CustomCursor() { - const [position, setPosition] = useState({ x: 0, y: 0 }); + const cursorRef = useRef(null); useEffect(() => { - document.body.style.cursor = "none"; + // Add a global style to hide cursor on all elements + const styleElement = document.createElement("style"); + styleElement.id = "custom-cursor-style"; + styleElement.innerHTML = `* { cursor: none !important; }`; + document.head.appendChild(styleElement); const handleMouseMove = (e: MouseEvent) => { - setPosition({ x: e.clientX, y: e.clientY }); + if (cursorRef.current) { + // Use requestAnimationFrame for smooth rendering without flickering + requestAnimationFrame(() => { + if (cursorRef.current) { + // Center the cursor on the mouse position + cursorRef.current.style.left = `${e.clientX}px`; + cursorRef.current.style.top = `${e.clientY}px`; + } + }); + } }; - window.addEventListener("mousemove", handleMouseMove); + window.addEventListener("mousemove", handleMouseMove, { passive: true }); return () => { window.removeEventListener("mousemove", handleMouseMove); - document.body.style.cursor = "auto"; + // Remove the global cursor style + const style = document.getElementById("custom-cursor-style"); + if (style) { + style.remove(); + } }; }, []); return ( -
+
Custom Cursor
); diff --git a/src/components/SettingsController.tsx b/src/components/SettingsController.tsx index 217206a..d26215b 100644 --- a/src/components/SettingsController.tsx +++ b/src/components/SettingsController.tsx @@ -59,31 +59,46 @@ export default function SettingsController({ children }: AccButtonProps) {
diff --git a/src/components/SpotlightCard.tsx b/src/components/SpotlightCard.tsx new file mode 100644 index 0000000..9e30e4f --- /dev/null +++ b/src/components/SpotlightCard.tsx @@ -0,0 +1,71 @@ +"use client"; +import React, { useRef, useState } from "react"; + +interface Position { + x: number; + y: number; +} + +interface SpotlightCardProps extends React.PropsWithChildren { + className?: string; + spotlightColor?: `rgba(${number}, ${number}, ${number}, ${number})`; +} + +const SpotlightCard: React.FC = ({ + children, + className = "", + spotlightColor = "rgba(255, 255, 255, 0.25)", +}) => { + const divRef = useRef(null); + const [isFocused, setIsFocused] = useState(false); + const [position, setPosition] = useState({ x: 0, y: 0 }); + const [opacity, setOpacity] = useState(0); + + const handleMouseMove: React.MouseEventHandler = (e) => { + if (!divRef.current || isFocused) return; + + const rect = divRef.current.getBoundingClientRect(); + setPosition({ x: e.clientX - rect.left, y: e.clientY - rect.top }); + }; + + const handleFocus = () => { + setIsFocused(true); + setOpacity(0.6); + }; + + const handleBlur = () => { + setIsFocused(false); + setOpacity(0); + }; + + const handleMouseEnter = () => { + setOpacity(0.6); + }; + + const handleMouseLeave = () => { + setOpacity(0); + }; + + return ( +
+
+ {children} +
+ ); +}; + +export default SpotlightCard; diff --git a/src/components/fancy/blocks/marquee-along-svg-path.tsx b/src/components/fancy/blocks/marquee-along-svg-path.tsx new file mode 100644 index 0000000..bca00c5 --- /dev/null +++ b/src/components/fancy/blocks/marquee-along-svg-path.tsx @@ -0,0 +1,409 @@ +import React, { RefObject, useCallback, useEffect, useRef } from "react"; +import { + motion, + SpringOptions, + useAnimationFrame, + useMotionValue, + useScroll, + useSpring, + useTransform, + useVelocity, +} from "motion/react"; + +import { cn } from "@/lib/utils"; + +// Custom wrap function +const wrap = (min: number, max: number, value: number): number => { + const range = max - min; + return ((((value - min) % range) + range) % range) + min; +}; + +type PreserveAspectRatioAlign = + | "none" + | "xMinYMin" + | "xMidYMin" + | "xMaxYMin" + | "xMinYMid" + | "xMidYMid" + | "xMaxYMid" + | "xMinYMax" + | "xMidYMax" + | "xMaxYMax"; + +interface CSSVariableInterpolation { + property: string; + from: number | string; + to: number | string; +} + +type PreserveAspectRatioMeetOrSlice = "meet" | "slice"; + +type PreserveAspectRatio = + | PreserveAspectRatioAlign + | `${Exclude} ${PreserveAspectRatioMeetOrSlice}`; + +interface MarqueeAlongSvgPathProps { + children: React.ReactNode; + className?: string; + + // Path properties + path: string; + pathId?: string; + preserveAspectRatio?: PreserveAspectRatio; + showPath?: boolean; + + // SVG properties + width?: string | number; + height?: string | number; + viewBox?: string; + + // Marquee properties + baseVelocity?: number; + direction?: "normal" | "reverse"; + easing?: (value: number) => number; + slowdownOnHover?: boolean; + slowDownFactor?: number; + slowDownSpringConfig?: SpringOptions; + + // Scroll properties + useScrollVelocity?: boolean; + scrollAwareDirection?: boolean; + scrollSpringConfig?: SpringOptions; + scrollContainer?: RefObject | HTMLElement | null; + + // Item repetition + repeat?: number; + + // Drag properties + draggable?: boolean; + dragSensitivity?: number; + dragVelocityDecay?: number; + dragAwareDirection?: boolean; + grabCursor?: boolean; + + // Z-index properties + enableRollingZIndex?: boolean; + zIndexBase?: number; + zIndexRange?: number; + + cssVariableInterpolation?: CSSVariableInterpolation[]; +} + +const MarqueeAlongSvgPath = ({ + children, + className, + + // Path defaults + path, + pathId, + preserveAspectRatio = "xMidYMid meet", + showPath = false, + + // SVG defaults + width = "100%", + height = "100%", + viewBox = "0 0 100 100", + + // Marquee defaults + baseVelocity = 5, + direction = "normal", + easing, + slowdownOnHover = false, + slowDownFactor = 0.3, + slowDownSpringConfig = { damping: 50, stiffness: 400 }, + + // Scroll defaults + useScrollVelocity = false, + scrollAwareDirection = false, + scrollSpringConfig = { damping: 50, stiffness: 400 }, + scrollContainer, + + // Items repetition + repeat = 3, + + // Drag defaults + draggable = false, + dragSensitivity = 0.2, + dragVelocityDecay = 0.96, + dragAwareDirection = false, + grabCursor = false, + + // Z-index defaults + enableRollingZIndex = true, + zIndexBase = 1, // Base z-index value + zIndexRange = 10, // Range of z-index values to use + + cssVariableInterpolation = [], +}: MarqueeAlongSvgPathProps) => { + const container = useRef(null); + const baseOffset = useMotionValue(0); + + const pathRef = useRef(null); + + const itemRefs = useRef>(new Map()); + + // Create an array of items outside of the render function + const items = React.useMemo(() => { + const childrenArray = React.Children.toArray(children); + + return childrenArray.flatMap((child, childIndex) => + Array.from({ length: repeat }, (_, repeatIndex) => { + const itemIndex = repeatIndex * childrenArray.length + childIndex; + const key = `${childIndex}-${repeatIndex}`; + return { + child, + childIndex, + repeatIndex, + itemIndex, + key, + }; + }), + ); + }, [children, repeat]); + + // Function to calculate z-index based on offset distance + const calculateZIndex = useCallback( + (offsetDistance: number) => { + if (!enableRollingZIndex) { + return undefined; + } + + // Simple progress-based z-index + const normalizedDistance = offsetDistance / 100; + return Math.floor(zIndexBase + normalizedDistance * zIndexRange); + }, + [enableRollingZIndex, zIndexBase, zIndexRange], + ); + + // Generate a random ID for the path if not provided + const id = + pathId || `marquee-path-${Math.random().toString(36).substring(7)}`; + + // Scroll tracking + const { scrollY } = useScroll({ + container: + (scrollContainer as RefObject) || container, + }); + + const scrollVelocity = useVelocity(scrollY); + const smoothVelocity = useSpring(scrollVelocity, scrollSpringConfig); + + // Hover and drag state tracking + const isHovered = useRef(false); + const isDragging = useRef(false); + const dragVelocity = useRef(0); + + // Direction factor for changing direction based on scroll or drag + const directionFactor = useRef(direction === "normal" ? 1 : -1); + + // Motion values for animation + const hoverFactorValue = useMotionValue(1); + const defaultVelocity = useMotionValue(1); + const smoothHoverFactor = useSpring(hoverFactorValue, slowDownSpringConfig); + + // Transform scroll velocity into a factor that affects marquee speed + const velocityFactor = useTransform( + useScrollVelocity ? smoothVelocity : defaultVelocity, + [0, 1000], + [0, 5], + { clamp: false }, + ); + + // Animation frame handler + useAnimationFrame((_, delta) => { + if (isDragging.current && draggable) { + baseOffset.set(baseOffset.get() + dragVelocity.current); + + // Add decay to dragVelocity + dragVelocity.current *= 0.9; + + // Stop completely if velocity is very small + if (Math.abs(dragVelocity.current) < 0.01) { + dragVelocity.current = 0; + } + + return; + } + + // Update hover factor + if (isHovered.current) { + hoverFactorValue.set(slowdownOnHover ? slowDownFactor : 1); + } else { + hoverFactorValue.set(1); + } + + // Calculate regular movement + let moveBy = + directionFactor.current * + baseVelocity * + (delta / 1000) * + smoothHoverFactor.get(); + + // Adjust movement based on scroll velocity if scrollAwareDirection is enabled + if (scrollAwareDirection && !isDragging.current) { + if (velocityFactor.get() < 0) { + directionFactor.current = -1; + } else if (velocityFactor.get() > 0) { + directionFactor.current = 1; + } + } + + moveBy += directionFactor.current * moveBy * velocityFactor.get(); + + if (draggable) { + moveBy += dragVelocity.current; + + // Update direction based on drag direction if dragAwareDirection is true + if (dragAwareDirection && Math.abs(dragVelocity.current) > 0.1) { + directionFactor.current = Math.sign(dragVelocity.current); + } + + // Gradually decay drag velocity back to zero + if (!isDragging.current && Math.abs(dragVelocity.current) > 0.01) { + dragVelocity.current *= dragVelocityDecay; + } else if (!isDragging.current) { + dragVelocity.current = 0; + } + } + + baseOffset.set(baseOffset.get() + moveBy); + }); + + // Pointer event handlers for dragging + const lastPointerPosition = useRef({ x: 0, y: 0 }); + + const handlePointerDown = (e: React.PointerEvent) => { + if (!draggable) return; + (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId); + + if (grabCursor) { + (e.currentTarget as HTMLElement).style.cursor = "grabbing"; + } + + isDragging.current = true; + lastPointerPosition.current = { x: e.clientX, y: e.clientY }; + + // Pause automatic animation by setting velocity to 0 + dragVelocity.current = 0; + }; + + const handlePointerMove = (e: React.PointerEvent) => { + if (!draggable || !isDragging.current) return; + + const currentPosition = { x: e.clientX, y: e.clientY }; + + // Calculate movement delta - simplified for path movement + const deltaX = currentPosition.x - lastPointerPosition.current.x; + const deltaY = currentPosition.y - lastPointerPosition.current.y; + + // For path following, we use a simple magnitude of movement + const delta = Math.sqrt(deltaX * deltaX + deltaY * deltaY); + const projectedDelta = deltaX > 0 ? delta : -delta; + + // Update drag velocity based on the projected movement + dragVelocity.current = projectedDelta * dragSensitivity; + + // Update last position + lastPointerPosition.current = currentPosition; + }; + + const handlePointerUp = (e: React.PointerEvent) => { + if (!draggable) return; + (e.currentTarget as HTMLElement).releasePointerCapture(e.pointerId); + isDragging.current = false; + + if (grabCursor) { + (e.currentTarget as HTMLElement).style.cursor = "grab"; + } + }; + + return ( +
+ + + + + {items.map(({ child, repeatIndex, itemIndex, key }) => { + // Create a unique offset transform for each item + const itemOffset = useTransform(baseOffset, (v) => { + const position = (itemIndex * 100) / items.length; + const wrappedValue = wrap(0, 100, v + position); + return `${easing ? easing(wrappedValue / 100) * 100 : wrappedValue}%`; + }); + + // Create a motion value for the current offset distance + const currentOffsetDistance = useMotionValue(0); + + // Update z-index when offset distance changes + const zIndex = useTransform(currentOffsetDistance, (value) => + calculateZIndex(value), + ); + + // Update current offset distance value when animation runs + useEffect(() => { + const unsubscribe = itemOffset.on("change", (value: string) => { + // Parse percentage string to get numerical value + const match = value.match(/^([\d.]+)%$/); + if (match && match[1]) { + currentOffsetDistance.set(parseFloat(match[1])); + } + }); + return unsubscribe; + }, [itemOffset, currentOffsetDistance]); + + const cssVariables = Object.fromEntries( + (cssVariableInterpolation || []).map(({ property, from, to }) => [ + property, + useTransform(currentOffsetDistance, [0, 100], [from, to]), + ]), + ); + + return ( + { + if (el) itemRefs.current.set(key, el); + }} + className={cn( + "absolute top-0 left-0", + draggable && grabCursor && "cursor-grab", + )} + style={{ + offsetPath: `path('${path}')`, + offsetDistance: itemOffset, + zIndex: enableRollingZIndex ? zIndex : undefined, + ...cssVariables, + }} + aria-hidden={repeatIndex > 0} + onMouseEnter={() => (isHovered.current = true)} + onMouseLeave={() => (isHovered.current = false)} + > + {child} + + ); + })} +
+ ); +}; + +export default MarqueeAlongSvgPath; diff --git a/src/components/fancy/blocks/simple-marquee.tsx b/src/components/fancy/blocks/simple-marquee.tsx new file mode 100644 index 0000000..a074bed --- /dev/null +++ b/src/components/fancy/blocks/simple-marquee.tsx @@ -0,0 +1,273 @@ +"use client"; +import { RefObject, useRef } from "react"; +import { + motion, + SpringOptions, + useAnimationFrame, + useMotionValue, + useScroll, + useSpring, + useTransform, + useVelocity, +} from "motion/react"; + +import { cn } from "@/lib/utils"; + +// Custom wrap function +const wrap = (min: number, max: number, value: number): number => { + const range = max - min; + return ((((value - min) % range) + range) % range) + min; +}; + +interface SimpleMarqueeProps { + children: React.ReactNode; // The elements to be scrolled + className?: string; // Additional CSS classes for the container + direction?: "left" | "right" | "up" | "down"; // The direction of the marquee + baseVelocity?: number; // The base velocity of the marquee in pixels per second + easing?: (value: number) => number; // The easing function for the animation + slowdownOnHover?: boolean; // Whether to slow down the animation on hover + slowDownFactor?: number; // The factor to slow down the animation on hover + slowDownSpringConfig?: SpringOptions; // The spring config for the slow down animation + useScrollVelocity?: boolean; // Whether to use the scroll velocity to control the marquee speed + scrollAwareDirection?: boolean; // Whether to adjust the direction based on the scroll direction + scrollSpringConfig?: SpringOptions; // The spring config for the scroll velocity-based direction adjustment + scrollContainer?: RefObject | HTMLElement | null; // The container to use for the scroll velocity + repeat?: number; // The number of times to repeat the children. + draggable?: boolean; // Whether to allow dragging of the marquee + dragSensitivity?: number; // The sensitivity of the drag movement + dragVelocityDecay?: number; // The decay of the drag velocity. This means how fast the velocity will gradually reduce to baseVelocity when we release the drag + dragAwareDirection?: boolean; // Whether to adjust the direction based on the drag velocity + dragAngle?: number; // The angle of the drag movement in degrees. This is useful if you eg. rotating your marquee by 45 degrees + grabCursor?: boolean; // Whether to change the cursor to grabbing when dragging +} + +const SimpleMarquee = ({ + children, + className, + direction = "right", + baseVelocity = 5, + slowdownOnHover = false, + slowDownFactor = 0.3, + slowDownSpringConfig = { damping: 50, stiffness: 400 }, + useScrollVelocity = false, + scrollAwareDirection = false, + scrollSpringConfig = { damping: 50, stiffness: 400 }, + scrollContainer, + repeat = 3, + draggable = false, + dragSensitivity = 0.2, + dragVelocityDecay = 0.96, + dragAwareDirection = false, + dragAngle = 0, + grabCursor = false, + easing, +}: SimpleMarqueeProps) => { + const baseX = useMotionValue(0); + const baseY = useMotionValue(0); + + const { scrollY } = useScroll({ + ...(scrollContainer && { + container: scrollContainer as RefObject, + }), + }); + + const scrollVelocity = useVelocity(scrollY); + const smoothVelocity = useSpring(scrollVelocity, scrollSpringConfig); + + const hoverFactorValue = useMotionValue(1); + const defaultVelocity = useMotionValue(1); + + // Track if user is currently dragging + const isDragging = useRef(false); + + // Store drag velocity + const dragVelocity = useRef(0); + + const smoothHoverFactor = useSpring(hoverFactorValue, slowDownSpringConfig); + + // Transform scroll velocity into a factor that affects marquee speed + const velocityFactor = useTransform( + useScrollVelocity ? smoothVelocity : defaultVelocity, + [0, 1000], + [0, 5], + { + clamp: false, + }, + ); + + // Determine if movement is horizontal or vertical. + const isHorizontal = direction === "left" || direction === "right"; + + // Convert baseVelocity to the correct direction + const actualBaseVelocity = + direction === "left" || direction === "up" ? -baseVelocity : baseVelocity; + + // Reference to track if mouse is hovering + const isHovered = useRef(false); + + // Direction factor for changing direction based on scroll or drag + const directionFactor = useRef(1); + + // Transform baseX/baseY into a percentage for the transform + // The wrap function ensures the value stays between 0 and -100 + const x = useTransform(baseX, (v) => { + // Apply easing if provided, otherwise use linear (v directly) + const wrappedValue = wrap(0, -100, v); + return `${easing ? easing(wrappedValue / -100) * -100 : wrappedValue}%`; + }); + const y = useTransform(baseY, (v) => { + // Apply easing if provided, otherwise use linear (v directly) + const wrappedValue = wrap(0, -100, v); + return `${easing ? easing(wrappedValue / -100) * -100 : wrappedValue}%`; + }); + + useAnimationFrame((t, delta) => { + if (isDragging.current && draggable) { + if (isHorizontal) { + baseX.set(baseX.get() + dragVelocity.current); + } else { + baseY.set(baseY.get() + dragVelocity.current); + } + + // Add decay to dragVelocity when not moving + // This will gradually reduce the velocity to zero when the pointer isn't moving + dragVelocity.current *= 0.9; + + // Stop completely if velocity is very small + if (Math.abs(dragVelocity.current) < 0.01) { + dragVelocity.current = 0; + } + + return; + } + + // Update hover factor + if (isHovered.current) { + hoverFactorValue.set(slowdownOnHover ? slowDownFactor : 1); + } else { + hoverFactorValue.set(1); + } + + // Calculate regular movement + let moveBy = + directionFactor.current * + actualBaseVelocity * + (delta / 1000) * + smoothHoverFactor.get(); + + // Adjust movement based on scroll velocity if scrollAwareDirection is enabled + if (scrollAwareDirection && !isDragging.current) { + if (velocityFactor.get() < 0) { + directionFactor.current = -1; + } else if (velocityFactor.get() > 0) { + directionFactor.current = 1; + } + } + + moveBy += directionFactor.current * moveBy * velocityFactor.get(); + + if (draggable) { + moveBy += dragVelocity.current; + + // Update direction based on drag direction if dragAwareDirection is true + if (dragAwareDirection && Math.abs(dragVelocity.current) > 0.1) { + // If dragging in negative direction, set directionFactor to -1 + // If dragging in positive direction, set directionFactor to 1 + directionFactor.current = Math.sign(dragVelocity.current); + } + + // Gradually decay drag velocity back to zero + if (!isDragging.current && Math.abs(dragVelocity.current) > 0.01) { + dragVelocity.current *= dragVelocityDecay; + } else if (!isDragging.current) { + dragVelocity.current = 0; + } + } + + if (isHorizontal) { + baseX.set(baseX.get() + moveBy); + } else { + baseY.set(baseY.get() + moveBy); + } + }); + + const lastPointerPosition = useRef({ x: 0, y: 0 }); + + const handlePointerDown = (e: React.PointerEvent) => { + if (!draggable) return; // Capture the pointer to receive events even when pointer moves outside + (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId); + + if (grabCursor) { + (e.currentTarget as HTMLElement).style.cursor = "grabbing"; + } + + isDragging.current = true; + lastPointerPosition.current = { x: e.clientX, y: e.clientY }; + + // Pause automatic animation by setting velocity to 0 + dragVelocity.current = 0; + }; + + const handlePointerMove = (e: React.PointerEvent) => { + if (!draggable || !isDragging.current) return; + + const currentPosition = { x: e.clientX, y: e.clientY }; + + // Calculate delta from last position + const deltaX = currentPosition.x - lastPointerPosition.current.x; + const deltaY = currentPosition.y - lastPointerPosition.current.y; + + // Convert dragAngle from degrees to radians + const angleInRadians = (dragAngle * Math.PI) / 180; + + // Calculate the projection of the movement along the angle direction + // Using the dot product of the movement vector and the direction vector + const directionX = Math.cos(angleInRadians); + const directionY = Math.sin(angleInRadians); + + // Project the movement onto the angle direction + const projectedDelta = deltaX * directionX + deltaY * directionY; + + // Update drag velocity based on the projected movement + dragVelocity.current = projectedDelta * dragSensitivity; + + // Update last position + lastPointerPosition.current = currentPosition; + }; + + const handlePointerUp = (e: React.PointerEvent) => { + if (!draggable) return; // Release pointer capture + (e.currentTarget as HTMLElement).releasePointerCapture(e.pointerId); + + isDragging.current = false; + }; + + return ( + (isHovered.current = true)} + onHoverEnd={() => (isHovered.current = false)} + onPointerDown={handlePointerDown} + onPointerMove={handlePointerMove} + onPointerUp={handlePointerUp} + onPointerCancel={handlePointerUp} + > + {Array.from({ length: repeat }, (_, i) => i).map((i) => ( + 0} + > + {children} + + ))} + + ); +}; + +export default SimpleMarquee; diff --git a/src/components/fancy/text/basic-number-ticker.tsx b/src/components/fancy/text/basic-number-ticker.tsx new file mode 100644 index 0000000..e3779c4 --- /dev/null +++ b/src/components/fancy/text/basic-number-ticker.tsx @@ -0,0 +1,107 @@ +"use client"; + +import { + forwardRef, + useCallback, + useEffect, + useImperativeHandle, + useState, +} from "react"; +import { + animate, + AnimationPlaybackControls, + motion, + useMotionValue, + useTransform, + ValueAnimationTransition, +} from "motion/react"; + +import { cn } from "@/lib/utils"; + +interface NumberTickerProps { + from: number; // Starting value of the animation + target: number; // End value of the animation + transition?: ValueAnimationTransition; // Animation configuration, refer to motion docs for more details + className?: string; // additionl CSS classes for styling + onStart?: () => void; // Callback function when animation starts + onComplete?: () => void; // Callback function when animation completes + autoStart?: boolean; // Whether to start the animation automatically +} + +// Ref interface to allow external control of the animation +export interface NumberTickerRef { + startAnimation: () => void; +} + +const NumberTicker = forwardRef( + ( + { + from = 0, + target = 100, + transition = { + duration: 3, + type: "tween", + ease: "easeInOut", + }, + className, + onStart, + onComplete, + autoStart = true, + ...props + }, + ref, + ) => { + const count = useMotionValue(from); + const rounded = useTransform(count, (latest) => Math.round(latest)); + const [controls, setControls] = useState( + null, + ); + + // Function to start the animation + const startAnimation = useCallback(() => { + if (controls) controls.stop(); + onStart?.(); + + count.set(from); + + const newControls = animate(count, target, { + ...transition, + onComplete: () => { + onComplete?.(); + }, + }); + setControls(newControls); + }, []); + + // Expose the startAnimation function via ref + useImperativeHandle(ref, () => ({ + startAnimation, + })); + + useEffect(() => { + if (autoStart) { + startAnimation(); + } + return () => controls?.stop(); + }, [autoStart]); + + return ( + + {rounded} + + ); + }, +); + +NumberTicker.displayName = "NumberTicker"; + +export default NumberTicker; + +// Usage example: +// To start the animation from outside the component: +// 1. Create a ref: +// const tickerRef = useRef(null); +// 2. Pass the ref to the NumberTicker component: +// +// 3. Call the startAnimation function: +// tickerRef.current?.startAnimation(); diff --git a/src/components/ui/src/components/ui/button.tsx b/src/components/ui/src/components/ui/button.tsx new file mode 100644 index 0000000..2adaf00 --- /dev/null +++ b/src/components/ui/src/components/ui/button.tsx @@ -0,0 +1,59 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", + destructive: + "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", + ghost: + "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2 has-[>svg]:px-3", + sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", + lg: "h-10 rounded-md px-6 has-[>svg]:px-4", + icon: "size-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +); + +function Button({ + className, + variant, + size, + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean; + }) { + const Comp = asChild ? Slot : "button"; + + return ( + + ); +} + +export { Button, buttonVariants }; diff --git a/src/components/vrm.tsx b/src/components/vrm.tsx index d977917..3d525a5 100644 --- a/src/components/vrm.tsx +++ b/src/components/vrm.tsx @@ -44,7 +44,9 @@ const animations = [ export const VRMModel: FC<{ vrm: import("@pixiv/three-vrm").VRM | null; mixer: AnimationMixer | null; -}> = ({ vrm, mixer }) => { + enableLookAt: boolean; + mousePosition: { x: number; y: number }; +}> = ({ vrm, mixer, enableLookAt, mousePosition }) => { useFrame(({ clock }, delta) => { if (vrm) { vrm.scene.position.set(0, -4.2, 0); @@ -52,6 +54,35 @@ export const VRMModel: FC<{ vrm.scene.rotation.y = Math.PI; vrm.expressionManager?.setValue("neutral", 1); + // Enable eye tracking if animation is done + if (enableLookAt && vrm.lookAt) { + // Convert mouse position to 3D world coordinates + const target = { + x: mousePosition.x * 2, + y: mousePosition.y * 2 + 0.5, + z: 2, + }; + // Use the lookAt method to set the target position + try { + //@ts-ignore + vrm.lookAt.lookAt(target); + } catch (error) { + // Silently handle if lookAt is not available + } + + // Also rotate the head slightly to match + const headBone = vrm.humanoid.getNormalizedBoneNode("head"); + if (headBone) { + // Apply subtle head rotation based on mouse position + const headRotationX = mousePosition.y * 0.3; // Up/down + const headRotationY = mousePosition.x * 0.3; // Left/right + + // Smoothly interpolate to the target rotation + headBone.rotation.x += (headRotationX - headBone.rotation.x) * 0.1; + headBone.rotation.y += (headRotationY - headBone.rotation.y) * 0.1; + } + } + vrm.update(delta); } if (mixer) { @@ -66,7 +97,34 @@ export function VRM() { const [vrm, setVrm] = useState(null); const [mixer, setMixer] = useState(null); const [isLoaded, setIsLoaded] = useState(false); + const [enableLookAt, setEnableLookAt] = useState(false); + const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 }); const actionRef = useRef(null); + const isLoopingRef = useRef(false); + const containerRef = useRef(null); + + // Global mouse tracking + useEffect(() => { + const handleGlobalMouseMove = (e: MouseEvent) => { + if (!containerRef.current) return; + + const rect = containerRef.current.getBoundingClientRect(); + const centerX = rect.left + rect.width / 2; + const centerY = rect.top + rect.height / 2; + + // Calculate normalized position relative to the container center + const x = (e.clientX - centerX) / rect.width; + const y = -(e.clientY - centerY) / rect.height; + + setMousePosition({ x, y }); + }; + + window.addEventListener("mousemove", handleGlobalMouseMove); + + return () => { + window.removeEventListener("mousemove", handleGlobalMouseMove); + }; + }, []); useEffect(() => { const loader = new GLTFLoader(); @@ -104,6 +162,7 @@ export function VRM() { const loadAnimation = (loadedVrm: import("@pixiv/three-vrm").VRM) => { const { url, loop } = pickAnimation(); + isLoopingRef.current = loop; loader.load( url, @@ -123,6 +182,11 @@ export function VRM() { } else { action.setLoop(LoopOnce, 1); action.clampWhenFinished = true; + + // Enable eye tracking when animation finishes + animationMixer.addEventListener("finished", () => { + setEnableLookAt(true); + }); } action.play(); @@ -155,7 +219,10 @@ export function VRM() { return (
-
+
{!isLoaded ? (
@@ -167,8 +234,13 @@ export function VRM() { className={"block w-full h-full"} > - - + + )} @@ -194,6 +266,10 @@ export function VRM() { actionRef.current.reset(); actionRef.current.paused = false; actionRef.current.play(); + // Disable look-at when restarting animation + if (!isLoopingRef.current) { + setEnableLookAt(false); + } } }} > diff --git a/src/lib/src/lib/utils.ts b/src/lib/src/lib/utils.ts new file mode 100644 index 0000000..a5ef193 --- /dev/null +++ b/src/lib/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/src/messages/en.json b/src/messages/en.json index bdaf2be..cdb8f8a 100644 --- a/src/messages/en.json +++ b/src/messages/en.json @@ -1,5 +1,65 @@ { "home": { - "hi": "Hello" + "creating-cool": "Creating cool", + "makeLifeEasier": "to make life easier.", + "stuff": "stuff", + "apps": "Apps", + "tools": "Tools", + "bots": "Bots", + "mainBlurb1": "We create open-source solutions for those itches in life that need scratching.", + "mainBlurb2": "Enrich your life without breaking the bank.", + "takeLook": "Take a look", + "learnMore": "Learn More", + "infoTitle": "what makes us special", + "infoBlurb": "The MikanDev Difference", + "OSSonOSS": "Open Source with Open Source", + "OSSonOSSBlurb": "We believe in the power of open source. All of our projects are free to self-host, modify and contribute to. Any third-party services we use are also open source.", + "partOfPage": "the very page you're reading is open source!", + "viewOnGH": "View on GitHub", + "SimpleNCheap": "Designed with simplicity for ultimate cost-effectiveness", + "SimpleNCheapBlurb": "We don't believe in overcomplicating things. Our projects are designed to be simple to use, and aren't held up by expensive third-party services. The savings are passed on to you!", + "monthlyCost": "Avg. Monthly running cost", + "MAUBilled": "MAU billed services used", + "despite": "Despite...", + "monthlyBandwidth": "Avg. Monthly bandwidth usage", + "mainServices": "Main services", + "monthlyUptime": "Avg. Monthly uptime", + "HowSoCheap": "How so cheap?", + "SelfFunded": "100% Self-funded", + "SelfFundedBlurb": "We don't have any investors or VC to answer to, so we can decide when we make a profit. We're here to make cool stuff, not money.", + "WorkWithBest": "Working with the best", + "WorkWithBestBlurb": "We partner with other cool organizations and help get their cool stuff out there. We're all about the community :3", + "workWithMe": "Work with us!", + "NoWait": "What's more to say?", + "NoWaitBlurb": "Check out our projects and see if there's something you like!" + }, + "nav": { + "support": "Support", + "docs": "Docs", + "solutions": "Solutions", + "legal": "Legal", + "payments": "Payment Center", + "blog": "Blog", + "discord": "Discord", + "contact": "Contact Us", + "terms": "Terms of Service", + "privacy": "Privacy Policy", + "jp-payments": "特定商取引法に基づく表記", + "gdpr": "GDPR Compliance", + "myAccount": "My Account", + "resources": "Resources", + "cookieConsent": "We use cookies for analytics and making stuff work. By clicking 'mmmmmmm cookies 🍪', you agree to our use of cookies.", + "accept": "mmmmmmm cookies 🍪" + }, + "contact": { + "title": "Contact Us", + "mail": "Email", + "phone": "Phone (JP Only)*", + "discord": "Discord", + "join": "Join our Discord", + "general-support": "General Support", + "billing-support": "Billing Support", + "abuse-reports": "Abuse Reports", + "phone-disclaimer": "*Calling this number from outside of Japan may result in high charges. Please use the email or Discord for support." } } diff --git a/tsconfig.json b/tsconfig.json index f3c0d66..0ba7d3f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -28,7 +28,9 @@ ".next/dev/types/**/*.ts", "**/*.mts", "**/*.ts", - "**/*.tsx" + "**/*.tsx", + ".next\\dev/types/**/*.ts", + ".next\\dev/types/**/*.ts" ], "exclude": ["node_modules"] }