diff --git a/components.json b/components.json index 24e4297..ac52552 100644 --- a/components.json +++ b/components.json @@ -1,10 +1,10 @@ { "$schema": "https://ui.shadcn.com/schema.json", - "style": "default", + "style": "new-york", "rsc": true, "tsx": true, "tailwind": { - "config": "tailwind.config.js", + "config": "tailwind.config.mjs", "css": "src/app/(frontend)/globals.css", "baseColor": "slate", "cssVariables": true, @@ -12,6 +12,10 @@ }, "aliases": { "components": "@/components", - "utils": "@/utilities/ui" - } + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" } diff --git a/package-lock.json b/package-lock.json index 2365e94..8246793 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,21 +22,31 @@ "@payloadcms/plugin-seo": "3.38.0", "@payloadcms/richtext-lexical": "3.38.0", "@payloadcms/ui": "3.38.0", + "@radix-ui/react-avatar": "^1.1.9", "@radix-ui/react-checkbox": "^1.0.4", + "@radix-ui/react-collapsible": "^1.1.10", + "@radix-ui/react-dialog": "^1.1.13", + "@radix-ui/react-dropdown-menu": "^2.1.14", "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-popover": "^1.1.13", "@radix-ui/react-select": "^2.0.0", - "@radix-ui/react-slot": "^1.0.2", - "class-variance-authority": "^0.7.0", + "@radix-ui/react-separator": "^1.1.6", + "@radix-ui/react-slot": "^1.2.2", + "@radix-ui/react-tooltip": "^1.2.6", + "@tabler/icons-react": "^3.33.0", + "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cross-env": "^7.0.3", + "date-fns": "^4.1.0", "geist": "^1.3.0", "graphql": "^16.8.2", "lucide-react": "^0.378.0", "next": "15.3.0", "next-sitemap": "^4.2.3", - "payload": "3.33.0", + "payload": "3.38.0", "prism-react-renderer": "^2.3.1", "react": "19.1.0", + "react-day-picker": "^8.10.1", "react-dom": "19.1.0", "react-hook-form": "7.45.4", "sharp": "0.32.6", @@ -3950,6 +3960,33 @@ } } }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.9.tgz", + "integrity": "sha512-10tQokfvZdFvnvDkcOJPjm2pWiP8A0R4T83MoD7tb15bC/k2GU7B1YBuzJi8lNQ8V1QqhP8ocNqp27ByZaNagQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.2", + "@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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-checkbox": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.1.tgz", @@ -3980,6 +4017,36 @@ } } }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.10.tgz", + "integrity": "sha512-O2mcG3gZNkJ/Ena34HurA3llPOEA/M4dJtIRMa6y/cknRDC8XY5UZBInKTsUwW5cUue9A4k0wi1XU5fKBzKe1w==", + "license": "MIT", + "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.4", + "@radix-ui/react-primitive": "2.1.2", + "@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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-collection": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.6.tgz", @@ -4036,6 +4103,42 @@ } } }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.13.tgz", + "integrity": "sha512-ARFmqUyhIVS3+riWzwGTe7JLjqwqgnODBUZdqpWar/z1WFs9z76fuOs/2BOWCR+YboRn4/WN9aoaGVwqNRr8VA==", + "license": "MIT", + "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-dismissable-layer": "1.1.9", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.6", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.8", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-slot": "1.2.2", + "@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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-direction": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", @@ -4078,6 +4181,35 @@ } } }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.14.tgz", + "integrity": "sha512-lzuyNjoWOoaMFE/VC5FnAAYM16JmQA8ZmucOXtlhm2kKR5TSU95YLAueQ4JYuRmUJmBvSqXaVFGIfuukybwZJQ==", + "license": "MIT", + "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-menu": "2.1.14", + "@radix-ui/react-primitive": "2.1.2", + "@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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-focus-guards": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", @@ -4159,6 +4291,83 @@ } } }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.14.tgz", + "integrity": "sha512-0zSiBAIFq9GSKoSH5PdEaQeRB3RnEGxC+H2P0egtnKoKKLNBH8VBHyVO6/jskhjAezhOIplyRUj7U2lds9A+Yg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.6", + "@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.9", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.6", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.6", + "@radix-ui/react-portal": "1.1.8", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-roving-focus": "1.1.9", + "@radix-ui/react-slot": "1.2.2", + "@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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.13.tgz", + "integrity": "sha512-84uqQV3omKDR076izYgcha6gdpN8m3z6w/AeJ83MSBJYVG/AbOHdLjAgsPZkeC/kt+k64moXFCnio8BbqXszlw==", + "license": "MIT", + "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-dismissable-layer": "1.1.9", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.6", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.6", + "@radix-ui/react-portal": "1.1.8", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-slot": "1.2.2", + "@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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.6.tgz", @@ -4262,6 +4471,37 @@ } } }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.9.tgz", + "integrity": "sha512-ZzrIFnMYHHCNqSNCsuN6l7wlewBEq0O0BCSBkabJMFXVO51LRUTq71gLP1UxFvmrXElqmPjA5VX7IqC9VpazAQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.6", + "@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.2", + "@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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-select": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.4.tgz", @@ -4305,6 +4545,29 @@ } } }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.6.tgz", + "integrity": "sha512-Izof3lPpbCfTM7WDta+LRkz31jem890VjEvpVRoWQNKpDUMMVffuyq854XPGP1KYGWWmjmYvHvPFeocWhFCy1w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.2.tgz", @@ -4323,6 +4586,40 @@ } } }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.6.tgz", + "integrity": "sha512-zYb+9dc9tkoN2JjBDIIPLQtk3gGyz8FMKoqYTb8EMVQ5a5hBcdHPECrsZVI4NpPAUOixhkoqg7Hj5ry5USowfA==", + "license": "MIT", + "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-dismissable-layer": "1.1.9", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.6", + "@radix-ui/react-portal": "1.1.8", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.2", + "@radix-ui/react-slot": "1.2.2", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", @@ -4393,6 +4690,24 @@ } } }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-layout-effect": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", @@ -5248,6 +5563,32 @@ "tslib": "^2.8.0" } }, + "node_modules/@tabler/icons": { + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.33.0.tgz", + "integrity": "sha512-NZeFfzcYe7xcBHR3zKoCSrw/cFWvfj6LjenPQ48yVMTGdX854HH9nH44ZfMH8rrDzHBllfjwl4CIX6Vh2tyN0Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + } + }, + "node_modules/@tabler/icons-react": { + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.33.0.tgz", + "integrity": "sha512-ay+HDecCjmFl25Lg14hcl59ffSjnOcgfrlV14shu8Qjbz+Xh4LRus93DuoyLQte8YSxE7Pe5gnEz6OF0GtwNtw==", + "license": "MIT", + "dependencies": { + "@tabler/icons": "3.33.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + }, + "peerDependencies": { + "react": ">= 16" + } + }, "node_modules/@tailwindcss/typography": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz", @@ -9046,13 +9387,10 @@ } }, "node_modules/image-size": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.0.tgz", - "integrity": "sha512-4S8fwbO6w3GeCVN6OPtA9I5IGKkcDMPcKndtUlpJuCwu7JLjtj7JZpwqLuyY2nrmQT3AWsCJLSKPsc2mPBSl3w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-2.0.2.tgz", + "integrity": "sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==", "license": "MIT", - "dependencies": { - "queue": "6.0.2" - }, "bin": { "image-size": "bin/image-size.js" }, @@ -11357,13 +11695,13 @@ } }, "node_modules/payload": { - "version": "3.33.0", - "resolved": "https://registry.npmjs.org/payload/-/payload-3.33.0.tgz", - "integrity": "sha512-KXNQf+QFStxNUw4A/poEq8KP0GIR9K5tXzyMN80iwi1+X6V2xEORXs3hm28OQYIuJR4WTHBQzo7VWcQ69oNDcg==", + "version": "3.38.0", + "resolved": "https://registry.npmjs.org/payload/-/payload-3.38.0.tgz", + "integrity": "sha512-A+KpKyn05Y4vlWTH4uAxkMySfBw4rtES1GydzFtjYEN8gxht1yXiK6zhfldGPyJrFuwPkzVpYC/7Lvg20Np7EA==", "license": "MIT", "dependencies": { "@next/env": "^15.1.5", - "@payloadcms/translations": "3.33.0", + "@payloadcms/translations": "3.38.0", "@types/busboy": "1.5.4", "ajv": "8.17.1", "bson-objectid": "2.0.4", @@ -11376,7 +11714,7 @@ "file-type": "19.3.0", "get-tsconfig": "4.8.1", "http-status": "2.1.0", - "image-size": "1.2.0", + "image-size": "2.0.2", "jose": "5.9.6", "json-schema-to-typescript": "15.0.3", "minimist": "1.2.8", @@ -11402,15 +11740,6 @@ "graphql": "^16.8.1" } }, - "node_modules/payload/node_modules/@payloadcms/translations": { - "version": "3.33.0", - "resolved": "https://registry.npmjs.org/@payloadcms/translations/-/translations-3.33.0.tgz", - "integrity": "sha512-QU8EFoporBLdyeGWoWogb6gZMEMopvFHmF43yQDa2TrzWxGtEaSY5pNCvJovQN1aPnLPYaK4we/nX/3ifa4G5Q==", - "license": "MIT", - "dependencies": { - "date-fns": "4.1.0" - } - }, "node_modules/payload/node_modules/ajv": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", @@ -12158,15 +12487,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/queue": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", - "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", - "license": "MIT", - "dependencies": { - "inherits": "~2.0.3" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -12251,6 +12571,20 @@ "url": "https://github.com/sponsors/kossnocorp" } }, + "node_modules/react-day-picker": { + "version": "8.10.1", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.1.tgz", + "integrity": "sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==", + "license": "MIT", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/gpbl" + }, + "peerDependencies": { + "date-fns": "^2.28.0 || ^3.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-diff-viewer-continued": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/react-diff-viewer-continued/-/react-diff-viewer-continued-4.0.5.tgz", @@ -14715,6 +15049,15 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", + "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/utf8-byte-length": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", diff --git a/package.json b/package.json index e7dc5f1..9125b37 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "biotracker", "version": "1.0.0", - "description": "Website template for Payload", + "description": "Iron City Biomechanics: Fitness Tracker for Instructors and Clients", "license": "MIT", "type": "module", "scripts": { @@ -32,21 +32,31 @@ "@payloadcms/plugin-seo": "3.38.0", "@payloadcms/richtext-lexical": "3.38.0", "@payloadcms/ui": "3.38.0", + "@radix-ui/react-avatar": "^1.1.9", "@radix-ui/react-checkbox": "^1.0.4", + "@radix-ui/react-collapsible": "^1.1.10", + "@radix-ui/react-dialog": "^1.1.13", + "@radix-ui/react-dropdown-menu": "^2.1.14", "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-popover": "^1.1.13", "@radix-ui/react-select": "^2.0.0", - "@radix-ui/react-slot": "^1.0.2", - "class-variance-authority": "^0.7.0", + "@radix-ui/react-separator": "^1.1.6", + "@radix-ui/react-slot": "^1.2.2", + "@radix-ui/react-tooltip": "^1.2.6", + "@tabler/icons-react": "^3.33.0", + "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cross-env": "^7.0.3", + "date-fns": "^4.1.0", "geist": "^1.3.0", "graphql": "^16.8.2", "lucide-react": "^0.378.0", "next": "15.3.0", "next-sitemap": "^4.2.3", - "payload": "3.33.0", + "payload": "3.38.0", "prism-react-renderer": "^2.3.1", "react": "19.1.0", + "react-day-picker": "^8.10.1", "react-dom": "19.1.0", "react-hook-form": "7.45.4", "sharp": "0.32.6", diff --git a/src/app/(frontend)/globals.css b/src/app/(frontend)/globals.css index 2c785c1..7178694 100644 --- a/src/app/(frontend)/globals.css +++ b/src/app/(frontend)/globals.css @@ -47,6 +47,14 @@ --success: 196 52% 74%; --warning: 34 89% 85%; --error: 10 100% 86%; + --sidebar-background: 0 0% 98%; + --sidebar-foreground: 240 5.3% 26.1%; + --sidebar-primary: 240 5.9% 10%; + --sidebar-primary-foreground: 0 0% 98%; + --sidebar-accent: 240 4.8% 95.9%; + --sidebar-accent-foreground: 240 5.9% 10%; + --sidebar-border: 220 13% 91%; + --sidebar-ring: 217.2 91.2% 59.8%; } [data-theme='dark'] { @@ -82,6 +90,16 @@ --warning: 34 51% 25%; --error: 10 39% 43%; } + .dark { + --sidebar-background: 240 5.9% 10%; + --sidebar-foreground: 240 4.8% 95.9%; + --sidebar-primary: 224.3 76.3% 48%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 240 3.7% 15.9%; + --sidebar-accent-foreground: 240 4.8% 95.9%; + --sidebar-border: 240 3.7% 15.9%; + --sidebar-ring: 217.2 91.2% 59.8%; + } } @layer base { @@ -101,3 +119,14 @@ html[data-theme='dark'], html[data-theme='light'] { opacity: initial; } + + + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx new file mode 100644 index 0000000..e6fe49d --- /dev/null +++ b/src/app/dashboard/page.tsx @@ -0,0 +1,44 @@ +import { SidebarLeft } from "@/components/sidebar-left" +import { SidebarRight } from "@/components/sidebar-right" +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbList, + BreadcrumbPage, +} from "@/components/ui/breadcrumb" +import { Separator } from "@/components/ui/separator" +import { + SidebarInset, + SidebarProvider, + SidebarTrigger, +} from "@/components/ui/sidebar" + +export default function Page() { + return ( + + + +
+
+ + + + + + + Project Management & Task Tracking + + + + +
+
+
+
+
+
+ + + + ) +} diff --git a/src/components/calendars.tsx b/src/components/calendars.tsx new file mode 100644 index 0000000..9a14ffa --- /dev/null +++ b/src/components/calendars.tsx @@ -0,0 +1,71 @@ +import * as React from "react" +import { Check, ChevronRight } from "lucide-react" + +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/components/ui/collapsible" +import { + SidebarGroup, + SidebarGroupContent, + SidebarGroupLabel, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + SidebarSeparator, +} from "@/components/ui/sidebar" + +export function Calendars({ + calendars, +}: { + calendars: { + name: string + items: string[] + }[] +}) { + return ( + <> + {calendars.map((calendar, index) => ( + + + + + + {calendar.name}{" "} + + + + + + + {calendar.items.map((item, index) => ( + + +
+ +
+ {item} +
+
+ ))} +
+
+
+
+
+ +
+ ))} + + ) +} diff --git a/src/components/date-picker.tsx b/src/components/date-picker.tsx new file mode 100644 index 0000000..5abd465 --- /dev/null +++ b/src/components/date-picker.tsx @@ -0,0 +1,15 @@ +import { Calendar } from "@/components/ui/calendar" +import { + SidebarGroup, + SidebarGroupContent, +} from "@/components/ui/sidebar" + +export function DatePicker() { + return ( + + + + + + ) +} diff --git a/src/components/nav-favorites.tsx b/src/components/nav-favorites.tsx new file mode 100644 index 0000000..34e2aea --- /dev/null +++ b/src/components/nav-favorites.tsx @@ -0,0 +1,94 @@ +"use client" + +import { + ArrowUpRight, + Link, + MoreHorizontal, + StarOff, + Trash2, +} from "lucide-react" + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { + SidebarGroup, + SidebarGroupLabel, + SidebarMenu, + SidebarMenuAction, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "@/components/ui/sidebar" + +export function NavFavorites({ + favorites, +}: { + favorites: { + name: string + url: string + emoji: string + }[] +}) { + const { isMobile } = useSidebar() + + return ( + + Favorites + + {favorites.map((item) => ( + + + + {item.emoji} + {item.name} + + + + + + + More + + + + + + Remove from Favorites + + + + + Copy Link + + + + Open in New Tab + + + + + Delete + + + + + ))} + + + + More + + + + + ) +} diff --git a/src/components/nav-main.tsx b/src/components/nav-main.tsx new file mode 100644 index 0000000..31edc97 --- /dev/null +++ b/src/components/nav-main.tsx @@ -0,0 +1,35 @@ +"use client" + +import { type LucideIcon } from "lucide-react" + +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, +} from "@/components/ui/sidebar" + +export function NavMain({ + items, +}: { + items: { + title: string + url: string + icon: LucideIcon + isActive?: boolean + }[] +}) { + return ( + + {items.map((item) => ( + + + + + {item.title} + + + + ))} + + ) +} diff --git a/src/components/nav-secondary.tsx b/src/components/nav-secondary.tsx new file mode 100644 index 0000000..71d2ebf --- /dev/null +++ b/src/components/nav-secondary.tsx @@ -0,0 +1,43 @@ +import React from "react" +import { type LucideIcon } from "lucide-react" + +import { + SidebarGroup, + SidebarGroupContent, + SidebarMenu, + SidebarMenuBadge, + SidebarMenuButton, + SidebarMenuItem, +} from "@/components/ui/sidebar" + +export function NavSecondary({ + items, + ...props +}: { + items: { + title: string + url: string + icon: LucideIcon + badge?: React.ReactNode + }[] +} & React.ComponentPropsWithoutRef) { + return ( + + + + {items.map((item) => ( + + + + + {item.title} + + + {item.badge && {item.badge}} + + ))} + + + + ) +} diff --git a/src/components/nav-user.tsx b/src/components/nav-user.tsx new file mode 100644 index 0000000..239d4ba --- /dev/null +++ b/src/components/nav-user.tsx @@ -0,0 +1,114 @@ +"use client" + +import { + BadgeCheck, + Bell, + ChevronsUpDown, + CreditCard, + LogOut, + Sparkles, +} from "lucide-react" + +import { + Avatar, + AvatarFallback, + AvatarImage, +} from "@/components/ui/avatar" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "@/components/ui/sidebar" + +export function NavUser({ + user, +}: { + user: { + name: string + email: string + avatar: string + } +}) { + const { isMobile } = useSidebar() + + return ( + + + + + + + + CN + +
+ {user.name} + {user.email} +
+ +
+
+ + +
+ + + CN + +
+ {user.name} + {user.email} +
+
+
+ + + + + Upgrade to Pro + + + + + + + Account + + + + Billing + + + + Notifications + + + + + + Log out + +
+
+
+
+ ) +} diff --git a/src/components/nav-workspaces.tsx b/src/components/nav-workspaces.tsx new file mode 100644 index 0000000..a9627f1 --- /dev/null +++ b/src/components/nav-workspaces.tsx @@ -0,0 +1,85 @@ +import { ChevronRight, MoreHorizontal, Plus } from "lucide-react" + +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/components/ui/collapsible" +import { + SidebarGroup, + SidebarGroupContent, + SidebarGroupLabel, + SidebarMenu, + SidebarMenuAction, + SidebarMenuButton, + SidebarMenuItem, + SidebarMenuSub, + SidebarMenuSubButton, + SidebarMenuSubItem, +} from "@/components/ui/sidebar" + +export function NavWorkspaces({ + workspaces, +}: { + workspaces: { + name: string + emoji: React.ReactNode + pages: { + name: string + emoji: React.ReactNode + }[] + }[] +}) { + return ( + + Workspaces + + + {workspaces.map((workspace) => ( + + + + + {workspace.emoji} + {workspace.name} + + + + + + + + + + + + + {workspace.pages.map((page) => ( + + + + {page.emoji} + {page.name} + + + + ))} + + + + + ))} + + + + More + + + + + + ) +} diff --git a/src/components/sidebar-left.tsx b/src/components/sidebar-left.tsx new file mode 100644 index 0000000..e5e52ce --- /dev/null +++ b/src/components/sidebar-left.tsx @@ -0,0 +1,278 @@ +"use client" + +import * as React from "react" +import { + AudioWaveform, + Blocks, + Calendar, + Command, + Home, + Inbox, + MessageCircleQuestion, + Search, + Settings2, + Sparkles, + Trash2, +} from "lucide-react" + +import { NavFavorites } from "@/components/nav-favorites" +import { NavMain } from "@/components/nav-main" +import { NavSecondary } from "@/components/nav-secondary" +import { NavWorkspaces } from "@/components/nav-workspaces" +import { TeamSwitcher } from "@/components/team-switcher" +import { + Sidebar, + SidebarContent, + SidebarHeader, + SidebarRail, +} from "@/components/ui/sidebar" + +// This is sample data. +const data = { + teams: [ + { + name: "Acme Inc", + logo: Command, + plan: "Enterprise", + }, + { + name: "Acme Corp.", + logo: AudioWaveform, + plan: "Startup", + }, + { + name: "Evil Corp.", + logo: Command, + plan: "Free", + }, + ], + navMain: [ + { + title: "Search", + url: "#", + icon: Search, + }, + { + title: "Ask AI", + url: "#", + icon: Sparkles, + }, + { + title: "Home", + url: "#", + icon: Home, + isActive: true, + }, + { + title: "Inbox", + url: "#", + icon: Inbox, + badge: "10", + }, + ], + navSecondary: [ + { + title: "Calendar", + url: "#", + icon: Calendar, + }, + { + title: "Settings", + url: "#", + icon: Settings2, + }, + { + title: "Templates", + url: "#", + icon: Blocks, + }, + { + title: "Trash", + url: "#", + icon: Trash2, + }, + { + title: "Help", + url: "#", + icon: MessageCircleQuestion, + }, + ], + favorites: [ + { + name: "Project Management & Task Tracking", + url: "#", + emoji: "πŸ“Š", + }, + { + name: "Family Recipe Collection & Meal Planning", + url: "#", + emoji: "🍳", + }, + { + name: "Fitness Tracker & Workout Routines", + url: "#", + emoji: "πŸ’ͺ", + }, + { + name: "Book Notes & Reading List", + url: "#", + emoji: "πŸ“š", + }, + { + name: "Sustainable Gardening Tips & Plant Care", + url: "#", + emoji: "🌱", + }, + { + name: "Language Learning Progress & Resources", + url: "#", + emoji: "πŸ—£οΈ", + }, + { + name: "Home Renovation Ideas & Budget Tracker", + url: "#", + emoji: "🏠", + }, + { + name: "Personal Finance & Investment Portfolio", + url: "#", + emoji: "πŸ’°", + }, + { + name: "Movie & TV Show Watchlist with Reviews", + url: "#", + emoji: "🎬", + }, + { + name: "Daily Habit Tracker & Goal Setting", + url: "#", + emoji: "βœ…", + }, + ], + workspaces: [ + { + name: "Personal Life Management", + emoji: "🏠", + pages: [ + { + name: "Daily Journal & Reflection", + url: "#", + emoji: "πŸ“”", + }, + { + name: "Health & Wellness Tracker", + url: "#", + emoji: "🍏", + }, + { + name: "Personal Growth & Learning Goals", + url: "#", + emoji: "🌟", + }, + ], + }, + { + name: "Professional Development", + emoji: "πŸ’Ό", + pages: [ + { + name: "Career Objectives & Milestones", + url: "#", + emoji: "🎯", + }, + { + name: "Skill Acquisition & Training Log", + url: "#", + emoji: "🧠", + }, + { + name: "Networking Contacts & Events", + url: "#", + emoji: "🀝", + }, + ], + }, + { + name: "Creative Projects", + emoji: "🎨", + pages: [ + { + name: "Writing Ideas & Story Outlines", + url: "#", + emoji: "✍️", + }, + { + name: "Art & Design Portfolio", + url: "#", + emoji: "πŸ–ΌοΈ", + }, + { + name: "Music Composition & Practice Log", + url: "#", + emoji: "🎡", + }, + ], + }, + { + name: "Home Management", + emoji: "🏑", + pages: [ + { + name: "Household Budget & Expense Tracking", + url: "#", + emoji: "πŸ’°", + }, + { + name: "Home Maintenance Schedule & Tasks", + url: "#", + emoji: "πŸ”§", + }, + { + name: "Family Calendar & Event Planning", + url: "#", + emoji: "πŸ“…", + }, + ], + }, + { + name: "Travel & Adventure", + emoji: "🧳", + pages: [ + { + name: "Trip Planning & Itineraries", + url: "#", + emoji: "πŸ—ΊοΈ", + }, + { + name: "Travel Bucket List & Inspiration", + url: "#", + emoji: "🌎", + }, + { + name: "Travel Journal & Photo Gallery", + url: "#", + emoji: "πŸ“Έ", + }, + ], + }, + ], +} + +export function SidebarLeft({ + ...props +}: React.ComponentProps) { + return ( + + + + + + + + + + + + + ) +} diff --git a/src/components/sidebar-right.tsx b/src/components/sidebar-right.tsx new file mode 100644 index 0000000..c28d8ca --- /dev/null +++ b/src/components/sidebar-right.tsx @@ -0,0 +1,71 @@ +import * as React from "react" +import { Plus } from "lucide-react" + +import { Calendars } from "@/components/calendars" +import { DatePicker } from "@/components/date-picker" +import { NavUser } from "@/components/nav-user" +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarHeader, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + SidebarRail, + SidebarSeparator, +} from "@/components/ui/sidebar" + +// This is sample data. +const data = { + user: { + name: "shadcn", + email: "m@example.com", + avatar: "/avatars/shadcn.jpg", + }, + calendars: [ + { + name: "My Calendars", + items: ["Personal", "Work", "Family"], + }, + { + name: "Favorites", + items: ["Holidays", "Birthdays"], + }, + { + name: "Other", + items: ["Travel", "Reminders", "Deadlines"], + }, + ], +} + +export function SidebarRight({ + ...props +}: React.ComponentProps) { + return ( + + + + + + + + + + + + + + + New Calendar + + + + + + ) +} diff --git a/src/components/team-switcher.tsx b/src/components/team-switcher.tsx new file mode 100644 index 0000000..e0ecfab --- /dev/null +++ b/src/components/team-switcher.tsx @@ -0,0 +1,83 @@ +"use client" + +import * as React from "react" +import { ChevronDown, Plus } from "lucide-react" + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, +} from "@/components/ui/sidebar" + +export function TeamSwitcher({ + teams, +}: { + teams: { + name: string + logo: React.ElementType + plan: string + }[] +}) { + const [activeTeam, setActiveTeam] = React.useState(teams[0]) + + if (!activeTeam) { + return null + } + + return ( + + + + + +
+ +
+ {activeTeam.name} + +
+
+ + + Teams + + {teams.map((team, index) => ( + setActiveTeam(team)} + className="gap-2 p-2" + > +
+ +
+ {team.name} + ⌘{index + 1} +
+ ))} + + +
+ +
+
Add team
+
+
+
+
+
+ ) +} diff --git a/src/components/ui/avatar.tsx b/src/components/ui/avatar.tsx new file mode 100644 index 0000000..51e507b --- /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/breadcrumb.tsx b/src/components/ui/breadcrumb.tsx new file mode 100644 index 0000000..60e6c96 --- /dev/null +++ b/src/components/ui/breadcrumb.tsx @@ -0,0 +1,115 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { ChevronRight, MoreHorizontal } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Breadcrumb = React.forwardRef< + HTMLElement, + React.ComponentPropsWithoutRef<"nav"> & { + separator?: React.ReactNode + } +>(({ ...props }, ref) =>