From d5b4a1800f0268b2a2adf7959653f32bfc475e60 Mon Sep 17 00:00:00 2001 From: "ALMAZROUEI Shamma (2021) WKIS203" <shamma.almazrouei.2021@live.rhul.ac.uk> Date: Tue, 11 Mar 2025 10:58:52 +0530 Subject: [PATCH] Build the header --- golden-crust-bakery/eslint.config.js | 11 +- golden-crust-bakery/index.html | 11 +- golden-crust-bakery/package-lock.json | 864 +++++++++++++++++- golden-crust-bakery/package.json | 9 +- golden-crust-bakery/src/App.jsx | 14 +- golden-crust-bakery/src/components/Header.jsx | 267 ++++++ .../src/components/ui/button.jsx | 48 + .../src/components/ui/dropdown-menu.jsx | 156 ++++ .../src/components/ui/input.jsx | 19 + .../src/components/ui/sheet.jsx | 108 +++ .../src/components/ui/sonner.jsx | 28 + golden-crust-bakery/src/lib/authStore.js | 37 + golden-crust-bakery/src/lib/data.js | 146 +++ golden-crust-bakery/src/lib/orderStore.js | 36 + golden-crust-bakery/src/lib/store.js | 49 + golden-crust-bakery/src/main.jsx | 14 +- golden-crust-bakery/src/pages/Landing.jsx | 0 golden-crust-bakery/tailwind.config.js | 110 +-- 18 files changed, 1862 insertions(+), 65 deletions(-) create mode 100644 golden-crust-bakery/src/components/Header.jsx create mode 100644 golden-crust-bakery/src/components/ui/button.jsx create mode 100644 golden-crust-bakery/src/components/ui/dropdown-menu.jsx create mode 100644 golden-crust-bakery/src/components/ui/input.jsx create mode 100644 golden-crust-bakery/src/components/ui/sheet.jsx create mode 100644 golden-crust-bakery/src/components/ui/sonner.jsx create mode 100644 golden-crust-bakery/src/lib/authStore.js create mode 100644 golden-crust-bakery/src/lib/data.js create mode 100644 golden-crust-bakery/src/lib/orderStore.js create mode 100644 golden-crust-bakery/src/lib/store.js create mode 100644 golden-crust-bakery/src/pages/Landing.jsx diff --git a/golden-crust-bakery/eslint.config.js b/golden-crust-bakery/eslint.config.js index ec2b712..abfe4ae 100644 --- a/golden-crust-bakery/eslint.config.js +++ b/golden-crust-bakery/eslint.config.js @@ -1,7 +1,7 @@ -import js from '@eslint/js' -import globals from 'globals' -import reactHooks from 'eslint-plugin-react-hooks' -import reactRefresh from 'eslint-plugin-react-refresh' +import js from '@eslint/js'; +import globals from 'globals'; +import reactHooks from 'eslint-plugin-react-hooks'; +import reactRefresh from 'eslint-plugin-react-refresh'; export default [ { ignores: ['dist'] }, @@ -23,6 +23,7 @@ export default [ rules: { ...js.configs.recommended.rules, ...reactHooks.configs.recommended.rules, + 'react/prop-types': 'off', 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], 'react-refresh/only-export-components': [ 'warn', @@ -30,4 +31,4 @@ export default [ ], }, }, -] +]; diff --git a/golden-crust-bakery/index.html b/golden-crust-bakery/index.html index 6b4c961..c05cbe1 100644 --- a/golden-crust-bakery/index.html +++ b/golden-crust-bakery/index.html @@ -3,14 +3,23 @@ <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" /> + + <link rel="preconnect" href="https://fonts.googleapis.com" /> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> + <link + href="https://fonts.googleapis.com/css2?family=Baskervville:ital@0;1&family=Fredoka:wght@300..700&family=Satisfy&display=swap" + rel="stylesheet" + /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="description" content="Golden Crust Bakery offers a delightful selection of freshly baked cakes for every occasion. Customize your orders, explore unique flavors, and enjoy doorstep delivery with ease. Taste the joy, one slice at a time!" /> + <title>Golden Crust Bakery - Sweetness Baked to Perfection</title> </head> - <body> + <body class="antialiased"> <div id="root"></div> <script type="module" src="/src/main.jsx"></script> </body> diff --git a/golden-crust-bakery/package-lock.json b/golden-crust-bakery/package-lock.json index b11267e..5eb7f30 100644 --- a/golden-crust-bakery/package-lock.json +++ b/golden-crust-bakery/package-lock.json @@ -8,13 +8,20 @@ "name": "golden-crust-bakery", "version": "0.0.0", "dependencies": { + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-dropdown-menu": "^2.1.6", + "@radix-ui/react-slot": "^1.1.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.479.0", + "next-themes": "^0.4.5", "react": "^19.0.0", "react-dom": "^19.0.0", + "react-router-dom": "^7.3.0", + "sonner": "^2.0.1", "tailwind-merge": "^3.0.2", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zustand": "^5.0.3" }, "devDependencies": { "@eslint/js": "^9.21.0", @@ -915,6 +922,44 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", + "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.13", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz", + "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "license": "MIT" + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1091,6 +1136,556 @@ "node": ">=14" } }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz", + "integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.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-collection": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz", + "integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.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-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "license": "MIT", + "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-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "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-dialog": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.6.tgz", + "integrity": "sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.5", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.2", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-portal": "1.1.4", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.1.0", + "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.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", + "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "license": "MIT", + "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-dismissable-layer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz", + "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.6.tgz", + "integrity": "sha512-no3X7V5fD487wab/ZYSHXq3H37u4NVeLDKI/Ks724X/eEFSSEFYZxWgsIlr1UBeEyDaM29HM5x9p1Nv8DuTYPA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-menu": "2.1.6", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", + "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", + "license": "MIT", + "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-focus-scope": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz", + "integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.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-menu": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.6.tgz", + "integrity": "sha512-tBBb5CXDJW3t2mo9WlO7r6GTmWV0F0uzHZVFmlRmYpiSK1CDU5IKojP1pm7oknpBOrFZx/YgBRW9oorPO2S/Lg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.5", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.2", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.2", + "@radix-ui/react-portal": "1.1.4", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-roving-focus": "1.1.2", + "@radix-ui/react-slot": "1.1.2", + "@radix-ui/react-use-callback-ref": "1.1.0", + "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.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz", + "integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz", + "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", + "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.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-roving-focus": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz", + "integrity": "sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz", + "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "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-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "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-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.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-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.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.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "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-rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", + "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.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-size": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.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/rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==", + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.35.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz", @@ -1402,6 +1997,12 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -1420,7 +2021,7 @@ "version": "19.0.10", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz", "integrity": "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -1430,7 +2031,7 @@ "version": "19.0.4", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.4.tgz", "integrity": "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.0.0" @@ -1555,6 +2156,18 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/aria-hidden": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", + "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/autoprefixer": { "version": "10.4.21", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", @@ -1822,6 +2435,15 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1852,7 +2474,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/debug": { @@ -1880,6 +2502,12 @@ "dev": true, "license": "MIT" }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -2337,6 +2965,15 @@ "node": ">=6.9.0" } }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -2799,6 +3436,16 @@ "dev": true, "license": "MIT" }, + "node_modules/next-themes": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.5.tgz", + "integrity": "sha512-E8/gYKBxZknOXBiDk/sRokAvkOw35PTUD4Gxtq1eBhd0r4Dx5S42zU65/q8ozR5rcSG2ZlE1E3+ShlUpC7an+A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", @@ -3209,6 +3856,115 @@ "node": ">=0.10.0" } }, + "node_modules/react-remove-scroll": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz", + "integrity": "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-router": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.3.0.tgz", + "integrity": "sha512-466f2W7HIWaNXTKM5nHTqNxLrHTyXybm7R0eBlVSt0k/u55tTCDO194OIx/NrYD4TS5SXKTNekXfT37kMKUjgw==", + "license": "MIT", + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.3.0.tgz", + "integrity": "sha512-z7Q5FTiHGgQfEurX/FBinkOXhWREJIAB2RiU24lvcBa82PxUpwqvs/PAXb9lJyPjTs2jrl6UkLvCZVGJPeNuuQ==", + "license": "MIT", + "dependencies": { + "react-router": "7.3.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -3348,6 +4104,12 @@ "semver": "bin/semver.js" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -3381,6 +4143,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/sonner": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.1.tgz", + "integrity": "sha512-FRBphaehZ5tLdLcQ8g2WOIRE+Y7BCfWi5Zyd8bCvBjiW8TxxAyoWZIxS661Yz6TGPqFQ4VLzOF89WEYhfynSFQ==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -3641,6 +4413,18 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "license": "Apache-2.0" }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/turbo-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==", + "license": "ISC" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -3695,6 +4479,49 @@ "punycode": "^2.1.0" } }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -3917,6 +4744,35 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz", + "integrity": "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/golden-crust-bakery/package.json b/golden-crust-bakery/package.json index e6326e9..dba008d 100644 --- a/golden-crust-bakery/package.json +++ b/golden-crust-bakery/package.json @@ -10,13 +10,20 @@ "preview": "vite preview" }, "dependencies": { + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-dropdown-menu": "^2.1.6", + "@radix-ui/react-slot": "^1.1.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.479.0", + "next-themes": "^0.4.5", "react": "^19.0.0", "react-dom": "^19.0.0", + "react-router-dom": "^7.3.0", + "sonner": "^2.0.1", "tailwind-merge": "^3.0.2", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zustand": "^5.0.3" }, "devDependencies": { "@eslint/js": "^9.21.0", diff --git a/golden-crust-bakery/src/App.jsx b/golden-crust-bakery/src/App.jsx index 1f1b34b..fd5f888 100644 --- a/golden-crust-bakery/src/App.jsx +++ b/golden-crust-bakery/src/App.jsx @@ -1,3 +1,15 @@ +import { Outlet } from 'react-router-dom'; + +import Header from './components/Header'; + export default function App() { - return <div>App</div>; + return ( + <> + <Header /> + <main> + <Outlet /> + </main> + {/* <Footer /> */} + </> + ); } diff --git a/golden-crust-bakery/src/components/Header.jsx b/golden-crust-bakery/src/components/Header.jsx new file mode 100644 index 0000000..8669237 --- /dev/null +++ b/golden-crust-bakery/src/components/Header.jsx @@ -0,0 +1,267 @@ +import { useState, useEffect } from 'react'; +import { Link, useLocation, useNavigate } from 'react-router-dom'; +import { Cake, LogOut, Menu, ShoppingBag, User, X } from 'lucide-react'; + +import { useCartStore } from '@/lib/store'; +import { useAuthStore } from '@/lib/authStore'; + +import { Button } from '@/components/ui/button'; +import { + Sheet, + SheetContent, + SheetDescription, + SheetTitle, + SheetTrigger, +} from '@/components/ui/sheet'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; + +export default function Header() { + const pathname = useLocation().pathname; + const navigate = useNavigate(); + + const { cart, initializeCart } = useCartStore(); + const { user, isAuthenticated, logout } = useAuthStore(); + const [isScrolled, setIsScrolled] = useState(false); + const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); + + useEffect(() => { + initializeCart(); + + const handleScroll = () => { + setIsScrolled(window.scrollY > 10); + }; + + window.addEventListener('scroll', handleScroll); + return () => window.removeEventListener('scroll', handleScroll); + }, [initializeCart]); + + const totalItems = cart.reduce((total, item) => total + item.quantity, 0); + + const navItems = [ + { name: 'Home', path: '/' }, + { name: 'Menu', path: '/menu' }, + { name: 'About', path: '/about' }, + { name: 'Contact', path: '/contact' }, + ]; + + const handleLogout = () => { + logout(); + navigate('/'); + }; + + return ( + <header + className={`sticky top-0 z-50 w-full transition-all duration-200 ${ + isScrolled ? 'bg-white shadow-sm' : 'bg-transparent' + }`} + > + <div className='container mx-auto px-4 md:px-6'> + <div className='flex h-20 items-center justify-between'> + <Link to='/' className='inline-flex items-center space-x-2'> + <Cake className='h-8 w-8 text-pink-500' /> + <span className='font-bold mt-2.5 text-xl font-script text-gray-800'> + Golden Crust <span className='hidden md:inline'>Bakery</span> + </span> + </Link> + + <nav className='hidden md:flex items-center space-x-8'> + {navItems.map((item) => ( + <Link + key={item.path} + to={item.path} + className={`font-medium transition-colors hover:text-pink-500 ${ + pathname === item.path ? 'text-pink-500' : 'text-gray-600' + }`} + > + {item.name} + </Link> + ))} + + {isAuthenticated && ( + <Link + to='/orders' + className={`font-medium transition-colors hover:text-pink-500 ${ + pathname === '/orders' ? 'text-pink-500' : 'text-gray-600' + }`} + > + My Orders + </Link> + )} + </nav> + + <div className='flex items-center space-x-4'> + {isAuthenticated ? ( + <> + <Button + variant='ghost' + size='icon' + onClick={() => navigate('/cart')} + className='relative' + aria-label='Shopping cart' + > + <ShoppingBag className='h-6 w-6 text-gray-700' /> + {totalItems > 0 && ( + <span className='absolute -top-1 -right-1 flex h-5 w-5 items-center justify-center rounded-full bg-pink-500 text-xs font-medium text-white'> + {totalItems} + </span> + )} + </Button> + + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button + variant='ghost' + size='icon' + className='relative' + aria-label='User menu' + > + <User className='h-6 w-6 text-gray-700' /> + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent align='end' className='w-56'> + <DropdownMenuLabel> + <div className='flex flex-col'> + <span>My Account</span> + <span className='text-xs font-normal text-gray-500'> + {user?.email} + </span> + </div> + </DropdownMenuLabel> + <DropdownMenuSeparator /> + <DropdownMenuItem onClick={() => navigate('/profile')}> + <User className='mr-2 h-4 w-4' /> Profile + </DropdownMenuItem> + <DropdownMenuItem onClick={() => navigate('/orders')}> + <ShoppingBag className='mr-2 h-4 w-4' /> My Orders + </DropdownMenuItem> + <DropdownMenuSeparator /> + <DropdownMenuItem onClick={handleLogout}> + <LogOut className='mr-2 h-4 w-4' /> Logout + </DropdownMenuItem> + </DropdownMenuContent> + </DropdownMenu> + </> + ) : ( + <Button + onClick={() => navigate('/login')} + className='bg-pink-500 hover:bg-pink-600 text-white rounded-full' + > + Sign In + </Button> + )} + + <Sheet open={isMobileMenuOpen} onOpenChange={setIsMobileMenuOpen}> + <SheetTitle className='sr-only'>Menu</SheetTitle> + <SheetDescription className='sr-only'> + Menubar for mobile devices. Not visible on desktop. + </SheetDescription> + <SheetTrigger asChild> + <Button + variant='ghost' + size='icon' + className='md:hidden' + aria-label='Menu' + > + <Menu className='h-6 w-6 text-gray-700' /> + </Button> + </SheetTrigger> + <SheetContent side='right' className='w-[300px] sm:w-[400px]'> + <div className='flex flex-col h-full'> + <div className='flex items-center justify-between mb-6'> + <div className='flex items-center space-x-2'> + <Cake className='h-6 w-6 text-pink-500' /> + <span className='font-bold font-script mt-2 text-lg text-gray-900'> + Golden Crust + </span> + </div> + </div> + <nav className='flex flex-col space-y-4'> + {navItems.map((item) => ( + <Link + key={item.path} + to={item.path} + className={`text-base font-medium transition-colors hover:text-pink-500 ${ + pathname === item.path + ? 'text-pink-500' + : 'text-gray-600' + }`} + onClick={() => setIsMobileMenuOpen(false)} + > + {item.name} + </Link> + ))} + {isAuthenticated && ( + <Link + to='/orders' + className={`text-base font-medium transition-colors hover:text-pink-500 ${ + pathname === '/orders' + ? 'text-pink-500' + : 'text-gray-600' + }`} + onClick={() => setIsMobileMenuOpen(false)} + > + My Orders + </Link> + )} + </nav> + <div className='mt-auto pt-6'> + {isAuthenticated ? ( + <> + <Button + onClick={() => { + navigate('/cart'); + setIsMobileMenuOpen(false); + }} + className='w-full bg-pink-500 hover:bg-pink-600 text-white rounded-full mb-4' + > + <ShoppingBag className='mr-2 h-4 w-4' /> + View Cart {totalItems > 0 && `(${totalItems})`} + </Button> + <Button + variant='outline' + onClick={handleLogout} + className='w-full border-red-300 text-red-600 hover:bg-red-50 rounded-full' + > + <LogOut className='mr-2 h-4 w-4' /> Logout + </Button> + </> + ) : ( + <div className='space-y-4'> + <Button + onClick={() => { + navigate('/login'); + setIsMobileMenuOpen(false); + }} + className='w-full bg-pink-500 hover:bg-pink-600 text-white rounded-full' + > + Sign In + </Button> + <Button + variant='outline' + onClick={() => { + navigate('/register'); + setIsMobileMenuOpen(false); + }} + className='w-full border-pink-300 text-pink-600 hover:bg-pink-50 rounded-full' + > + Create Account + </Button> + </div> + )} + </div> + </div> + </SheetContent> + </Sheet> + </div> + </div> + </div> + </header> + ); +} diff --git a/golden-crust-bakery/src/components/ui/button.jsx b/golden-crust-bakery/src/components/ui/button.jsx new file mode 100644 index 0000000..d57408f --- /dev/null +++ b/golden-crust-bakery/src/components/ui/button.jsx @@ -0,0 +1,48 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva } from "class-variance-authority"; + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", + outline: + "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2", + sm: "h-8 rounded-md px-3 text-xs", + lg: "h-10 rounded-md px-8", + icon: "h-9 w-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button" + return ( + <Comp + className={cn(buttonVariants({ variant, size, className }))} + ref={ref} + {...props} /> + ); +}) +Button.displayName = "Button" + +export { Button, buttonVariants } diff --git a/golden-crust-bakery/src/components/ui/dropdown-menu.jsx b/golden-crust-bakery/src/components/ui/dropdown-menu.jsx new file mode 100644 index 0000000..46c5386 --- /dev/null +++ b/golden-crust-bakery/src/components/ui/dropdown-menu.jsx @@ -0,0 +1,156 @@ +import * as React from "react" +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" +import { Check, ChevronRight, Circle } from "lucide-react" + +import { cn } from "@/lib/utils" + +const DropdownMenu = DropdownMenuPrimitive.Root + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger + +const DropdownMenuGroup = DropdownMenuPrimitive.Group + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal + +const DropdownMenuSub = DropdownMenuPrimitive.Sub + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup + +const DropdownMenuSubTrigger = React.forwardRef(({ className, inset, children, ...props }, ref) => ( + <DropdownMenuPrimitive.SubTrigger + ref={ref} + className={cn( + "flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + inset && "pl-8", + className + )} + {...props}> + {children} + <ChevronRight className="ml-auto" /> + </DropdownMenuPrimitive.SubTrigger> +)) +DropdownMenuSubTrigger.displayName = + DropdownMenuPrimitive.SubTrigger.displayName + +const DropdownMenuSubContent = React.forwardRef(({ className, ...props }, ref) => ( + <DropdownMenuPrimitive.SubContent + ref={ref} + className={cn( + "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", + className + )} + {...props} /> +)) +DropdownMenuSubContent.displayName = + DropdownMenuPrimitive.SubContent.displayName + +const DropdownMenuContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => ( + <DropdownMenuPrimitive.Portal> + <DropdownMenuPrimitive.Content + ref={ref} + sideOffset={sideOffset} + className={cn( + "z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md", + "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", + className + )} + {...props} /> + </DropdownMenuPrimitive.Portal> +)) +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName + +const DropdownMenuItem = React.forwardRef(({ className, inset, ...props }, ref) => ( + <DropdownMenuPrimitive.Item + ref={ref} + className={cn( + "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0", + inset && "pl-8", + className + )} + {...props} /> +)) +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName + +const DropdownMenuCheckboxItem = React.forwardRef(({ className, children, checked, ...props }, ref) => ( + <DropdownMenuPrimitive.CheckboxItem + ref={ref} + className={cn( + "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", + className + )} + checked={checked} + {...props}> + <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> + <DropdownMenuPrimitive.ItemIndicator> + <Check className="h-4 w-4" /> + </DropdownMenuPrimitive.ItemIndicator> + </span> + {children} + </DropdownMenuPrimitive.CheckboxItem> +)) +DropdownMenuCheckboxItem.displayName = + DropdownMenuPrimitive.CheckboxItem.displayName + +const DropdownMenuRadioItem = React.forwardRef(({ className, children, ...props }, ref) => ( + <DropdownMenuPrimitive.RadioItem + ref={ref} + className={cn( + "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", + className + )} + {...props}> + <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> + <DropdownMenuPrimitive.ItemIndicator> + <Circle className="h-2 w-2 fill-current" /> + </DropdownMenuPrimitive.ItemIndicator> + </span> + {children} + </DropdownMenuPrimitive.RadioItem> +)) +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName + +const DropdownMenuLabel = React.forwardRef(({ className, inset, ...props }, ref) => ( + <DropdownMenuPrimitive.Label + ref={ref} + className={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)} + {...props} /> +)) +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName + +const DropdownMenuSeparator = React.forwardRef(({ className, ...props }, ref) => ( + <DropdownMenuPrimitive.Separator + ref={ref} + className={cn("-mx-1 my-1 h-px bg-muted", className)} + {...props} /> +)) +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName + +const DropdownMenuShortcut = ({ + className, + ...props +}) => { + return ( + <span + className={cn("ml-auto text-xs tracking-widest opacity-60", className)} + {...props} /> + ); +} +DropdownMenuShortcut.displayName = "DropdownMenuShortcut" + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +} diff --git a/golden-crust-bakery/src/components/ui/input.jsx b/golden-crust-bakery/src/components/ui/input.jsx new file mode 100644 index 0000000..764b48f --- /dev/null +++ b/golden-crust-bakery/src/components/ui/input.jsx @@ -0,0 +1,19 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Input = React.forwardRef(({ className, type, ...props }, ref) => { + return ( + <input + type={type} + className={cn( + "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", + className + )} + ref={ref} + {...props} /> + ); +}) +Input.displayName = "Input" + +export { Input } diff --git a/golden-crust-bakery/src/components/ui/sheet.jsx b/golden-crust-bakery/src/components/ui/sheet.jsx new file mode 100644 index 0000000..6741fcb --- /dev/null +++ b/golden-crust-bakery/src/components/ui/sheet.jsx @@ -0,0 +1,108 @@ +import * as React from "react" +import * as SheetPrimitive from "@radix-ui/react-dialog" +import { cva } from "class-variance-authority"; +import { X } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Sheet = SheetPrimitive.Root + +const SheetTrigger = SheetPrimitive.Trigger + +const SheetClose = SheetPrimitive.Close + +const SheetPortal = SheetPrimitive.Portal + +const SheetOverlay = React.forwardRef(({ className, ...props }, ref) => ( + <SheetPrimitive.Overlay + className={cn( + "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", + className + )} + {...props} + ref={ref} /> +)) +SheetOverlay.displayName = SheetPrimitive.Overlay.displayName + +const sheetVariants = cva( + "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out", + { + variants: { + side: { + top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top", + bottom: + "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom", + left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm", + right: + "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", + }, + }, + defaultVariants: { + side: "right", + }, + } +) + +const SheetContent = React.forwardRef(({ side = "right", className, children, ...props }, ref) => ( + <SheetPortal> + <SheetOverlay /> + <SheetPrimitive.Content ref={ref} className={cn(sheetVariants({ side }), className)} {...props}> + <SheetPrimitive.Close + className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary"> + <X className="h-4 w-4" /> + <span className="sr-only">Close</span> + </SheetPrimitive.Close> + {children} + </SheetPrimitive.Content> + </SheetPortal> +)) +SheetContent.displayName = SheetPrimitive.Content.displayName + +const SheetHeader = ({ + className, + ...props +}) => ( + <div + className={cn("flex flex-col space-y-2 text-center sm:text-left", className)} + {...props} /> +) +SheetHeader.displayName = "SheetHeader" + +const SheetFooter = ({ + className, + ...props +}) => ( + <div + className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)} + {...props} /> +) +SheetFooter.displayName = "SheetFooter" + +const SheetTitle = React.forwardRef(({ className, ...props }, ref) => ( + <SheetPrimitive.Title + ref={ref} + className={cn("text-lg font-semibold text-foreground", className)} + {...props} /> +)) +SheetTitle.displayName = SheetPrimitive.Title.displayName + +const SheetDescription = React.forwardRef(({ className, ...props }, ref) => ( + <SheetPrimitive.Description + ref={ref} + className={cn("text-sm text-muted-foreground", className)} + {...props} /> +)) +SheetDescription.displayName = SheetPrimitive.Description.displayName + +export { + Sheet, + SheetPortal, + SheetOverlay, + SheetTrigger, + SheetClose, + SheetContent, + SheetHeader, + SheetFooter, + SheetTitle, + SheetDescription, +} diff --git a/golden-crust-bakery/src/components/ui/sonner.jsx b/golden-crust-bakery/src/components/ui/sonner.jsx new file mode 100644 index 0000000..354f972 --- /dev/null +++ b/golden-crust-bakery/src/components/ui/sonner.jsx @@ -0,0 +1,28 @@ +import { useTheme } from "next-themes" +import { Toaster as Sonner } from "sonner" + +const Toaster = ({ + ...props +}) => { + const { theme = "system" } = useTheme() + + return ( + <Sonner + theme={theme} + className="toaster group" + toastOptions={{ + classNames: { + toast: + "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg", + description: "group-[.toast]:text-muted-foreground", + actionButton: + "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground", + cancelButton: + "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground", + }, + }} + {...props} /> + ); +} + +export { Toaster } diff --git a/golden-crust-bakery/src/lib/authStore.js b/golden-crust-bakery/src/lib/authStore.js new file mode 100644 index 0000000..8a171a5 --- /dev/null +++ b/golden-crust-bakery/src/lib/authStore.js @@ -0,0 +1,37 @@ +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; + +export const useAuthStore = create( + persist( + (set) => ({ + user: null, + isAuthenticated: false, + + login: (userData) => { + set({ + user: userData, + isAuthenticated: true, + }); + }, + + logout: () => { + set({ + user: null, + isAuthenticated: false, + }); + }, + + updateUser: (userData) => { + set((state) => ({ + user: { + ...state.user, + ...userData, + }, + })); + }, + }), + { + name: 'auth-storage', + } + ) +); diff --git a/golden-crust-bakery/src/lib/data.js b/golden-crust-bakery/src/lib/data.js new file mode 100644 index 0000000..4929e52 --- /dev/null +++ b/golden-crust-bakery/src/lib/data.js @@ -0,0 +1,146 @@ +export const cakeData = [ + { + id: 1, + name: 'Strawberry Delight', + description: + 'Fresh strawberries on a vanilla base with cream cheese frosting. Perfect for summer celebrations.', + price: 32.99, + category: 'Birthday', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 2, + name: 'Chocolate Dream', + description: + "Rich chocolate cake with ganache and chocolate shavings. A chocolate lover's paradise.", + price: 34.99, + category: 'Birthday', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 3, + name: 'Lemon Sunshine', + description: + 'Zesty lemon cake with lemon curd and buttercream. Bright and refreshing for any occasion.', + price: 29.99, + category: 'Special Occasion', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 4, + name: 'Red Velvet Romance', + description: + 'Classic red velvet cake with cream cheese frosting. Elegant and timeless.', + price: 36.99, + category: 'Wedding', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 5, + name: 'Vanilla Bean Dream', + description: + 'Premium vanilla bean cake with vanilla buttercream. Simple yet sophisticated.', + price: 28.99, + category: 'Birthday', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 6, + name: 'Carrot Cake Delight', + description: + 'Moist carrot cake with walnuts and cream cheese frosting. A beloved classic.', + price: 31.99, + category: 'Special Occasion', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 7, + name: 'Tiramisu Cake', + description: + 'Coffee-soaked layers with mascarpone cream and cocoa. An Italian favorite.', + price: 38.99, + category: 'Special Occasion', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 8, + name: 'Wedding Elegance', + description: + 'Three-tier white cake with delicate floral decorations. Perfect for your special day.', + price: 149.99, + category: 'Wedding', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 9, + name: 'Pumpkin Spice', + description: + 'Warm pumpkin cake with cinnamon cream cheese frosting. Ideal for fall celebrations.', + price: 33.99, + category: 'Seasonal', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 10, + name: 'Mint Chocolate Chip', + description: + 'Chocolate cake with mint buttercream and chocolate chips. Refreshingly delicious.', + price: 35.99, + category: 'Birthday', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 11, + name: 'Coconut Paradise', + description: + 'Coconut cake with coconut cream and toasted coconut flakes. A tropical treat.', + price: 32.99, + category: 'Special Occasion', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 12, + name: 'Black Forest', + description: + 'Chocolate cake with cherries and whipped cream. A German classic.', + price: 37.99, + category: 'Birthday', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 13, + name: 'Holiday Spice', + description: + 'Spiced cake with cinnamon, nutmeg, and cloves. Perfect for winter holidays.', + price: 34.99, + category: 'Seasonal', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 14, + name: 'Raspberry Elegance', + description: + 'White cake with raspberry filling and white chocolate buttercream. Delicate and delicious.', + price: 36.99, + category: 'Wedding', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 15, + name: 'Caramel Drizzle', + description: + 'Vanilla cake with caramel filling and salted caramel drizzle. Sweet with a touch of salt.', + price: 33.99, + category: 'Birthday', + image: '/placeholder.svg?height=300&width=300', + }, + { + id: 16, + name: 'Spring Blossom', + description: + 'Light lemon cake with floral decorations. A celebration of spring.', + price: 35.99, + category: 'Seasonal', + image: '/placeholder.svg?height=300&width=300', + }, +]; diff --git a/golden-crust-bakery/src/lib/orderStore.js b/golden-crust-bakery/src/lib/orderStore.js new file mode 100644 index 0000000..e1aa6ab --- /dev/null +++ b/golden-crust-bakery/src/lib/orderStore.js @@ -0,0 +1,36 @@ +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; + +export const useOrderStore = create( + persist( + (set, get) => ({ + orders: [], + + initializeOrders: () => {}, + + addOrder: (order) => { + const { orders } = get(); + set({ orders: [order, ...orders] }); + }, + + cancelOrder: (id) => { + const { orders } = get(); + const updatedOrders = orders.map((order) => + order.id === id ? { ...order, status: 'cancelled' } : order + ); + set({ orders: updatedOrders }); + }, + + updateOrderStatus: (id, status) => { + const { orders } = get(); + const updatedOrders = orders.map((order) => + order.id === id ? { ...order, status } : order + ); + set({ orders: updatedOrders }); + }, + }), + { + name: 'order-storage', + } + ) +); diff --git a/golden-crust-bakery/src/lib/store.js b/golden-crust-bakery/src/lib/store.js new file mode 100644 index 0000000..53ec237 --- /dev/null +++ b/golden-crust-bakery/src/lib/store.js @@ -0,0 +1,49 @@ +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; + +export const useCartStore = create( + persist( + (set, get) => ({ + cart: [], + + initializeCart: () => {}, + + addToCart: (item) => { + const { cart } = get(); + const existingItem = cart.find((cartItem) => cartItem.id === item.id); + + if (existingItem) { + const updatedCart = cart.map((cartItem) => + cartItem.id === item.id + ? { ...cartItem, quantity: cartItem.quantity + item.quantity } + : cartItem + ); + set({ cart: updatedCart }); + } else { + set({ cart: [...cart, item] }); + } + }, + + removeFromCart: (id) => { + const { cart } = get(); + const updatedCart = cart.filter((item) => item.id !== id); + set({ cart: updatedCart }); + }, + + updateQuantity: (id, quantity) => { + const { cart } = get(); + const updatedCart = cart.map((item) => + item.id === id ? { ...item, quantity } : item + ); + set({ cart: updatedCart }); + }, + + clearCart: () => { + set({ cart: [] }); + }, + }), + { + name: 'cart-storage', + } + ) +); diff --git a/golden-crust-bakery/src/main.jsx b/golden-crust-bakery/src/main.jsx index c928043..ca61feb 100644 --- a/golden-crust-bakery/src/main.jsx +++ b/golden-crust-bakery/src/main.jsx @@ -1,11 +1,23 @@ import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; +import { Toaster } from 'sonner'; + +import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import './index.css'; + import App from './App.jsx'; +const router = createBrowserRouter([ + { + path: '/', + element: <App />, + }, +]); + createRoot(document.getElementById('root')).render( <StrictMode> - <App /> + <Toaster /> + <RouterProvider router={router} /> </StrictMode> ); diff --git a/golden-crust-bakery/src/pages/Landing.jsx b/golden-crust-bakery/src/pages/Landing.jsx new file mode 100644 index 0000000..e69de29 diff --git a/golden-crust-bakery/tailwind.config.js b/golden-crust-bakery/tailwind.config.js index b524d55..6f8fa29 100644 --- a/golden-crust-bakery/tailwind.config.js +++ b/golden-crust-bakery/tailwind.config.js @@ -1,57 +1,63 @@ /** @type {import('tailwindcss').Config} */ export default { - darkMode: ['class'], - content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], + darkMode: ['class'], + content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], theme: { - extend: { - 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))' - } - } - } + extend: { + fontFamily: { + sans: ['Fredoka', 'sans-serif'], + serif: ['Baskervville', 'serif'], + script: ['Satisfy', 'cursive'], + }, + + 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: [require("tailwindcss-animate")], + plugins: [require('tailwindcss-animate')], }; -- GitLab