From ba98783058fff5525984cfc2912eff1bf500ca94 Mon Sep 17 00:00:00 2001 From: C4 Patino Date: Sun, 24 Nov 2024 21:05:09 -0600 Subject: [PATCH] All components mostly created and basic UI initialized --- components.json | 21 + package.json | 45 +- pnpm-lock.yaml | 811 +++++++++++++++++++++--- src/app/@modal/(.)timer/[id]/modal.tsx | 24 + src/app/@modal/(.)timer/[id]/page.tsx | 17 + src/app/@modal/default.tsx | 3 + src/app/_components/full-page-timer.tsx | 75 +++ src/app/_components/navigation.tsx | 25 + src/app/_components/timer.tsx | 93 +++ src/app/api/timer/[id]/route.ts | 22 + src/app/layout.tsx | 26 +- src/app/page.tsx | 71 ++- src/app/timer/[id]/page.tsx | 12 + src/components/ui/avatar.tsx | 50 ++ src/components/ui/card.tsx | 76 +++ src/components/ui/dialog.tsx | 122 ++++ src/components/ui/navigation-menu.tsx | 128 ++++ src/lib/utils.ts | 6 + src/server/db/schema.ts | 36 +- src/server/queries.ts | 39 ++ src/styles/globals.css | 68 ++ tailwind.config.ts | 50 +- 22 files changed, 1662 insertions(+), 158 deletions(-) create mode 100644 components.json create mode 100644 src/app/@modal/(.)timer/[id]/modal.tsx create mode 100644 src/app/@modal/(.)timer/[id]/page.tsx create mode 100644 src/app/@modal/default.tsx create mode 100644 src/app/_components/full-page-timer.tsx create mode 100644 src/app/_components/navigation.tsx create mode 100644 src/app/_components/timer.tsx create mode 100644 src/app/api/timer/[id]/route.ts create mode 100644 src/app/timer/[id]/page.tsx create mode 100644 src/components/ui/avatar.tsx create mode 100644 src/components/ui/card.tsx create mode 100644 src/components/ui/dialog.tsx create mode 100644 src/components/ui/navigation-menu.tsx create mode 100644 src/lib/utils.ts create mode 100644 src/server/queries.ts diff --git a/components.json b/components.json new file mode 100644 index 0000000..0da679a --- /dev/null +++ b/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "src/styles/globals.css", + "baseColor": "zinc", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "~/components", + "utils": "~/lib/utils", + "ui": "~/components/ui", + "lib": "~/lib", + "hooks": "~/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/package.json b/package.json index c786322..739a56b 100644 --- a/package.json +++ b/package.json @@ -20,31 +20,40 @@ "format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,mdx}\" --cache" }, "dependencies": { + "@radix-ui/react-avatar": "^1.1.1", + "@radix-ui/react-dialog": "^1.1.2", + "@radix-ui/react-navigation-menu": "^1.2.1", "@t3-oss/env-nextjs": "^0.10.1", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", "drizzle-orm": "^0.33.0", - "geist": "^1.3.0", - "next": "^15.0.1", - "postgres": "^3.4.4", + "geist": "^1.3.1", + "lucide-react": "^0.460.0", + "next": "^15.0.3", + "postgres": "^3.4.5", "react": "^18.3.1", "react-dom": "^18.3.1", - "zod": "^3.23.3" + "server-only": "^0.0.1", + "tailwind-merge": "^2.5.4", + "tailwindcss-animate": "^1.0.7", + "zod": "^3.23.8" }, "devDependencies": { - "@types/eslint": "^8.56.10", - "@types/node": "^20.14.10", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^8.1.0", - "@typescript-eslint/parser": "^8.1.0", - "drizzle-kit": "^0.24.0", - "eslint": "^8.57.0", - "eslint-config-next": "^15.0.1", + "@types/eslint": "^8.56.12", + "@types/node": "^20.17.6", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@typescript-eslint/eslint-plugin": "^8.15.0", + "@typescript-eslint/parser": "^8.15.0", + "drizzle-kit": "^0.24.2", + "eslint": "^8.57.1", + "eslint-config-next": "^15.0.3", "eslint-plugin-drizzle": "^0.2.3", - "postcss": "^8.4.39", - "prettier": "^3.3.2", - "prettier-plugin-tailwindcss": "^0.6.5", - "tailwindcss": "^3.4.3", - "typescript": "^5.5.3" + "postcss": "^8.4.49", + "prettier": "^3.3.3", + "prettier-plugin-tailwindcss": "^0.6.9", + "tailwindcss": "^3.4.15", + "typescript": "^5.7.2" }, "ct3aMetadata": { "initVersion": "7.38.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aa1e29b..7d864eb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,20 +8,38 @@ importers: .: dependencies: + '@radix-ui/react-avatar': + specifier: ^1.1.1 + version: 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-dialog': + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-navigation-menu': + specifier: ^1.2.1 + version: 1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@t3-oss/env-nextjs': specifier: ^0.10.1 - version: 0.10.1(typescript@5.6.3)(zod@3.23.8) + version: 0.10.1(typescript@5.7.2)(zod@3.23.8) + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.0 + clsx: + specifier: ^2.1.1 + version: 2.1.1 drizzle-orm: specifier: ^0.33.0 version: 0.33.0(@types/react@18.3.12)(postgres@3.4.5)(react@18.3.1) geist: - specifier: ^1.3.0 + specifier: ^1.3.1 version: 1.3.1(next@15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + lucide-react: + specifier: ^0.460.0 + version: 0.460.0(react@18.3.1) next: - specifier: ^15.0.1 + specifier: ^15.0.3 version: 15.0.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) postgres: - specifier: ^3.4.4 + specifier: ^3.4.5 version: 3.4.5 react: specifier: ^18.3.1 @@ -29,55 +47,64 @@ importers: react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) + server-only: + specifier: ^0.0.1 + version: 0.0.1 + tailwind-merge: + specifier: ^2.5.4 + version: 2.5.4 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.15) zod: - specifier: ^3.23.3 + specifier: ^3.23.8 version: 3.23.8 devDependencies: '@types/eslint': - specifier: ^8.56.10 + specifier: ^8.56.12 version: 8.56.12 '@types/node': - specifier: ^20.14.10 + specifier: ^20.17.6 version: 20.17.6 '@types/react': - specifier: ^18.3.3 + specifier: ^18.3.12 version: 18.3.12 '@types/react-dom': - specifier: ^18.3.0 + specifier: ^18.3.1 version: 18.3.1 '@typescript-eslint/eslint-plugin': - specifier: ^8.1.0 - version: 8.15.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) + specifier: ^8.15.0 + version: 8.15.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2) '@typescript-eslint/parser': - specifier: ^8.1.0 - version: 8.15.0(eslint@8.57.1)(typescript@5.6.3) + specifier: ^8.15.0 + version: 8.15.0(eslint@8.57.1)(typescript@5.7.2) drizzle-kit: - specifier: ^0.24.0 + specifier: ^0.24.2 version: 0.24.2 eslint: - specifier: ^8.57.0 + specifier: ^8.57.1 version: 8.57.1 eslint-config-next: - specifier: ^15.0.1 - version: 15.0.3(eslint@8.57.1)(typescript@5.6.3) + specifier: ^15.0.3 + version: 15.0.3(eslint@8.57.1)(typescript@5.7.2) eslint-plugin-drizzle: specifier: ^0.2.3 version: 0.2.3(eslint@8.57.1) postcss: - specifier: ^8.4.39 + specifier: ^8.4.49 version: 8.4.49 prettier: - specifier: ^3.3.2 + specifier: ^3.3.3 version: 3.3.3 prettier-plugin-tailwindcss: - specifier: ^0.6.5 - version: 0.6.8(prettier@3.3.3) + specifier: ^0.6.9 + version: 0.6.9(prettier@3.3.3) tailwindcss: - specifier: ^3.4.3 + specifier: ^3.4.15 version: 3.4.15 typescript: - specifier: ^5.5.3 - version: 5.6.3 + specifier: ^5.7.2 + version: 5.7.2 packages: @@ -601,6 +628,247 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@radix-ui/primitive@1.1.0': + resolution: {integrity: sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==} + + '@radix-ui/react-avatar@1.1.1': + resolution: {integrity: sha512-eoOtThOmxeoizxpX6RiEsQZ2wj5r4+zoeqAwO0cBaFQGjJwIH3dIX0OCxNrCyrrdxG+vBweMETh3VziQG7c1kw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.0': + resolution: {integrity: sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.0': + resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.0': + resolution: {integrity: sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.1': + resolution: {integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.2': + resolution: {integrity: sha512-Yj4dZtqa2o+kG61fzB0H2qUvmwBA2oyQroGLyNtBj1beo1khoQ3q1a2AO8rrQYjd8256CO9+N8L9tvsS+bnIyA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-direction@1.1.0': + resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.1': + resolution: {integrity: sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.1': + resolution: {integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.0': + resolution: {integrity: sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.0': + resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-navigation-menu@1.2.1': + resolution: {integrity: sha512-egDo0yJD2IK8L17gC82vptkvW1jLeni1VuqCyzY727dSJdk5cDjINomouLoNk8RVF7g2aNIfENKWL4UzeU9c8Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.2': + resolution: {integrity: sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.1': + resolution: {integrity: sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.0.0': + resolution: {integrity: sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.1.0': + resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.0': + resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.1.0': + resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.0': + resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.0': + resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.0': + resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.1.0': + resolution: {integrity: sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} @@ -762,6 +1030,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.4: + resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} + engines: {node: '>=10'} + aria-query@5.3.2: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} @@ -849,8 +1121,8 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - caniuse-lite@1.0.30001680: - resolution: {integrity: sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==} + caniuse-lite@1.0.30001683: + resolution: {integrity: sha512-iqmNnThZ0n70mNwvxpEC2nBJ037ZHZUoBI5Gorh1Mw6IlEAZujEoU1tXA628iZfzm7R9FvFzxbfdgml82a3k8Q==} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -860,9 +1132,20 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + class-variance-authority@0.7.0: + resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==} + client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + clsx@2.0.0: + resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} + engines: {node: '>=6'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -943,6 +1226,9 @@ packages: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} @@ -1303,6 +1589,10 @@ packages: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + get-symbol-description@1.0.2: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} @@ -1392,6 +1682,9 @@ packages: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + is-array-buffer@3.0.4: resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} @@ -1587,6 +1880,11 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lucide-react@0.460.0: + resolution: {integrity: sha512-BVtq/DykVeIvRTJvRAgCsOwaGL8Un3Bxh8MbDxMhEWlZay3T4IpEKDEpwt5KZ0KJMHzgm6jrltxlT5eXOWXDHg==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1797,8 +2095,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier-plugin-tailwindcss@0.6.8: - resolution: {integrity: sha512-dGu3kdm7SXPkiW4nzeWKCl3uoImdd5CTZEJGxyypEPL37Wj0HT2pLqjrvSei1nTeuQfO4PUfjeW5cTUNRLZ4sA==} + prettier-plugin-tailwindcss@0.6.9: + resolution: {integrity: sha512-r0i3uhaZAXYP0At5xGfJH876W3HHGHDp+LCRUJrs57PBeQ6mYHMwr25KH8NPX44F2yGTvdnH7OqCshlQx183Eg==} engines: {node: '>=14.21.3'} peerDependencies: '@ianvs/prettier-plugin-sort-imports': '*' @@ -1875,6 +2173,36 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-remove-scroll-bar@2.3.6: + resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.6.0: + resolution: {integrity: sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-style-singleton@2.2.1: + resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -1941,6 +2269,9 @@ packages: engines: {node: '>=10'} hasBin: true + server-only@0.0.1: + resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -2059,6 +2390,14 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + tailwind-merge@2.5.4: + resolution: {integrity: sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==} + + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + tailwindcss@3.4.15: resolution: {integrity: sha512-r4MeXnfBmSOuKUWmXe6h2CcyfzJCEk4F0pptO5jlnYSIViUkVmsawj80N5h2lO3gwcmSb4n3PuN+e+GC1Guylw==} engines: {node: '>=14.0.0'} @@ -2113,16 +2452,16 @@ packages: resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} engines: {node: '>= 0.4'} - typed-array-byte-offset@1.0.2: - resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + typed-array-byte-offset@1.0.3: + resolution: {integrity: sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==} engines: {node: '>= 0.4'} typed-array-length@1.0.6: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} - typescript@5.6.3: - resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} engines: {node: '>=14.17'} hasBin: true @@ -2135,6 +2474,26 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-callback-ref@1.3.2: + resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.2: + resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -2173,8 +2532,8 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - yaml@2.6.0: - resolution: {integrity: sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==} + yaml@2.6.1: + resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==} engines: {node: '>= 14'} hasBin: true @@ -2524,6 +2883,214 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@radix-ui/primitive@1.1.0': {} + + '@radix-ui/react-avatar@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-context': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + + '@radix-ui/react-collection@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + + '@radix-ui/react-compose-refs@1.1.0(@types/react@18.3.12)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + + '@radix-ui/react-context@1.1.0(@types/react@18.3.12)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + + '@radix-ui/react-context@1.1.1(@types/react@18.3.12)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + + '@radix-ui/react-dialog@1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-portal': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.12)(react@18.3.1) + aria-hidden: 1.2.4 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.6.0(@types/react@18.3.12)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + + '@radix-ui/react-direction@1.1.0(@types/react@18.3.12)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + + '@radix-ui/react-dismissable-layer@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + + '@radix-ui/react-focus-guards@1.1.1(@types/react@18.3.12)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + + '@radix-ui/react-focus-scope@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + + '@radix-ui/react-id@1.1.0(@types/react@18.3.12)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + + '@radix-ui/react-navigation-menu@1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + + '@radix-ui/react-portal@1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + + '@radix-ui/react-presence@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.12)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + + '@radix-ui/react-primitive@2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + + '@radix-ui/react-slot@1.1.0(@types/react@18.3.12)(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + + '@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.12)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + + '@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.3.12)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + + '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.3.12)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.12)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + + '@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.3.12)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + + '@radix-ui/react-use-previous@1.1.0(@types/react@18.3.12)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.12 + + '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + '@types/react-dom': 18.3.1 + '@rtsao/scc@1.1.0': {} '@rushstack/eslint-patch@1.10.4': {} @@ -2534,18 +3101,18 @@ snapshots: dependencies: tslib: 2.8.1 - '@t3-oss/env-core@0.10.1(typescript@5.6.3)(zod@3.23.8)': + '@t3-oss/env-core@0.10.1(typescript@5.7.2)(zod@3.23.8)': dependencies: zod: 3.23.8 optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 - '@t3-oss/env-nextjs@0.10.1(typescript@5.6.3)(zod@3.23.8)': + '@t3-oss/env-nextjs@0.10.1(typescript@5.7.2)(zod@3.23.8)': dependencies: - '@t3-oss/env-core': 0.10.1(typescript@5.6.3)(zod@3.23.8) + '@t3-oss/env-core': 0.10.1(typescript@5.7.2)(zod@3.23.8) zod: 3.23.8 optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 '@types/eslint@8.56.12': dependencies: @@ -2573,34 +3140,34 @@ snapshots: '@types/prop-types': 15.7.13 csstype: 3.1.3 - '@typescript-eslint/eslint-plugin@8.15.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@8.15.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.15.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/parser': 8.15.0(eslint@8.57.1)(typescript@5.7.2) '@typescript-eslint/scope-manager': 8.15.0 - '@typescript-eslint/type-utils': 8.15.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/utils': 8.15.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/type-utils': 8.15.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/utils': 8.15.0(eslint@8.57.1)(typescript@5.7.2) '@typescript-eslint/visitor-keys': 8.15.0 eslint: 8.57.1 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 1.4.0(typescript@5.6.3) + ts-api-utils: 1.4.0(typescript@5.7.2) optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.7.2)': dependencies: '@typescript-eslint/scope-manager': 8.15.0 '@typescript-eslint/types': 8.15.0 - '@typescript-eslint/typescript-estree': 8.15.0(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 8.15.0(typescript@5.7.2) '@typescript-eslint/visitor-keys': 8.15.0 debug: 4.3.7 eslint: 8.57.1 optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color @@ -2609,21 +3176,21 @@ snapshots: '@typescript-eslint/types': 8.15.0 '@typescript-eslint/visitor-keys': 8.15.0 - '@typescript-eslint/type-utils@8.15.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/type-utils@8.15.0(eslint@8.57.1)(typescript@5.7.2)': dependencies: - '@typescript-eslint/typescript-estree': 8.15.0(typescript@5.6.3) - '@typescript-eslint/utils': 8.15.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 8.15.0(typescript@5.7.2) + '@typescript-eslint/utils': 8.15.0(eslint@8.57.1)(typescript@5.7.2) debug: 4.3.7 eslint: 8.57.1 - ts-api-utils: 1.4.0(typescript@5.6.3) + ts-api-utils: 1.4.0(typescript@5.7.2) optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color '@typescript-eslint/types@8.15.0': {} - '@typescript-eslint/typescript-estree@8.15.0(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@8.15.0(typescript@5.7.2)': dependencies: '@typescript-eslint/types': 8.15.0 '@typescript-eslint/visitor-keys': 8.15.0 @@ -2632,21 +3199,21 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 - ts-api-utils: 1.4.0(typescript@5.6.3) + ts-api-utils: 1.4.0(typescript@5.7.2) optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.15.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/utils@8.15.0(eslint@8.57.1)(typescript@5.7.2)': dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) '@typescript-eslint/scope-manager': 8.15.0 '@typescript-eslint/types': 8.15.0 - '@typescript-eslint/typescript-estree': 8.15.0(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 8.15.0(typescript@5.7.2) eslint: 8.57.1 optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color @@ -2691,6 +3258,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.4: + dependencies: + tslib: 2.8.1 + aria-query@5.3.2: {} array-buffer-byte-length@1.0.1: @@ -2803,7 +3374,7 @@ snapshots: camelcase-css@2.0.1: {} - caniuse-lite@1.0.30001680: {} + caniuse-lite@1.0.30001683: {} chalk@4.1.2: dependencies: @@ -2822,8 +3393,16 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + class-variance-authority@0.7.0: + dependencies: + clsx: 2.0.0 + client-only@0.0.1: {} + clsx@2.0.0: {} + + clsx@2.1.1: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -2901,6 +3480,8 @@ snapshots: detect-libc@2.0.3: optional: true + detect-node-es@1.1.0: {} + didyoumean@1.2.2: {} dlv@1.1.3: {} @@ -2983,7 +3564,7 @@ snapshots: string.prototype.trimstart: 1.0.8 typed-array-buffer: 1.0.2 typed-array-byte-length: 1.0.1 - typed-array-byte-offset: 1.0.2 + typed-array-byte-offset: 1.0.3 typed-array-length: 1.0.6 unbox-primitive: 1.0.2 which-typed-array: 1.1.15 @@ -3092,21 +3673,21 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-next@15.0.3(eslint@8.57.1)(typescript@5.6.3): + eslint-config-next@15.0.3(eslint@8.57.1)(typescript@5.7.2): dependencies: '@next/eslint-plugin-next': 15.0.3 '@rushstack/eslint-patch': 1.10.4 - '@typescript-eslint/eslint-plugin': 8.15.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/parser': 8.15.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/eslint-plugin': 8.15.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/parser': 8.15.0(eslint@8.57.1)(typescript@5.7.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.2(eslint@8.57.1) eslint-plugin-react-hooks: 5.0.0(eslint@8.57.1) optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - eslint-import-resolver-webpack - eslint-plugin-import-x @@ -3120,33 +3701,33 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.57.1 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 is-glob: 4.0.3 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.15.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/parser': 8.15.0(eslint@8.57.1)(typescript@5.7.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -3154,7 +3735,7 @@ snapshots: dependencies: eslint: 8.57.1 - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -3165,7 +3746,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -3177,7 +3758,7 @@ snapshots: string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.15.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/parser': 8.15.0(eslint@8.57.1)(typescript@5.7.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -3382,6 +3963,8 @@ snapshots: has-symbols: 1.0.3 hasown: 2.0.2 + get-nonce@1.0.1: {} + get-symbol-description@1.0.2: dependencies: call-bind: 1.0.7 @@ -3477,6 +4060,10 @@ snapshots: hasown: 2.0.2 side-channel: 1.0.6 + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 + is-array-buffer@3.0.4: dependencies: call-bind: 1.0.7 @@ -3658,6 +4245,10 @@ snapshots: lru-cache@10.4.3: {} + lucide-react@0.460.0(react@18.3.1): + dependencies: + react: 18.3.1 + merge2@1.4.1: {} micromatch@4.0.8: @@ -3695,7 +4286,7 @@ snapshots: '@swc/counter': 0.1.3 '@swc/helpers': 0.5.13 busboy: 1.6.0 - caniuse-lite: 1.0.30001680 + caniuse-lite: 1.0.30001683 postcss: 8.4.31 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -3821,7 +4412,7 @@ snapshots: postcss-load-config@4.0.2(postcss@8.4.49): dependencies: lilconfig: 3.1.2 - yaml: 2.6.0 + yaml: 2.6.1 optionalDependencies: postcss: 8.4.49 @@ -3853,7 +4444,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier-plugin-tailwindcss@0.6.8(prettier@3.3.3): + prettier-plugin-tailwindcss@0.6.9(prettier@3.3.3): dependencies: prettier: 3.3.3 @@ -3877,6 +4468,34 @@ snapshots: react-is@16.13.1: {} + react-remove-scroll-bar@2.3.6(@types/react@18.3.12)(react@18.3.1): + dependencies: + react: 18.3.1 + react-style-singleton: 2.2.1(@types/react@18.3.12)(react@18.3.1) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.12 + + react-remove-scroll@2.6.0(@types/react@18.3.12)(react@18.3.1): + dependencies: + react: 18.3.1 + react-remove-scroll-bar: 2.3.6(@types/react@18.3.12)(react@18.3.1) + react-style-singleton: 2.2.1(@types/react@18.3.12)(react@18.3.1) + tslib: 2.8.1 + use-callback-ref: 1.3.2(@types/react@18.3.12)(react@18.3.1) + use-sidecar: 1.1.2(@types/react@18.3.12)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.12 + + react-style-singleton@2.2.1(@types/react@18.3.12)(react@18.3.1): + dependencies: + get-nonce: 1.0.1 + invariant: 2.2.4 + react: 18.3.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.12 + react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -3953,6 +4572,8 @@ snapshots: semver@7.6.3: {} + server-only@0.0.1: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -4117,6 +4738,12 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + tailwind-merge@2.5.4: {} + + tailwindcss-animate@1.0.7(tailwindcss@3.4.15): + dependencies: + tailwindcss: 3.4.15 + tailwindcss@3.4.15: dependencies: '@alloc/quick-lru': 5.2.0 @@ -4160,9 +4787,9 @@ snapshots: dependencies: is-number: 7.0.0 - ts-api-utils@1.4.0(typescript@5.6.3): + ts-api-utils@1.4.0(typescript@5.7.2): dependencies: - typescript: 5.6.3 + typescript: 5.7.2 ts-interface-checker@0.1.13: {} @@ -4195,7 +4822,7 @@ snapshots: has-proto: 1.0.3 is-typed-array: 1.1.13 - typed-array-byte-offset@1.0.2: + typed-array-byte-offset@1.0.3: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.7 @@ -4203,6 +4830,7 @@ snapshots: gopd: 1.0.1 has-proto: 1.0.3 is-typed-array: 1.1.13 + reflect.getprototypeof: 1.0.6 typed-array-length@1.0.6: dependencies: @@ -4213,7 +4841,7 @@ snapshots: is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 - typescript@5.6.3: {} + typescript@5.7.2: {} unbox-primitive@1.0.2: dependencies: @@ -4228,6 +4856,21 @@ snapshots: dependencies: punycode: 2.3.1 + use-callback-ref@1.3.2(@types/react@18.3.12)(react@18.3.1): + dependencies: + react: 18.3.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.12 + + use-sidecar@1.1.2(@types/react@18.3.12)(react@18.3.1): + dependencies: + detect-node-es: 1.1.0 + react: 18.3.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.12 + util-deprecate@1.0.2: {} which-boxed-primitive@1.0.2: @@ -4288,7 +4931,7 @@ snapshots: wrappy@1.0.2: {} - yaml@2.6.0: {} + yaml@2.6.1: {} yocto-queue@0.1.0: {} diff --git a/src/app/@modal/(.)timer/[id]/modal.tsx b/src/app/@modal/(.)timer/[id]/modal.tsx new file mode 100644 index 0000000..4481ebb --- /dev/null +++ b/src/app/@modal/(.)timer/[id]/modal.tsx @@ -0,0 +1,24 @@ +"use client"; +import { Dialog, DialogContent, DialogTitle } from "~/components/ui/dialog"; +import { useRouter } from "next/navigation"; + +export default function Modal({ children }: { children: React.ReactNode }) { + const router = useRouter(); + + const handleOpenChange = (open: boolean) => { + if (!open) { + router.back(); + } + }; + + return ( + +
+ + + {children} + +
+
+ ); +} diff --git a/src/app/@modal/(.)timer/[id]/page.tsx b/src/app/@modal/(.)timer/[id]/page.tsx new file mode 100644 index 0000000..652db6f --- /dev/null +++ b/src/app/@modal/(.)timer/[id]/page.tsx @@ -0,0 +1,17 @@ +import FullPageTimer from "~/app/_components/full-page-timer"; +import { getTimer } from "~/server/queries"; +import Modal from "./modal"; + +export default async function TimerModal({ + params, +}: { + params: Promise<{ id: string }>; +}) { + const timer = await getTimer((await params).id); + + return ( + + + + ); +} diff --git a/src/app/@modal/default.tsx b/src/app/@modal/default.tsx new file mode 100644 index 0000000..4e8611a --- /dev/null +++ b/src/app/@modal/default.tsx @@ -0,0 +1,3 @@ +export default function DefaultModal() { + return null; +} diff --git a/src/app/_components/full-page-timer.tsx b/src/app/_components/full-page-timer.tsx new file mode 100644 index 0000000..8557b38 --- /dev/null +++ b/src/app/_components/full-page-timer.tsx @@ -0,0 +1,75 @@ +"use client"; + +import { useEffect, useState } from "react"; + +const formatTime = (elapsed: number): [number, number, number, number] => { + const seconds = Math.floor(elapsed / 1000); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + const days = Math.floor(hours / 24); + + const remainingSeconds = seconds % 60; + const remainingMinutes = minutes % 60; + const remainingHours = hours % 24; + + return [days, remainingHours, remainingMinutes, remainingSeconds]; +}; + +const calculateTimeSince = (start: Date) => { + const now = new Date(); + return now.getTime() - start.getTime(); +}; + +export default function Timer(props: { eventTime: Date; caption: string }) { + const [timeSince, setTimeSince] = useState( + calculateTimeSince(props.eventTime), + ); + + useEffect(() => { + const interval = setInterval(() => { + const elapsed = calculateTimeSince(props.eventTime); + setTimeSince(elapsed); + }, 1000); + + return () => clearInterval(interval); + }, [props.eventTime]); + + const [days, hours, mins, secs] = formatTime(timeSince); + + return ( +
+
+

It has been

+
+
+
+
+ {days.toString().padStart(2, "0")} +
+
DAYS
+
+
+
+ {hours.toString().padStart(2, "0")} +
+
HOURS
+
+
+
+ {mins.toString().padStart(2, "0")} +
+
MINUTES
+
+
+
+ {secs.toString().padStart(2, "0")} +
+
SECONDS
+
+
+
+

{props.caption}

+
+
+ ); +} diff --git a/src/app/_components/navigation.tsx b/src/app/_components/navigation.tsx new file mode 100644 index 0000000..826e3a1 --- /dev/null +++ b/src/app/_components/navigation.tsx @@ -0,0 +1,25 @@ +import Link from "next/link"; +import { + NavigationMenu, + NavigationMenuLink, + NavigationMenuList, + navigationMenuTriggerStyle, +} from "~/components/ui/navigation-menu"; + +export function TopNav() { + return ( + + ); +} diff --git a/src/app/_components/timer.tsx b/src/app/_components/timer.tsx new file mode 100644 index 0000000..a0c67d1 --- /dev/null +++ b/src/app/_components/timer.tsx @@ -0,0 +1,93 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "~/components/ui/card"; +import { Avatar, AvatarFallback, AvatarImage } from "~/components/ui/avatar"; + +const formatTime = (elapsed: number): [number, number, number, number] => { + const seconds = Math.floor(elapsed / 1000); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + const days = Math.floor(hours / 24); + + const remainingSeconds = seconds % 60; + const remainingMinutes = minutes % 60; + const remainingHours = hours % 24; + + return [days, remainingHours, remainingMinutes, remainingSeconds]; +}; + +const calculateTimeSince = (start: Date) => { + const now = new Date(); + return now.getTime() - start.getTime(); +}; + +export default function Timer(props: { + eventTime: Date; + caption?: string; + email?: string; + emailHash?: string; +}) { + const [timeSince, setTimeSince] = useState( + calculateTimeSince(props.eventTime), + ); + + useEffect(() => { + const interval = setInterval(() => { + const elapsed = calculateTimeSince(props.eventTime); + setTimeSince(elapsed); + }, 1000); + + return () => clearInterval(interval); + }, [props.eventTime]); + + const [days, hours, mins, secs] = formatTime(timeSince); + + return ( + + + + + +
+ {props.caption} + {props.email} +
+
+ +
+
+
+ {days.toString().padStart(2, "0")} +
+
DAYS
+
+
+
+ {hours.toString().padStart(2, "0")} +
+
HOURS
+
+
+
+ {mins.toString().padStart(2, "0")} +
+
MINUTES
+
+
+
+ {secs.toString().padStart(2, "0")} +
+
SECONDS
+
+
+
+
+ ); +} diff --git a/src/app/api/timer/[id]/route.ts b/src/app/api/timer/[id]/route.ts new file mode 100644 index 0000000..40f08e9 --- /dev/null +++ b/src/app/api/timer/[id]/route.ts @@ -0,0 +1,22 @@ +import { updateTimerTime } from "~/server/queries"; + +export async function POST( + _: Request, + { params }: { params: Promise<{ id: string }> }, +) { + const idAsNumber = parseInt((await params).id); + + try { + const updated = await updateTimerTime(idAsNumber); + + return Response.json({}, { status: 200 }); + } catch (error: any) { + const typedError = error as Error; + + if (error.message === "Timer not found") { + return Response.json({}, { status: 404 }); + } else { + return Response.json({}, { status: 500 }); + } + } +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 42ed47c..7d37aab 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,20 +1,34 @@ import "~/styles/globals.css"; -import { GeistSans } from "geist/font/sans"; +import { Inter } from "next/font/google"; import { type Metadata } from "next"; +import { TopNav } from "./_components/navigation"; export const metadata: Metadata = { - title: "Create T3 App", - description: "Generated by create-t3-app", + title: "Days Since", + description: "A simple app to track the number of days since an event", icons: [{ rel: "icon", url: "/favicon.ico" }], }; +const inter = Inter({ + subsets: ["latin"], + variable: "--font-sans", +}); + export default function RootLayout({ + modal, children, -}: Readonly<{ children: React.ReactNode }>) { +}: Readonly<{ children: React.ReactNode; modal: React.ReactNode }>) { return ( - - {children} + + +
+ +
{children}
+ {modal} + + ); } diff --git a/src/app/page.tsx b/src/app/page.tsx index 773fef1..3f72d62 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,37 +1,46 @@ +import Timer from "~/app/_components/timer"; + +import { createHash } from "crypto"; +import { getAllTimers } from "~/server/queries"; import Link from "next/link"; -export default function HomePage() { +const hashEmail = (email: string) => { + const hash = createHash("sha256") + .update(email.trim().toLowerCase()) + .digest("hex"); + + return hash; +}; + +export default async function HomePage() { + const timers = await getAllTimers(); + return ( -
-
-

- Create T3 App -

-
- -

First Steps →

-
- Just the basics - Everything you need to know to set up your - database and authentication. -
+
+ {timers.map((timer, idx) => + idx % 4 == 0 ? ( +
+ + + +
+ ) : ( + + - -

Documentation →

-
- Learn more about Create T3 App, the libraries it uses, and how to - deploy it. -
- -
-
-
+ ), + )} +
); } diff --git a/src/app/timer/[id]/page.tsx b/src/app/timer/[id]/page.tsx new file mode 100644 index 0000000..9fe0deb --- /dev/null +++ b/src/app/timer/[id]/page.tsx @@ -0,0 +1,12 @@ +import FullPageTimer from "~/app/_components/full-page-timer"; +import { getTimer } from "~/server/queries"; + +export default async function TimerPage({ + params, +}: { + params: Promise<{ id: string }>; +}) { + const timer = await getTimer((await params).id); + + return ; +} diff --git a/src/components/ui/avatar.tsx b/src/components/ui/avatar.tsx new file mode 100644 index 0000000..05e961c --- /dev/null +++ b/src/components/ui/avatar.tsx @@ -0,0 +1,50 @@ +"use client" + +import * as React from "react" +import * as AvatarPrimitive from "@radix-ui/react-avatar" + +import { cn } from "~/lib/utils" + +const Avatar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +Avatar.displayName = AvatarPrimitive.Root.displayName + +const AvatarImage = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AvatarImage.displayName = AvatarPrimitive.Image.displayName + +const AvatarFallback = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx new file mode 100644 index 0000000..874ce09 --- /dev/null +++ b/src/components/ui/card.tsx @@ -0,0 +1,76 @@ +import * as React from "react" + +import { cn } from "~/lib/utils" + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx new file mode 100644 index 0000000..a75e1df --- /dev/null +++ b/src/components/ui/dialog.tsx @@ -0,0 +1,122 @@ +"use client" + +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { X } from "lucide-react" + +import { cn } from "~/lib/utils" + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogHeader.displayName = "DialogHeader" + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogFooter.displayName = "DialogFooter" + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogTrigger, + DialogClose, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} diff --git a/src/components/ui/navigation-menu.tsx b/src/components/ui/navigation-menu.tsx new file mode 100644 index 0000000..3dea8df --- /dev/null +++ b/src/components/ui/navigation-menu.tsx @@ -0,0 +1,128 @@ +import * as React from "react"; +import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"; +import { cva } from "class-variance-authority"; +import { ChevronDown } from "lucide-react"; + +import { cn } from "~/lib/utils"; + +const NavigationMenu = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + {children} + + +)); +NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName; + +const NavigationMenuList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName; + +const NavigationMenuItem = NavigationMenuPrimitive.Item; + +const navigationMenuTriggerStyle = cva( + "group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50", +); + +const NavigationMenuTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + {children}{" "} + +)); +NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName; + +const NavigationMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName; + +const NavigationMenuLink = NavigationMenuPrimitive.Link; + +const NavigationMenuViewport = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( +
+ +
+)); +NavigationMenuViewport.displayName = + NavigationMenuPrimitive.Viewport.displayName; + +const NavigationMenuIndicator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +
+ +)); +NavigationMenuIndicator.displayName = + NavigationMenuPrimitive.Indicator.displayName; + +export { + navigationMenuTriggerStyle, + NavigationMenu, + NavigationMenuList, + NavigationMenuItem, + NavigationMenuContent, + NavigationMenuTrigger, + NavigationMenuLink, + NavigationMenuIndicator, + NavigationMenuViewport, +}; 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/server/db/schema.ts b/src/server/db/schema.ts index 59102fd..3c89210 100644 --- a/src/server/db/schema.ts +++ b/src/server/db/schema.ts @@ -3,11 +3,11 @@ import { sql } from "drizzle-orm"; import { - index, - integer, pgTableCreator, timestamp, varchar, + boolean, + uuid, } from "drizzle-orm/pg-core"; /** @@ -18,19 +18,19 @@ import { */ export const createTable = pgTableCreator((name) => `days-since_${name}`); -export const posts = createTable( - "post", - { - id: integer("id").primaryKey().generatedByDefaultAsIdentity(), - name: varchar("name", { length: 256 }), - createdAt: timestamp("created_at", { withTimezone: true }) - .default(sql`CURRENT_TIMESTAMP`) - .notNull(), - updatedAt: timestamp("updated_at", { withTimezone: true }).$onUpdate( - () => new Date() - ), - }, - (example) => ({ - nameIndex: index("name_idx").on(example.name), - }) -); +export const timers = createTable("timer", { + id: varchar("timerId") + .default(sql`gen_random_uuid()`) + .primaryKey(), + userId: varchar("userId", { length: 256 }).notNull(), + userEmail: varchar("userEmail", { length: 256 }).notNull(), + caption: varchar("caption", { length: 256 }).notNull(), + createdAt: timestamp("created_at", { withTimezone: true }) + .default(sql`CURRENT_TIMESTAMP`) + .notNull(), + updatedAt: timestamp("updated_at", { withTimezone: true }) + .$onUpdate(() => new Date()) + .default(sql`CURRENT_TIMESTAMP`) + .notNull(), + public: boolean("public").default(false).notNull(), +}); diff --git a/src/server/queries.ts b/src/server/queries.ts new file mode 100644 index 0000000..0dca67a --- /dev/null +++ b/src/server/queries.ts @@ -0,0 +1,39 @@ +import "server-only"; + +import { eq } from "drizzle-orm"; +import { db } from "./db"; +import { timers } from "./db/schema"; +import { notFound } from "next/navigation"; + +export async function getTimer(id: string) { + const timer = await db.query.timers.findFirst({ + where: (model, { and, eq }) => + and(eq(model.id, id), eq(model.public, true)), + }); + + if (!timer) notFound(); + + if (!timer.public) notFound(); + + return timer; +} + +export async function getAllTimers() { + const timers = db.query.timers + .findMany({ + where: (model, { eq }) => eq(model.public, true), + }) + .execute(); + + return timers; +} + +export async function updateTimerTime(id: string) { + const updated = await db + .update(timers) + .set({ updatedAt: new Date() }) + .where(eq(timers.id, id)) + .returning({ id: timers.id }); + + if (updated.length === 0) throw new Error("Timer not found"); +} diff --git a/src/styles/globals.css b/src/styles/globals.css index b5c61c9..75f6040 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -1,3 +1,71 @@ @tailwind base; @tailwind components; @tailwind utilities; +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; + --primary: 240 5.9% 10%; + --primary-foreground: 0 0% 98%; + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; + --accent: 240 4.8% 95.9%; + --accent-foreground: 240 5.9% 10%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 240 10% 3.9%; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --radius: 0.5rem + } + .dark { + --background: 240 10% 3.9%; + --foreground: 0 0% 98%; + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 240 4.9% 83.9%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55% + } +} +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} + +.div[role="dialog"] { + max-width: 100vw; + max-height: 100vh; +} diff --git a/tailwind.config.ts b/tailwind.config.ts index 5fd44e8..b309766 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -2,13 +2,61 @@ import { type Config } from "tailwindcss"; import { fontFamily } from "tailwindcss/defaultTheme"; export default { + darkMode: ["class"], content: ["./src/**/*.tsx"], theme: { extend: { fontFamily: { sans: ["var(--font-geist-sans)", ...fontFamily.sans], }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + colors: { + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + chart: { + "1": "hsl(var(--chart-1))", + "2": "hsl(var(--chart-2))", + "3": "hsl(var(--chart-3))", + "4": "hsl(var(--chart-4))", + "5": "hsl(var(--chart-5))", + }, + }, }, }, - plugins: [], + plugins: [require("tailwindcss-animate")], } satisfies Config;