diff --git a/.gitignore b/.gitignore
index 41669ba273..269f3d1295 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,7 @@
node_modules
.DS_Store
+.idea
+.vscode
.env.local
.env.development.local
.env.test.local
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index 9e26dfeeb6..0000000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
\ No newline at end of file
diff --git a/week1/assets/exercises/chat.png b/week1/assets/exercises/chat.png
old mode 100755
new mode 100644
diff --git a/week1/assets/exercises/coin.png b/week1/assets/exercises/coin.png
old mode 100755
new mode 100644
diff --git a/week1/assets/exercises/f-delivery.png b/week1/assets/exercises/f-delivery.png
old mode 100755
new mode 100644
diff --git a/week3/project/e-commerce/.gitignore b/week3/project/e-commerce/.gitignore
new file mode 100644
index 0000000000..a547bf36d8
--- /dev/null
+++ b/week3/project/e-commerce/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/week3/project/e-commerce/README.md b/week3/project/e-commerce/README.md
new file mode 100644
index 0000000000..7059a962ad
--- /dev/null
+++ b/week3/project/e-commerce/README.md
@@ -0,0 +1,12 @@
+# React + Vite
+
+This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
+
+Currently, two official plugins are available:
+
+- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
+
+## Expanding the ESLint configuration
+
+If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
diff --git a/week3/project/e-commerce/eslint.config.js b/week3/project/e-commerce/eslint.config.js
new file mode 100644
index 0000000000..46c5909b9b
--- /dev/null
+++ b/week3/project/e-commerce/eslint.config.js
@@ -0,0 +1,33 @@
+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"] },
+ {
+ files: ["**/*.{js,jsx}"],
+ languageOptions: {
+ ecmaVersion: 2020,
+ globals: globals.browser,
+ parserOptions: {
+ ecmaVersion: "latest",
+ ecmaFeatures: { jsx: true },
+ sourceType: "module",
+ },
+ },
+ plugins: {
+ "react-hooks": reactHooks,
+ "react-refresh": reactRefresh,
+ },
+ rules: {
+ ...js.configs.recommended.rules,
+ ...reactHooks.configs.recommended.rules,
+ "no-unused-vars": ["error", { varsIgnorePattern: "^[A-Z_]" }],
+ "react-refresh/only-export-components": [
+ "warn",
+ { allowConstantExport: true },
+ ],
+ },
+ },
+];
diff --git a/week3/project/e-commerce/index.html b/week3/project/e-commerce/index.html
new file mode 100644
index 0000000000..b7db956ac2
--- /dev/null
+++ b/week3/project/e-commerce/index.html
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+ Ecommerce
+
+
+
+
+
+
diff --git a/week3/project/e-commerce/package.json b/week3/project/e-commerce/package.json
new file mode 100644
index 0000000000..263a5cf08c
--- /dev/null
+++ b/week3/project/e-commerce/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "e-commerce",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "lint": "eslint .",
+ "preview": "vite preview",
+ "prettier": "prettier . --write ."
+ },
+ "dependencies": {
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0",
+ "react-router-dom": "^7.6.2",
+ "react-spinners": "^0.17.0"
+ },
+ "devDependencies": {
+ "@eslint/js": "^9.25.0",
+ "@types/react": "^19.1.2",
+ "@types/react-dom": "^19.1.2",
+ "@vitejs/plugin-react": "^4.4.1",
+ "eslint": "^9.25.0",
+ "eslint-plugin-react-hooks": "^5.2.0",
+ "eslint-plugin-react-refresh": "^0.4.19",
+ "globals": "^16.0.0",
+ "prettier": "^3.6.2",
+ "vite": "^6.3.5"
+ }
+}
diff --git a/week3/project/e-commerce/pnpm-lock.yaml b/week3/project/e-commerce/pnpm-lock.yaml
new file mode 100644
index 0000000000..9317ce0112
--- /dev/null
+++ b/week3/project/e-commerce/pnpm-lock.yaml
@@ -0,0 +1,2425 @@
+lockfileVersion: "9.0"
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+ .:
+ dependencies:
+ react:
+ specifier: ^19.1.0
+ version: 19.1.0
+ react-dom:
+ specifier: ^19.1.0
+ version: 19.1.0(react@19.1.0)
+ react-router-dom:
+ specifier: ^7.6.2
+ version: 7.6.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ react-spinners:
+ specifier: ^0.17.0
+ version: 0.17.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ devDependencies:
+ "@eslint/js":
+ specifier: ^9.25.0
+ version: 9.29.0
+ "@types/react":
+ specifier: ^19.1.2
+ version: 19.1.8
+ "@types/react-dom":
+ specifier: ^19.1.2
+ version: 19.1.6(@types/react@19.1.8)
+ "@vitejs/plugin-react":
+ specifier: ^4.4.1
+ version: 4.5.2(vite@6.3.5)
+ eslint:
+ specifier: ^9.25.0
+ version: 9.29.0
+ eslint-plugin-react-hooks:
+ specifier: ^5.2.0
+ version: 5.2.0(eslint@9.29.0)
+ eslint-plugin-react-refresh:
+ specifier: ^0.4.19
+ version: 0.4.20(eslint@9.29.0)
+ globals:
+ specifier: ^16.0.0
+ version: 16.2.0
+ prettier:
+ specifier: ^3.6.2
+ version: 3.6.2
+ vite:
+ specifier: ^6.3.5
+ version: 6.3.5
+
+packages:
+ "@ampproject/remapping@2.3.0":
+ resolution:
+ {
+ integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==,
+ }
+ engines: { node: ">=6.0.0" }
+
+ "@babel/code-frame@7.27.1":
+ resolution:
+ {
+ integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ "@babel/compat-data@7.27.5":
+ resolution:
+ {
+ integrity: sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ "@babel/core@7.27.4":
+ resolution:
+ {
+ integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ "@babel/generator@7.27.5":
+ resolution:
+ {
+ integrity: sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ "@babel/helper-compilation-targets@7.27.2":
+ resolution:
+ {
+ integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ "@babel/helper-module-imports@7.27.1":
+ resolution:
+ {
+ integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ "@babel/helper-module-transforms@7.27.3":
+ resolution:
+ {
+ integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==,
+ }
+ engines: { node: ">=6.9.0" }
+ peerDependencies:
+ "@babel/core": ^7.0.0
+
+ "@babel/helper-plugin-utils@7.27.1":
+ resolution:
+ {
+ integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ "@babel/helper-string-parser@7.27.1":
+ resolution:
+ {
+ integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ "@babel/helper-validator-identifier@7.27.1":
+ resolution:
+ {
+ integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ "@babel/helper-validator-option@7.27.1":
+ resolution:
+ {
+ integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ "@babel/helpers@7.27.6":
+ resolution:
+ {
+ integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ "@babel/parser@7.27.5":
+ resolution:
+ {
+ integrity: sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==,
+ }
+ engines: { node: ">=6.0.0" }
+ hasBin: true
+
+ "@babel/plugin-transform-react-jsx-self@7.27.1":
+ resolution:
+ {
+ integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==,
+ }
+ engines: { node: ">=6.9.0" }
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+
+ "@babel/plugin-transform-react-jsx-source@7.27.1":
+ resolution:
+ {
+ integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==,
+ }
+ engines: { node: ">=6.9.0" }
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+
+ "@babel/template@7.27.2":
+ resolution:
+ {
+ integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ "@babel/traverse@7.27.4":
+ resolution:
+ {
+ integrity: sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ "@babel/types@7.27.6":
+ resolution:
+ {
+ integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ "@esbuild/aix-ppc64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==,
+ }
+ engines: { node: ">=18" }
+ cpu: [ppc64]
+ os: [aix]
+
+ "@esbuild/android-arm64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==,
+ }
+ engines: { node: ">=18" }
+ cpu: [arm64]
+ os: [android]
+
+ "@esbuild/android-arm@0.25.5":
+ resolution:
+ {
+ integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==,
+ }
+ engines: { node: ">=18" }
+ cpu: [arm]
+ os: [android]
+
+ "@esbuild/android-x64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==,
+ }
+ engines: { node: ">=18" }
+ cpu: [x64]
+ os: [android]
+
+ "@esbuild/darwin-arm64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==,
+ }
+ engines: { node: ">=18" }
+ cpu: [arm64]
+ os: [darwin]
+
+ "@esbuild/darwin-x64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==,
+ }
+ engines: { node: ">=18" }
+ cpu: [x64]
+ os: [darwin]
+
+ "@esbuild/freebsd-arm64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==,
+ }
+ engines: { node: ">=18" }
+ cpu: [arm64]
+ os: [freebsd]
+
+ "@esbuild/freebsd-x64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==,
+ }
+ engines: { node: ">=18" }
+ cpu: [x64]
+ os: [freebsd]
+
+ "@esbuild/linux-arm64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==,
+ }
+ engines: { node: ">=18" }
+ cpu: [arm64]
+ os: [linux]
+
+ "@esbuild/linux-arm@0.25.5":
+ resolution:
+ {
+ integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==,
+ }
+ engines: { node: ">=18" }
+ cpu: [arm]
+ os: [linux]
+
+ "@esbuild/linux-ia32@0.25.5":
+ resolution:
+ {
+ integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==,
+ }
+ engines: { node: ">=18" }
+ cpu: [ia32]
+ os: [linux]
+
+ "@esbuild/linux-loong64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==,
+ }
+ engines: { node: ">=18" }
+ cpu: [loong64]
+ os: [linux]
+
+ "@esbuild/linux-mips64el@0.25.5":
+ resolution:
+ {
+ integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==,
+ }
+ engines: { node: ">=18" }
+ cpu: [mips64el]
+ os: [linux]
+
+ "@esbuild/linux-ppc64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==,
+ }
+ engines: { node: ">=18" }
+ cpu: [ppc64]
+ os: [linux]
+
+ "@esbuild/linux-riscv64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==,
+ }
+ engines: { node: ">=18" }
+ cpu: [riscv64]
+ os: [linux]
+
+ "@esbuild/linux-s390x@0.25.5":
+ resolution:
+ {
+ integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==,
+ }
+ engines: { node: ">=18" }
+ cpu: [s390x]
+ os: [linux]
+
+ "@esbuild/linux-x64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==,
+ }
+ engines: { node: ">=18" }
+ cpu: [x64]
+ os: [linux]
+
+ "@esbuild/netbsd-arm64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==,
+ }
+ engines: { node: ">=18" }
+ cpu: [arm64]
+ os: [netbsd]
+
+ "@esbuild/netbsd-x64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==,
+ }
+ engines: { node: ">=18" }
+ cpu: [x64]
+ os: [netbsd]
+
+ "@esbuild/openbsd-arm64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==,
+ }
+ engines: { node: ">=18" }
+ cpu: [arm64]
+ os: [openbsd]
+
+ "@esbuild/openbsd-x64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==,
+ }
+ engines: { node: ">=18" }
+ cpu: [x64]
+ os: [openbsd]
+
+ "@esbuild/sunos-x64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==,
+ }
+ engines: { node: ">=18" }
+ cpu: [x64]
+ os: [sunos]
+
+ "@esbuild/win32-arm64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==,
+ }
+ engines: { node: ">=18" }
+ cpu: [arm64]
+ os: [win32]
+
+ "@esbuild/win32-ia32@0.25.5":
+ resolution:
+ {
+ integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==,
+ }
+ engines: { node: ">=18" }
+ cpu: [ia32]
+ os: [win32]
+
+ "@esbuild/win32-x64@0.25.5":
+ resolution:
+ {
+ integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==,
+ }
+ engines: { node: ">=18" }
+ cpu: [x64]
+ os: [win32]
+
+ "@eslint-community/eslint-utils@4.7.0":
+ resolution:
+ {
+ integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==,
+ }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
+ "@eslint-community/regexpp@4.12.1":
+ resolution:
+ {
+ integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==,
+ }
+ engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 }
+
+ "@eslint/config-array@0.20.1":
+ resolution:
+ {
+ integrity: sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==,
+ }
+ engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
+
+ "@eslint/config-helpers@0.2.3":
+ resolution:
+ {
+ integrity: sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==,
+ }
+ engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
+
+ "@eslint/core@0.14.0":
+ resolution:
+ {
+ integrity: sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==,
+ }
+ engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
+
+ "@eslint/core@0.15.0":
+ resolution:
+ {
+ integrity: sha512-b7ePw78tEWWkpgZCDYkbqDOP8dmM6qe+AOC6iuJqlq1R/0ahMAeH3qynpnqKFGkMltrp44ohV4ubGyvLX28tzw==,
+ }
+ engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
+
+ "@eslint/eslintrc@3.3.1":
+ resolution:
+ {
+ integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==,
+ }
+ engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
+
+ "@eslint/js@9.29.0":
+ resolution:
+ {
+ integrity: sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==,
+ }
+ engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
+
+ "@eslint/object-schema@2.1.6":
+ resolution:
+ {
+ integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==,
+ }
+ engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
+
+ "@eslint/plugin-kit@0.3.2":
+ resolution:
+ {
+ integrity: sha512-4SaFZCNfJqvk/kenHpI8xvN42DMaoycy4PzKc5otHxRswww1kAt82OlBuwRVLofCACCTZEcla2Ydxv8scMXaTg==,
+ }
+ engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
+
+ "@humanfs/core@0.19.1":
+ resolution:
+ {
+ integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==,
+ }
+ engines: { node: ">=18.18.0" }
+
+ "@humanfs/node@0.16.6":
+ resolution:
+ {
+ integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==,
+ }
+ engines: { node: ">=18.18.0" }
+
+ "@humanwhocodes/module-importer@1.0.1":
+ resolution:
+ {
+ integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==,
+ }
+ engines: { node: ">=12.22" }
+
+ "@humanwhocodes/retry@0.3.1":
+ resolution:
+ {
+ integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==,
+ }
+ engines: { node: ">=18.18" }
+
+ "@humanwhocodes/retry@0.4.3":
+ resolution:
+ {
+ integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==,
+ }
+ engines: { node: ">=18.18" }
+
+ "@jridgewell/gen-mapping@0.3.8":
+ resolution:
+ {
+ integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==,
+ }
+ engines: { node: ">=6.0.0" }
+
+ "@jridgewell/resolve-uri@3.1.2":
+ resolution:
+ {
+ integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==,
+ }
+ engines: { node: ">=6.0.0" }
+
+ "@jridgewell/set-array@1.2.1":
+ resolution:
+ {
+ integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==,
+ }
+ engines: { node: ">=6.0.0" }
+
+ "@jridgewell/sourcemap-codec@1.5.0":
+ resolution:
+ {
+ integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==,
+ }
+
+ "@jridgewell/trace-mapping@0.3.25":
+ resolution:
+ {
+ integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==,
+ }
+
+ "@rolldown/pluginutils@1.0.0-beta.11":
+ resolution:
+ {
+ integrity: sha512-L/gAA/hyCSuzTF1ftlzUSI/IKr2POHsv1Dd78GfqkR83KMNuswWD61JxGV2L7nRwBBBSDr6R1gCkdTmoN7W4ag==,
+ }
+
+ "@rollup/rollup-android-arm-eabi@4.43.0":
+ resolution:
+ {
+ integrity: sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==,
+ }
+ cpu: [arm]
+ os: [android]
+
+ "@rollup/rollup-android-arm64@4.43.0":
+ resolution:
+ {
+ integrity: sha512-ss4YJwRt5I63454Rpj+mXCXicakdFmKnUNxr1dLK+5rv5FJgAxnN7s31a5VchRYxCFWdmnDWKd0wbAdTr0J5EA==,
+ }
+ cpu: [arm64]
+ os: [android]
+
+ "@rollup/rollup-darwin-arm64@4.43.0":
+ resolution:
+ {
+ integrity: sha512-eKoL8ykZ7zz8MjgBenEF2OoTNFAPFz1/lyJ5UmmFSz5jW+7XbH1+MAgCVHy72aG59rbuQLcJeiMrP8qP5d/N0A==,
+ }
+ cpu: [arm64]
+ os: [darwin]
+
+ "@rollup/rollup-darwin-x64@4.43.0":
+ resolution:
+ {
+ integrity: sha512-SYwXJgaBYW33Wi/q4ubN+ldWC4DzQY62S4Ll2dgfr/dbPoF50dlQwEaEHSKrQdSjC6oIe1WgzosoaNoHCdNuMg==,
+ }
+ cpu: [x64]
+ os: [darwin]
+
+ "@rollup/rollup-freebsd-arm64@4.43.0":
+ resolution:
+ {
+ integrity: sha512-SV+U5sSo0yujrjzBF7/YidieK2iF6E7MdF6EbYxNz94lA+R0wKl3SiixGyG/9Klab6uNBIqsN7j4Y/Fya7wAjQ==,
+ }
+ cpu: [arm64]
+ os: [freebsd]
+
+ "@rollup/rollup-freebsd-x64@4.43.0":
+ resolution:
+ {
+ integrity: sha512-J7uCsiV13L/VOeHJBo5SjasKiGxJ0g+nQTrBkAsmQBIdil3KhPnSE9GnRon4ejX1XDdsmK/l30IYLiAaQEO0Cg==,
+ }
+ cpu: [x64]
+ os: [freebsd]
+
+ "@rollup/rollup-linux-arm-gnueabihf@4.43.0":
+ resolution:
+ {
+ integrity: sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==,
+ }
+ cpu: [arm]
+ os: [linux]
+
+ "@rollup/rollup-linux-arm-musleabihf@4.43.0":
+ resolution:
+ {
+ integrity: sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==,
+ }
+ cpu: [arm]
+ os: [linux]
+
+ "@rollup/rollup-linux-arm64-gnu@4.43.0":
+ resolution:
+ {
+ integrity: sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==,
+ }
+ cpu: [arm64]
+ os: [linux]
+
+ "@rollup/rollup-linux-arm64-musl@4.43.0":
+ resolution:
+ {
+ integrity: sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==,
+ }
+ cpu: [arm64]
+ os: [linux]
+
+ "@rollup/rollup-linux-loongarch64-gnu@4.43.0":
+ resolution:
+ {
+ integrity: sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==,
+ }
+ cpu: [loong64]
+ os: [linux]
+
+ "@rollup/rollup-linux-powerpc64le-gnu@4.43.0":
+ resolution:
+ {
+ integrity: sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==,
+ }
+ cpu: [ppc64]
+ os: [linux]
+
+ "@rollup/rollup-linux-riscv64-gnu@4.43.0":
+ resolution:
+ {
+ integrity: sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==,
+ }
+ cpu: [riscv64]
+ os: [linux]
+
+ "@rollup/rollup-linux-riscv64-musl@4.43.0":
+ resolution:
+ {
+ integrity: sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==,
+ }
+ cpu: [riscv64]
+ os: [linux]
+
+ "@rollup/rollup-linux-s390x-gnu@4.43.0":
+ resolution:
+ {
+ integrity: sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==,
+ }
+ cpu: [s390x]
+ os: [linux]
+
+ "@rollup/rollup-linux-x64-gnu@4.43.0":
+ resolution:
+ {
+ integrity: sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==,
+ }
+ cpu: [x64]
+ os: [linux]
+
+ "@rollup/rollup-linux-x64-musl@4.43.0":
+ resolution:
+ {
+ integrity: sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==,
+ }
+ cpu: [x64]
+ os: [linux]
+
+ "@rollup/rollup-win32-arm64-msvc@4.43.0":
+ resolution:
+ {
+ integrity: sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==,
+ }
+ cpu: [arm64]
+ os: [win32]
+
+ "@rollup/rollup-win32-ia32-msvc@4.43.0":
+ resolution:
+ {
+ integrity: sha512-fYCTEyzf8d+7diCw8b+asvWDCLMjsCEA8alvtAutqJOJp/wL5hs1rWSqJ1vkjgW0L2NB4bsYJrpKkiIPRR9dvw==,
+ }
+ cpu: [ia32]
+ os: [win32]
+
+ "@rollup/rollup-win32-x64-msvc@4.43.0":
+ resolution:
+ {
+ integrity: sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==,
+ }
+ cpu: [x64]
+ os: [win32]
+
+ "@types/babel__core@7.20.5":
+ resolution:
+ {
+ integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==,
+ }
+
+ "@types/babel__generator@7.27.0":
+ resolution:
+ {
+ integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==,
+ }
+
+ "@types/babel__template@7.4.4":
+ resolution:
+ {
+ integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==,
+ }
+
+ "@types/babel__traverse@7.20.7":
+ resolution:
+ {
+ integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==,
+ }
+
+ "@types/estree@1.0.7":
+ resolution:
+ {
+ integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==,
+ }
+
+ "@types/estree@1.0.8":
+ resolution:
+ {
+ integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==,
+ }
+
+ "@types/json-schema@7.0.15":
+ resolution:
+ {
+ integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==,
+ }
+
+ "@types/react-dom@19.1.6":
+ resolution:
+ {
+ integrity: sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==,
+ }
+ peerDependencies:
+ "@types/react": ^19.0.0
+
+ "@types/react@19.1.8":
+ resolution:
+ {
+ integrity: sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==,
+ }
+
+ "@vitejs/plugin-react@4.5.2":
+ resolution:
+ {
+ integrity: sha512-QNVT3/Lxx99nMQWJWF7K4N6apUEuT0KlZA3mx/mVaoGj3smm/8rc8ezz15J1pcbcjDK0V15rpHetVfya08r76Q==,
+ }
+ engines: { node: ^14.18.0 || >=16.0.0 }
+ peerDependencies:
+ vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0
+
+ acorn-jsx@5.3.2:
+ resolution:
+ {
+ integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==,
+ }
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+ acorn@8.15.0:
+ resolution:
+ {
+ integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==,
+ }
+ engines: { node: ">=0.4.0" }
+ hasBin: true
+
+ ajv@6.12.6:
+ resolution:
+ {
+ integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==,
+ }
+
+ ansi-styles@4.3.0:
+ resolution:
+ {
+ integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==,
+ }
+ engines: { node: ">=8" }
+
+ argparse@2.0.1:
+ resolution:
+ {
+ integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==,
+ }
+
+ balanced-match@1.0.2:
+ resolution:
+ {
+ integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==,
+ }
+
+ brace-expansion@1.1.12:
+ resolution:
+ {
+ integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==,
+ }
+
+ browserslist@4.25.0:
+ resolution:
+ {
+ integrity: sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==,
+ }
+ engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 }
+ hasBin: true
+
+ callsites@3.1.0:
+ resolution:
+ {
+ integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==,
+ }
+ engines: { node: ">=6" }
+
+ caniuse-lite@1.0.30001723:
+ resolution:
+ {
+ integrity: sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==,
+ }
+
+ chalk@4.1.2:
+ resolution:
+ {
+ integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==,
+ }
+ engines: { node: ">=10" }
+
+ color-convert@2.0.1:
+ resolution:
+ {
+ integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==,
+ }
+ engines: { node: ">=7.0.0" }
+
+ color-name@1.1.4:
+ resolution:
+ {
+ integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==,
+ }
+
+ concat-map@0.0.1:
+ resolution:
+ {
+ integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==,
+ }
+
+ convert-source-map@2.0.0:
+ resolution:
+ {
+ integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==,
+ }
+
+ cookie@1.0.2:
+ resolution:
+ {
+ integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==,
+ }
+ engines: { node: ">=18" }
+
+ cross-spawn@7.0.6:
+ resolution:
+ {
+ integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==,
+ }
+ engines: { node: ">= 8" }
+
+ csstype@3.1.3:
+ resolution:
+ {
+ integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==,
+ }
+
+ debug@4.4.1:
+ resolution:
+ {
+ integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==,
+ }
+ engines: { node: ">=6.0" }
+ peerDependencies:
+ supports-color: "*"
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ deep-is@0.1.4:
+ resolution:
+ {
+ integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==,
+ }
+
+ electron-to-chromium@1.5.167:
+ resolution:
+ {
+ integrity: sha512-LxcRvnYO5ez2bMOFpbuuVuAI5QNeY1ncVytE/KXaL6ZNfzX1yPlAO0nSOyIHx2fVAuUprMqPs/TdVhUFZy7SIQ==,
+ }
+
+ esbuild@0.25.5:
+ resolution:
+ {
+ integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==,
+ }
+ engines: { node: ">=18" }
+ hasBin: true
+
+ escalade@3.2.0:
+ resolution:
+ {
+ integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==,
+ }
+ engines: { node: ">=6" }
+
+ escape-string-regexp@4.0.0:
+ resolution:
+ {
+ integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==,
+ }
+ engines: { node: ">=10" }
+
+ eslint-plugin-react-hooks@5.2.0:
+ resolution:
+ {
+ integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==,
+ }
+ engines: { node: ">=10" }
+ peerDependencies:
+ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
+
+ eslint-plugin-react-refresh@0.4.20:
+ resolution:
+ {
+ integrity: sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==,
+ }
+ peerDependencies:
+ eslint: ">=8.40"
+
+ eslint-scope@8.4.0:
+ resolution:
+ {
+ integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==,
+ }
+ engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
+
+ eslint-visitor-keys@3.4.3:
+ resolution:
+ {
+ integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==,
+ }
+ engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
+
+ eslint-visitor-keys@4.2.1:
+ resolution:
+ {
+ integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==,
+ }
+ engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
+
+ eslint@9.29.0:
+ resolution:
+ {
+ integrity: sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==,
+ }
+ engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
+ hasBin: true
+ peerDependencies:
+ jiti: "*"
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+
+ espree@10.4.0:
+ resolution:
+ {
+ integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==,
+ }
+ engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
+
+ esquery@1.6.0:
+ resolution:
+ {
+ integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==,
+ }
+ engines: { node: ">=0.10" }
+
+ esrecurse@4.3.0:
+ resolution:
+ {
+ integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==,
+ }
+ engines: { node: ">=4.0" }
+
+ estraverse@5.3.0:
+ resolution:
+ {
+ integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==,
+ }
+ engines: { node: ">=4.0" }
+
+ esutils@2.0.3:
+ resolution:
+ {
+ integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==,
+ }
+ engines: { node: ">=0.10.0" }
+
+ fast-deep-equal@3.1.3:
+ resolution:
+ {
+ integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==,
+ }
+
+ fast-json-stable-stringify@2.1.0:
+ resolution:
+ {
+ integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==,
+ }
+
+ fast-levenshtein@2.0.6:
+ resolution:
+ {
+ integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==,
+ }
+
+ fdir@6.4.6:
+ resolution:
+ {
+ integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==,
+ }
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ file-entry-cache@8.0.0:
+ resolution:
+ {
+ integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==,
+ }
+ engines: { node: ">=16.0.0" }
+
+ find-up@5.0.0:
+ resolution:
+ {
+ integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==,
+ }
+ engines: { node: ">=10" }
+
+ flat-cache@4.0.1:
+ resolution:
+ {
+ integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==,
+ }
+ engines: { node: ">=16" }
+
+ flatted@3.3.3:
+ resolution:
+ {
+ integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==,
+ }
+
+ fsevents@2.3.3:
+ resolution:
+ {
+ integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==,
+ }
+ engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 }
+ os: [darwin]
+
+ gensync@1.0.0-beta.2:
+ resolution:
+ {
+ integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==,
+ }
+ engines: { node: ">=6.9.0" }
+
+ glob-parent@6.0.2:
+ resolution:
+ {
+ integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==,
+ }
+ engines: { node: ">=10.13.0" }
+
+ globals@11.12.0:
+ resolution:
+ {
+ integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==,
+ }
+ engines: { node: ">=4" }
+
+ globals@14.0.0:
+ resolution:
+ {
+ integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==,
+ }
+ engines: { node: ">=18" }
+
+ globals@16.2.0:
+ resolution:
+ {
+ integrity: sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==,
+ }
+ engines: { node: ">=18" }
+
+ has-flag@4.0.0:
+ resolution:
+ {
+ integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==,
+ }
+ engines: { node: ">=8" }
+
+ ignore@5.3.2:
+ resolution:
+ {
+ integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==,
+ }
+ engines: { node: ">= 4" }
+
+ import-fresh@3.3.1:
+ resolution:
+ {
+ integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==,
+ }
+ engines: { node: ">=6" }
+
+ imurmurhash@0.1.4:
+ resolution:
+ {
+ integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==,
+ }
+ engines: { node: ">=0.8.19" }
+
+ is-extglob@2.1.1:
+ resolution:
+ {
+ integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==,
+ }
+ engines: { node: ">=0.10.0" }
+
+ is-glob@4.0.3:
+ resolution:
+ {
+ integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==,
+ }
+ engines: { node: ">=0.10.0" }
+
+ isexe@2.0.0:
+ resolution:
+ {
+ integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==,
+ }
+
+ js-tokens@4.0.0:
+ resolution:
+ {
+ integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==,
+ }
+
+ js-yaml@4.1.0:
+ resolution:
+ {
+ integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==,
+ }
+ hasBin: true
+
+ jsesc@3.1.0:
+ resolution:
+ {
+ integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==,
+ }
+ engines: { node: ">=6" }
+ hasBin: true
+
+ json-buffer@3.0.1:
+ resolution:
+ {
+ integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==,
+ }
+
+ json-schema-traverse@0.4.1:
+ resolution:
+ {
+ integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==,
+ }
+
+ json-stable-stringify-without-jsonify@1.0.1:
+ resolution:
+ {
+ integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==,
+ }
+
+ json5@2.2.3:
+ resolution:
+ {
+ integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==,
+ }
+ engines: { node: ">=6" }
+ hasBin: true
+
+ keyv@4.5.4:
+ resolution:
+ {
+ integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==,
+ }
+
+ levn@0.4.1:
+ resolution:
+ {
+ integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==,
+ }
+ engines: { node: ">= 0.8.0" }
+
+ locate-path@6.0.0:
+ resolution:
+ {
+ integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==,
+ }
+ engines: { node: ">=10" }
+
+ lodash.merge@4.6.2:
+ resolution:
+ {
+ integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==,
+ }
+
+ lru-cache@5.1.1:
+ resolution:
+ {
+ integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==,
+ }
+
+ minimatch@3.1.2:
+ resolution:
+ {
+ integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==,
+ }
+
+ ms@2.1.3:
+ resolution:
+ {
+ integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==,
+ }
+
+ nanoid@3.3.11:
+ resolution:
+ {
+ integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==,
+ }
+ engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 }
+ hasBin: true
+
+ natural-compare@1.4.0:
+ resolution:
+ {
+ integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==,
+ }
+
+ node-releases@2.0.19:
+ resolution:
+ {
+ integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==,
+ }
+
+ optionator@0.9.4:
+ resolution:
+ {
+ integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==,
+ }
+ engines: { node: ">= 0.8.0" }
+
+ p-limit@3.1.0:
+ resolution:
+ {
+ integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==,
+ }
+ engines: { node: ">=10" }
+
+ p-locate@5.0.0:
+ resolution:
+ {
+ integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==,
+ }
+ engines: { node: ">=10" }
+
+ parent-module@1.0.1:
+ resolution:
+ {
+ integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==,
+ }
+ engines: { node: ">=6" }
+
+ path-exists@4.0.0:
+ resolution:
+ {
+ integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==,
+ }
+ engines: { node: ">=8" }
+
+ path-key@3.1.1:
+ resolution:
+ {
+ integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==,
+ }
+ engines: { node: ">=8" }
+
+ picocolors@1.1.1:
+ resolution:
+ {
+ integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==,
+ }
+
+ picomatch@4.0.2:
+ resolution:
+ {
+ integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==,
+ }
+ engines: { node: ">=12" }
+
+ postcss@8.5.5:
+ resolution:
+ {
+ integrity: sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==,
+ }
+ engines: { node: ^10 || ^12 || >=14 }
+
+ prelude-ls@1.2.1:
+ resolution:
+ {
+ integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==,
+ }
+ engines: { node: ">= 0.8.0" }
+
+ prettier@3.6.2:
+ resolution:
+ {
+ integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==,
+ }
+ engines: { node: ">=14" }
+ hasBin: true
+
+ punycode@2.3.1:
+ resolution:
+ {
+ integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==,
+ }
+ engines: { node: ">=6" }
+
+ react-dom@19.1.0:
+ resolution:
+ {
+ integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==,
+ }
+ peerDependencies:
+ react: ^19.1.0
+
+ react-refresh@0.17.0:
+ resolution:
+ {
+ integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==,
+ }
+ engines: { node: ">=0.10.0" }
+
+ react-router-dom@7.6.2:
+ resolution:
+ {
+ integrity: sha512-Q8zb6VlTbdYKK5JJBLQEN06oTUa/RAbG/oQS1auK1I0TbJOXktqm+QENEVJU6QvWynlXPRBXI3fiOQcSEA78rA==,
+ }
+ engines: { node: ">=20.0.0" }
+ peerDependencies:
+ react: ">=18"
+ react-dom: ">=18"
+
+ react-router@7.6.2:
+ resolution:
+ {
+ integrity: sha512-U7Nv3y+bMimgWjhlT5CRdzHPu2/KVmqPwKUCChW8en5P3znxUqwlYFlbmyj8Rgp1SF6zs5X4+77kBVknkg6a0w==,
+ }
+ engines: { node: ">=20.0.0" }
+ peerDependencies:
+ react: ">=18"
+ react-dom: ">=18"
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+
+ react-spinners@0.17.0:
+ resolution:
+ {
+ integrity: sha512-L/8HTylaBmIWwQzIjMq+0vyaRXuoAevzWoD35wKpNTxxtYXWZp+xtgkfD7Y4WItuX0YvdxMPU79+7VhhmbmuTQ==,
+ }
+ peerDependencies:
+ react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
+ react@19.1.0:
+ resolution:
+ {
+ integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==,
+ }
+ engines: { node: ">=0.10.0" }
+
+ resolve-from@4.0.0:
+ resolution:
+ {
+ integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==,
+ }
+ engines: { node: ">=4" }
+
+ rollup@4.43.0:
+ resolution:
+ {
+ integrity: sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==,
+ }
+ engines: { node: ">=18.0.0", npm: ">=8.0.0" }
+ hasBin: true
+
+ scheduler@0.26.0:
+ resolution:
+ {
+ integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==,
+ }
+
+ semver@6.3.1:
+ resolution:
+ {
+ integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==,
+ }
+ hasBin: true
+
+ set-cookie-parser@2.7.1:
+ resolution:
+ {
+ integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==,
+ }
+
+ shebang-command@2.0.0:
+ resolution:
+ {
+ integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==,
+ }
+ engines: { node: ">=8" }
+
+ shebang-regex@3.0.0:
+ resolution:
+ {
+ integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==,
+ }
+ engines: { node: ">=8" }
+
+ source-map-js@1.2.1:
+ resolution:
+ {
+ integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==,
+ }
+ engines: { node: ">=0.10.0" }
+
+ strip-json-comments@3.1.1:
+ resolution:
+ {
+ integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==,
+ }
+ engines: { node: ">=8" }
+
+ supports-color@7.2.0:
+ resolution:
+ {
+ integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==,
+ }
+ engines: { node: ">=8" }
+
+ tinyglobby@0.2.14:
+ resolution:
+ {
+ integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==,
+ }
+ engines: { node: ">=12.0.0" }
+
+ type-check@0.4.0:
+ resolution:
+ {
+ integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==,
+ }
+ engines: { node: ">= 0.8.0" }
+
+ update-browserslist-db@1.1.3:
+ resolution:
+ {
+ integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==,
+ }
+ hasBin: true
+ peerDependencies:
+ browserslist: ">= 4.21.0"
+
+ uri-js@4.4.1:
+ resolution:
+ {
+ integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==,
+ }
+
+ vite@6.3.5:
+ resolution:
+ {
+ integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==,
+ }
+ engines: { node: ^18.0.0 || ^20.0.0 || >=22.0.0 }
+ hasBin: true
+ peerDependencies:
+ "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0
+ jiti: ">=1.21.0"
+ less: "*"
+ lightningcss: ^1.21.0
+ sass: "*"
+ sass-embedded: "*"
+ stylus: "*"
+ sugarss: "*"
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ "@types/node":
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
+ which@2.0.2:
+ resolution:
+ {
+ integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==,
+ }
+ engines: { node: ">= 8" }
+ hasBin: true
+
+ word-wrap@1.2.5:
+ resolution:
+ {
+ integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==,
+ }
+ engines: { node: ">=0.10.0" }
+
+ yallist@3.1.1:
+ resolution:
+ {
+ integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==,
+ }
+
+ yocto-queue@0.1.0:
+ resolution:
+ {
+ integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==,
+ }
+ engines: { node: ">=10" }
+
+snapshots:
+ "@ampproject/remapping@2.3.0":
+ dependencies:
+ "@jridgewell/gen-mapping": 0.3.8
+ "@jridgewell/trace-mapping": 0.3.25
+
+ "@babel/code-frame@7.27.1":
+ dependencies:
+ "@babel/helper-validator-identifier": 7.27.1
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ "@babel/compat-data@7.27.5": {}
+
+ "@babel/core@7.27.4":
+ dependencies:
+ "@ampproject/remapping": 2.3.0
+ "@babel/code-frame": 7.27.1
+ "@babel/generator": 7.27.5
+ "@babel/helper-compilation-targets": 7.27.2
+ "@babel/helper-module-transforms": 7.27.3(@babel/core@7.27.4)
+ "@babel/helpers": 7.27.6
+ "@babel/parser": 7.27.5
+ "@babel/template": 7.27.2
+ "@babel/traverse": 7.27.4
+ "@babel/types": 7.27.6
+ convert-source-map: 2.0.0
+ debug: 4.4.1
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ "@babel/generator@7.27.5":
+ dependencies:
+ "@babel/parser": 7.27.5
+ "@babel/types": 7.27.6
+ "@jridgewell/gen-mapping": 0.3.8
+ "@jridgewell/trace-mapping": 0.3.25
+ jsesc: 3.1.0
+
+ "@babel/helper-compilation-targets@7.27.2":
+ dependencies:
+ "@babel/compat-data": 7.27.5
+ "@babel/helper-validator-option": 7.27.1
+ browserslist: 4.25.0
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ "@babel/helper-module-imports@7.27.1":
+ dependencies:
+ "@babel/traverse": 7.27.4
+ "@babel/types": 7.27.6
+ transitivePeerDependencies:
+ - supports-color
+
+ "@babel/helper-module-transforms@7.27.3(@babel/core@7.27.4)":
+ dependencies:
+ "@babel/core": 7.27.4
+ "@babel/helper-module-imports": 7.27.1
+ "@babel/helper-validator-identifier": 7.27.1
+ "@babel/traverse": 7.27.4
+ transitivePeerDependencies:
+ - supports-color
+
+ "@babel/helper-plugin-utils@7.27.1": {}
+
+ "@babel/helper-string-parser@7.27.1": {}
+
+ "@babel/helper-validator-identifier@7.27.1": {}
+
+ "@babel/helper-validator-option@7.27.1": {}
+
+ "@babel/helpers@7.27.6":
+ dependencies:
+ "@babel/template": 7.27.2
+ "@babel/types": 7.27.6
+
+ "@babel/parser@7.27.5":
+ dependencies:
+ "@babel/types": 7.27.6
+
+ "@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.27.4)":
+ dependencies:
+ "@babel/core": 7.27.4
+ "@babel/helper-plugin-utils": 7.27.1
+
+ "@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.27.4)":
+ dependencies:
+ "@babel/core": 7.27.4
+ "@babel/helper-plugin-utils": 7.27.1
+
+ "@babel/template@7.27.2":
+ dependencies:
+ "@babel/code-frame": 7.27.1
+ "@babel/parser": 7.27.5
+ "@babel/types": 7.27.6
+
+ "@babel/traverse@7.27.4":
+ dependencies:
+ "@babel/code-frame": 7.27.1
+ "@babel/generator": 7.27.5
+ "@babel/parser": 7.27.5
+ "@babel/template": 7.27.2
+ "@babel/types": 7.27.6
+ debug: 4.4.1
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+
+ "@babel/types@7.27.6":
+ dependencies:
+ "@babel/helper-string-parser": 7.27.1
+ "@babel/helper-validator-identifier": 7.27.1
+
+ "@esbuild/aix-ppc64@0.25.5":
+ optional: true
+
+ "@esbuild/android-arm64@0.25.5":
+ optional: true
+
+ "@esbuild/android-arm@0.25.5":
+ optional: true
+
+ "@esbuild/android-x64@0.25.5":
+ optional: true
+
+ "@esbuild/darwin-arm64@0.25.5":
+ optional: true
+
+ "@esbuild/darwin-x64@0.25.5":
+ optional: true
+
+ "@esbuild/freebsd-arm64@0.25.5":
+ optional: true
+
+ "@esbuild/freebsd-x64@0.25.5":
+ optional: true
+
+ "@esbuild/linux-arm64@0.25.5":
+ optional: true
+
+ "@esbuild/linux-arm@0.25.5":
+ optional: true
+
+ "@esbuild/linux-ia32@0.25.5":
+ optional: true
+
+ "@esbuild/linux-loong64@0.25.5":
+ optional: true
+
+ "@esbuild/linux-mips64el@0.25.5":
+ optional: true
+
+ "@esbuild/linux-ppc64@0.25.5":
+ optional: true
+
+ "@esbuild/linux-riscv64@0.25.5":
+ optional: true
+
+ "@esbuild/linux-s390x@0.25.5":
+ optional: true
+
+ "@esbuild/linux-x64@0.25.5":
+ optional: true
+
+ "@esbuild/netbsd-arm64@0.25.5":
+ optional: true
+
+ "@esbuild/netbsd-x64@0.25.5":
+ optional: true
+
+ "@esbuild/openbsd-arm64@0.25.5":
+ optional: true
+
+ "@esbuild/openbsd-x64@0.25.5":
+ optional: true
+
+ "@esbuild/sunos-x64@0.25.5":
+ optional: true
+
+ "@esbuild/win32-arm64@0.25.5":
+ optional: true
+
+ "@esbuild/win32-ia32@0.25.5":
+ optional: true
+
+ "@esbuild/win32-x64@0.25.5":
+ optional: true
+
+ "@eslint-community/eslint-utils@4.7.0(eslint@9.29.0)":
+ dependencies:
+ eslint: 9.29.0
+ eslint-visitor-keys: 3.4.3
+
+ "@eslint-community/regexpp@4.12.1": {}
+
+ "@eslint/config-array@0.20.1":
+ dependencies:
+ "@eslint/object-schema": 2.1.6
+ debug: 4.4.1
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ "@eslint/config-helpers@0.2.3": {}
+
+ "@eslint/core@0.14.0":
+ dependencies:
+ "@types/json-schema": 7.0.15
+
+ "@eslint/core@0.15.0":
+ dependencies:
+ "@types/json-schema": 7.0.15
+
+ "@eslint/eslintrc@3.3.1":
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.4.1
+ espree: 10.4.0
+ globals: 14.0.0
+ ignore: 5.3.2
+ import-fresh: 3.3.1
+ js-yaml: 4.1.0
+ minimatch: 3.1.2
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+
+ "@eslint/js@9.29.0": {}
+
+ "@eslint/object-schema@2.1.6": {}
+
+ "@eslint/plugin-kit@0.3.2":
+ dependencies:
+ "@eslint/core": 0.15.0
+ levn: 0.4.1
+
+ "@humanfs/core@0.19.1": {}
+
+ "@humanfs/node@0.16.6":
+ dependencies:
+ "@humanfs/core": 0.19.1
+ "@humanwhocodes/retry": 0.3.1
+
+ "@humanwhocodes/module-importer@1.0.1": {}
+
+ "@humanwhocodes/retry@0.3.1": {}
+
+ "@humanwhocodes/retry@0.4.3": {}
+
+ "@jridgewell/gen-mapping@0.3.8":
+ dependencies:
+ "@jridgewell/set-array": 1.2.1
+ "@jridgewell/sourcemap-codec": 1.5.0
+ "@jridgewell/trace-mapping": 0.3.25
+
+ "@jridgewell/resolve-uri@3.1.2": {}
+
+ "@jridgewell/set-array@1.2.1": {}
+
+ "@jridgewell/sourcemap-codec@1.5.0": {}
+
+ "@jridgewell/trace-mapping@0.3.25":
+ dependencies:
+ "@jridgewell/resolve-uri": 3.1.2
+ "@jridgewell/sourcemap-codec": 1.5.0
+
+ "@rolldown/pluginutils@1.0.0-beta.11": {}
+
+ "@rollup/rollup-android-arm-eabi@4.43.0":
+ optional: true
+
+ "@rollup/rollup-android-arm64@4.43.0":
+ optional: true
+
+ "@rollup/rollup-darwin-arm64@4.43.0":
+ optional: true
+
+ "@rollup/rollup-darwin-x64@4.43.0":
+ optional: true
+
+ "@rollup/rollup-freebsd-arm64@4.43.0":
+ optional: true
+
+ "@rollup/rollup-freebsd-x64@4.43.0":
+ optional: true
+
+ "@rollup/rollup-linux-arm-gnueabihf@4.43.0":
+ optional: true
+
+ "@rollup/rollup-linux-arm-musleabihf@4.43.0":
+ optional: true
+
+ "@rollup/rollup-linux-arm64-gnu@4.43.0":
+ optional: true
+
+ "@rollup/rollup-linux-arm64-musl@4.43.0":
+ optional: true
+
+ "@rollup/rollup-linux-loongarch64-gnu@4.43.0":
+ optional: true
+
+ "@rollup/rollup-linux-powerpc64le-gnu@4.43.0":
+ optional: true
+
+ "@rollup/rollup-linux-riscv64-gnu@4.43.0":
+ optional: true
+
+ "@rollup/rollup-linux-riscv64-musl@4.43.0":
+ optional: true
+
+ "@rollup/rollup-linux-s390x-gnu@4.43.0":
+ optional: true
+
+ "@rollup/rollup-linux-x64-gnu@4.43.0":
+ optional: true
+
+ "@rollup/rollup-linux-x64-musl@4.43.0":
+ optional: true
+
+ "@rollup/rollup-win32-arm64-msvc@4.43.0":
+ optional: true
+
+ "@rollup/rollup-win32-ia32-msvc@4.43.0":
+ optional: true
+
+ "@rollup/rollup-win32-x64-msvc@4.43.0":
+ optional: true
+
+ "@types/babel__core@7.20.5":
+ dependencies:
+ "@babel/parser": 7.27.5
+ "@babel/types": 7.27.6
+ "@types/babel__generator": 7.27.0
+ "@types/babel__template": 7.4.4
+ "@types/babel__traverse": 7.20.7
+
+ "@types/babel__generator@7.27.0":
+ dependencies:
+ "@babel/types": 7.27.6
+
+ "@types/babel__template@7.4.4":
+ dependencies:
+ "@babel/parser": 7.27.5
+ "@babel/types": 7.27.6
+
+ "@types/babel__traverse@7.20.7":
+ dependencies:
+ "@babel/types": 7.27.6
+
+ "@types/estree@1.0.7": {}
+
+ "@types/estree@1.0.8": {}
+
+ "@types/json-schema@7.0.15": {}
+
+ "@types/react-dom@19.1.6(@types/react@19.1.8)":
+ dependencies:
+ "@types/react": 19.1.8
+
+ "@types/react@19.1.8":
+ dependencies:
+ csstype: 3.1.3
+
+ "@vitejs/plugin-react@4.5.2(vite@6.3.5)":
+ dependencies:
+ "@babel/core": 7.27.4
+ "@babel/plugin-transform-react-jsx-self": 7.27.1(@babel/core@7.27.4)
+ "@babel/plugin-transform-react-jsx-source": 7.27.1(@babel/core@7.27.4)
+ "@rolldown/pluginutils": 1.0.0-beta.11
+ "@types/babel__core": 7.20.5
+ react-refresh: 0.17.0
+ vite: 6.3.5
+ transitivePeerDependencies:
+ - supports-color
+
+ acorn-jsx@5.3.2(acorn@8.15.0):
+ dependencies:
+ acorn: 8.15.0
+
+ acorn@8.15.0: {}
+
+ ajv@6.12.6:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ argparse@2.0.1: {}
+
+ balanced-match@1.0.2: {}
+
+ brace-expansion@1.1.12:
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+
+ browserslist@4.25.0:
+ dependencies:
+ caniuse-lite: 1.0.30001723
+ electron-to-chromium: 1.5.167
+ node-releases: 2.0.19
+ update-browserslist-db: 1.1.3(browserslist@4.25.0)
+
+ callsites@3.1.0: {}
+
+ caniuse-lite@1.0.30001723: {}
+
+ chalk@4.1.2:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.4: {}
+
+ concat-map@0.0.1: {}
+
+ convert-source-map@2.0.0: {}
+
+ cookie@1.0.2: {}
+
+ cross-spawn@7.0.6:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ csstype@3.1.3: {}
+
+ debug@4.4.1:
+ dependencies:
+ ms: 2.1.3
+
+ deep-is@0.1.4: {}
+
+ electron-to-chromium@1.5.167: {}
+
+ esbuild@0.25.5:
+ optionalDependencies:
+ "@esbuild/aix-ppc64": 0.25.5
+ "@esbuild/android-arm": 0.25.5
+ "@esbuild/android-arm64": 0.25.5
+ "@esbuild/android-x64": 0.25.5
+ "@esbuild/darwin-arm64": 0.25.5
+ "@esbuild/darwin-x64": 0.25.5
+ "@esbuild/freebsd-arm64": 0.25.5
+ "@esbuild/freebsd-x64": 0.25.5
+ "@esbuild/linux-arm": 0.25.5
+ "@esbuild/linux-arm64": 0.25.5
+ "@esbuild/linux-ia32": 0.25.5
+ "@esbuild/linux-loong64": 0.25.5
+ "@esbuild/linux-mips64el": 0.25.5
+ "@esbuild/linux-ppc64": 0.25.5
+ "@esbuild/linux-riscv64": 0.25.5
+ "@esbuild/linux-s390x": 0.25.5
+ "@esbuild/linux-x64": 0.25.5
+ "@esbuild/netbsd-arm64": 0.25.5
+ "@esbuild/netbsd-x64": 0.25.5
+ "@esbuild/openbsd-arm64": 0.25.5
+ "@esbuild/openbsd-x64": 0.25.5
+ "@esbuild/sunos-x64": 0.25.5
+ "@esbuild/win32-arm64": 0.25.5
+ "@esbuild/win32-ia32": 0.25.5
+ "@esbuild/win32-x64": 0.25.5
+
+ escalade@3.2.0: {}
+
+ escape-string-regexp@4.0.0: {}
+
+ eslint-plugin-react-hooks@5.2.0(eslint@9.29.0):
+ dependencies:
+ eslint: 9.29.0
+
+ eslint-plugin-react-refresh@0.4.20(eslint@9.29.0):
+ dependencies:
+ eslint: 9.29.0
+
+ eslint-scope@8.4.0:
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+
+ eslint-visitor-keys@3.4.3: {}
+
+ eslint-visitor-keys@4.2.1: {}
+
+ eslint@9.29.0:
+ dependencies:
+ "@eslint-community/eslint-utils": 4.7.0(eslint@9.29.0)
+ "@eslint-community/regexpp": 4.12.1
+ "@eslint/config-array": 0.20.1
+ "@eslint/config-helpers": 0.2.3
+ "@eslint/core": 0.14.0
+ "@eslint/eslintrc": 3.3.1
+ "@eslint/js": 9.29.0
+ "@eslint/plugin-kit": 0.3.2
+ "@humanfs/node": 0.16.6
+ "@humanwhocodes/module-importer": 1.0.1
+ "@humanwhocodes/retry": 0.4.3
+ "@types/estree": 1.0.8
+ "@types/json-schema": 7.0.15
+ ajv: 6.12.6
+ chalk: 4.1.2
+ cross-spawn: 7.0.6
+ debug: 4.4.1
+ escape-string-regexp: 4.0.0
+ eslint-scope: 8.4.0
+ eslint-visitor-keys: 4.2.1
+ espree: 10.4.0
+ esquery: 1.6.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 8.0.0
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ ignore: 5.3.2
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ json-stable-stringify-without-jsonify: 1.0.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.2
+ natural-compare: 1.4.0
+ optionator: 0.9.4
+ transitivePeerDependencies:
+ - supports-color
+
+ espree@10.4.0:
+ dependencies:
+ acorn: 8.15.0
+ acorn-jsx: 5.3.2(acorn@8.15.0)
+ eslint-visitor-keys: 4.2.1
+
+ esquery@1.6.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ esrecurse@4.3.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ estraverse@5.3.0: {}
+
+ esutils@2.0.3: {}
+
+ fast-deep-equal@3.1.3: {}
+
+ fast-json-stable-stringify@2.1.0: {}
+
+ fast-levenshtein@2.0.6: {}
+
+ fdir@6.4.6(picomatch@4.0.2):
+ optionalDependencies:
+ picomatch: 4.0.2
+
+ file-entry-cache@8.0.0:
+ dependencies:
+ flat-cache: 4.0.1
+
+ find-up@5.0.0:
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+
+ flat-cache@4.0.1:
+ dependencies:
+ flatted: 3.3.3
+ keyv: 4.5.4
+
+ flatted@3.3.3: {}
+
+ fsevents@2.3.3:
+ optional: true
+
+ gensync@1.0.0-beta.2: {}
+
+ glob-parent@6.0.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ globals@11.12.0: {}
+
+ globals@14.0.0: {}
+
+ globals@16.2.0: {}
+
+ has-flag@4.0.0: {}
+
+ ignore@5.3.2: {}
+
+ import-fresh@3.3.1:
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
+ imurmurhash@0.1.4: {}
+
+ is-extglob@2.1.1: {}
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ isexe@2.0.0: {}
+
+ js-tokens@4.0.0: {}
+
+ js-yaml@4.1.0:
+ dependencies:
+ argparse: 2.0.1
+
+ jsesc@3.1.0: {}
+
+ json-buffer@3.0.1: {}
+
+ json-schema-traverse@0.4.1: {}
+
+ json-stable-stringify-without-jsonify@1.0.1: {}
+
+ json5@2.2.3: {}
+
+ keyv@4.5.4:
+ dependencies:
+ json-buffer: 3.0.1
+
+ levn@0.4.1:
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+
+ locate-path@6.0.0:
+ dependencies:
+ p-locate: 5.0.0
+
+ lodash.merge@4.6.2: {}
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ minimatch@3.1.2:
+ dependencies:
+ brace-expansion: 1.1.12
+
+ ms@2.1.3: {}
+
+ nanoid@3.3.11: {}
+
+ natural-compare@1.4.0: {}
+
+ node-releases@2.0.19: {}
+
+ optionator@0.9.4:
+ dependencies:
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ word-wrap: 1.2.5
+
+ p-limit@3.1.0:
+ dependencies:
+ yocto-queue: 0.1.0
+
+ p-locate@5.0.0:
+ dependencies:
+ p-limit: 3.1.0
+
+ parent-module@1.0.1:
+ dependencies:
+ callsites: 3.1.0
+
+ path-exists@4.0.0: {}
+
+ path-key@3.1.1: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@4.0.2: {}
+
+ postcss@8.5.5:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ prelude-ls@1.2.1: {}
+
+ prettier@3.6.2: {}
+
+ punycode@2.3.1: {}
+
+ react-dom@19.1.0(react@19.1.0):
+ dependencies:
+ react: 19.1.0
+ scheduler: 0.26.0
+
+ react-refresh@0.17.0: {}
+
+ react-router-dom@7.6.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ dependencies:
+ react: 19.1.0
+ react-dom: 19.1.0(react@19.1.0)
+ react-router: 7.6.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+
+ react-router@7.6.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ dependencies:
+ cookie: 1.0.2
+ react: 19.1.0
+ set-cookie-parser: 2.7.1
+ optionalDependencies:
+ react-dom: 19.1.0(react@19.1.0)
+
+ react-spinners@0.17.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ dependencies:
+ react: 19.1.0
+ react-dom: 19.1.0(react@19.1.0)
+
+ react@19.1.0: {}
+
+ resolve-from@4.0.0: {}
+
+ rollup@4.43.0:
+ dependencies:
+ "@types/estree": 1.0.7
+ optionalDependencies:
+ "@rollup/rollup-android-arm-eabi": 4.43.0
+ "@rollup/rollup-android-arm64": 4.43.0
+ "@rollup/rollup-darwin-arm64": 4.43.0
+ "@rollup/rollup-darwin-x64": 4.43.0
+ "@rollup/rollup-freebsd-arm64": 4.43.0
+ "@rollup/rollup-freebsd-x64": 4.43.0
+ "@rollup/rollup-linux-arm-gnueabihf": 4.43.0
+ "@rollup/rollup-linux-arm-musleabihf": 4.43.0
+ "@rollup/rollup-linux-arm64-gnu": 4.43.0
+ "@rollup/rollup-linux-arm64-musl": 4.43.0
+ "@rollup/rollup-linux-loongarch64-gnu": 4.43.0
+ "@rollup/rollup-linux-powerpc64le-gnu": 4.43.0
+ "@rollup/rollup-linux-riscv64-gnu": 4.43.0
+ "@rollup/rollup-linux-riscv64-musl": 4.43.0
+ "@rollup/rollup-linux-s390x-gnu": 4.43.0
+ "@rollup/rollup-linux-x64-gnu": 4.43.0
+ "@rollup/rollup-linux-x64-musl": 4.43.0
+ "@rollup/rollup-win32-arm64-msvc": 4.43.0
+ "@rollup/rollup-win32-ia32-msvc": 4.43.0
+ "@rollup/rollup-win32-x64-msvc": 4.43.0
+ fsevents: 2.3.3
+
+ scheduler@0.26.0: {}
+
+ semver@6.3.1: {}
+
+ set-cookie-parser@2.7.1: {}
+
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
+ shebang-regex@3.0.0: {}
+
+ source-map-js@1.2.1: {}
+
+ strip-json-comments@3.1.1: {}
+
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ tinyglobby@0.2.14:
+ dependencies:
+ fdir: 6.4.6(picomatch@4.0.2)
+ picomatch: 4.0.2
+
+ type-check@0.4.0:
+ dependencies:
+ prelude-ls: 1.2.1
+
+ update-browserslist-db@1.1.3(browserslist@4.25.0):
+ dependencies:
+ browserslist: 4.25.0
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ uri-js@4.4.1:
+ dependencies:
+ punycode: 2.3.1
+
+ vite@6.3.5:
+ dependencies:
+ esbuild: 0.25.5
+ fdir: 6.4.6(picomatch@4.0.2)
+ picomatch: 4.0.2
+ postcss: 8.5.5
+ rollup: 4.43.0
+ tinyglobby: 0.2.14
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
+
+ word-wrap@1.2.5: {}
+
+ yallist@3.1.1: {}
+
+ yocto-queue@0.1.0: {}
diff --git a/week3/project/e-commerce/public/favicon/android-chrome-192x192.png b/week3/project/e-commerce/public/favicon/android-chrome-192x192.png
new file mode 100644
index 0000000000..c3532e8995
Binary files /dev/null and b/week3/project/e-commerce/public/favicon/android-chrome-192x192.png differ
diff --git a/week3/project/e-commerce/public/favicon/android-chrome-512x512.png b/week3/project/e-commerce/public/favicon/android-chrome-512x512.png
new file mode 100644
index 0000000000..7ba4f2477c
Binary files /dev/null and b/week3/project/e-commerce/public/favicon/android-chrome-512x512.png differ
diff --git a/week3/project/e-commerce/public/favicon/apple-touch-icon.png b/week3/project/e-commerce/public/favicon/apple-touch-icon.png
new file mode 100644
index 0000000000..96a39062fc
Binary files /dev/null and b/week3/project/e-commerce/public/favicon/apple-touch-icon.png differ
diff --git a/week3/project/e-commerce/public/favicon/favicon-16x16.png b/week3/project/e-commerce/public/favicon/favicon-16x16.png
new file mode 100644
index 0000000000..dd5e5171a6
Binary files /dev/null and b/week3/project/e-commerce/public/favicon/favicon-16x16.png differ
diff --git a/week3/project/e-commerce/public/favicon/favicon-32x32.png b/week3/project/e-commerce/public/favicon/favicon-32x32.png
new file mode 100644
index 0000000000..3d888b1fb5
Binary files /dev/null and b/week3/project/e-commerce/public/favicon/favicon-32x32.png differ
diff --git a/week3/project/e-commerce/public/favicon/favicon.ico b/week3/project/e-commerce/public/favicon/favicon.ico
new file mode 100644
index 0000000000..7260fc58f4
Binary files /dev/null and b/week3/project/e-commerce/public/favicon/favicon.ico differ
diff --git a/week3/project/e-commerce/public/favicon/site.webmanifest b/week3/project/e-commerce/public/favicon/site.webmanifest
new file mode 100644
index 0000000000..fa99de77db
--- /dev/null
+++ b/week3/project/e-commerce/public/favicon/site.webmanifest
@@ -0,0 +1,19 @@
+{
+ "name": "",
+ "short_name": "",
+ "icons": [
+ {
+ "src": "/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "/android-chrome-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ],
+ "theme_color": "#ffffff",
+ "background_color": "#ffffff",
+ "display": "standalone"
+}
diff --git a/week3/project/assets/heart-regular.svg b/week3/project/e-commerce/src/assets/heart-regular.svg
similarity index 100%
rename from week3/project/assets/heart-regular.svg
rename to week3/project/e-commerce/src/assets/heart-regular.svg
diff --git a/week3/project/assets/heart-solid.svg b/week3/project/e-commerce/src/assets/heart-solid.svg
similarity index 100%
rename from week3/project/assets/heart-solid.svg
rename to week3/project/e-commerce/src/assets/heart-solid.svg
diff --git a/week3/project/e-commerce/src/components/Categories/Categories.jsx b/week3/project/e-commerce/src/components/Categories/Categories.jsx
new file mode 100644
index 0000000000..7c18d2794f
--- /dev/null
+++ b/week3/project/e-commerce/src/components/Categories/Categories.jsx
@@ -0,0 +1,34 @@
+import style from "./categories.module.css";
+import Error from "../Error/Error.jsx";
+import useFetch from "../../hooks/useFetch.js";
+import Loading from "../Loading.jsx";
+
+function Categories({ selectedCategory, setCategory }) {
+ const url = "https://fakestoreapi.com/products/categories";
+ const { data, loading, error } = useFetch(url);
+
+ if (error) return ;
+ if (!data || loading) return ;
+
+ return (
+
+
+ {data.map((category) => (
+ - {
+ selectedCategory === category
+ ? setCategory(null)
+ : setCategory(category);
+ }}
+ >
+ {category}
+
+ ))}
+
+
+ );
+}
+
+export default Categories;
diff --git a/week3/project/e-commerce/src/components/Categories/categories.module.css b/week3/project/e-commerce/src/components/Categories/categories.module.css
new file mode 100644
index 0000000000..831b7f78cb
--- /dev/null
+++ b/week3/project/e-commerce/src/components/Categories/categories.module.css
@@ -0,0 +1,21 @@
+.categoriesList {
+ list-style: none;
+ text-align: center;
+}
+.categoryLi {
+ display: inline-block;
+ cursor: pointer;
+ padding: 1rem;
+ margin: 0.5rem;
+ border-radius: 5px;
+ border: 1px solid var(--primary);
+}
+.categoryLi:hover {
+ background: var(--primary);
+ color: var(--background);
+}
+.active {
+ background: var(--secondary);
+ color: var(--background);
+ border: 1px solid transparent;
+}
diff --git a/week3/project/e-commerce/src/components/Error/Error.jsx b/week3/project/e-commerce/src/components/Error/Error.jsx
new file mode 100644
index 0000000000..eba35d6c10
--- /dev/null
+++ b/week3/project/e-commerce/src/components/Error/Error.jsx
@@ -0,0 +1,14 @@
+import style from "./error.module.css";
+
+function Error({ error }) {
+ return (
+
+ );
+}
+
+export default Error;
diff --git a/week3/project/e-commerce/src/components/Error/error.module.css b/week3/project/e-commerce/src/components/Error/error.module.css
new file mode 100644
index 0000000000..d20b3b7bc0
--- /dev/null
+++ b/week3/project/e-commerce/src/components/Error/error.module.css
@@ -0,0 +1,10 @@
+.errorContainer {
+ background: var(--secondary);
+ color: var(--background);
+ padding: 3rem;
+ border-radius: 5px;
+}
+.header {
+ margin-bottom: 4rem;
+ border-bottom: 1px solid var(--background);
+}
diff --git a/week3/project/e-commerce/src/components/Loading.jsx b/week3/project/e-commerce/src/components/Loading.jsx
new file mode 100644
index 0000000000..c52680eb3a
--- /dev/null
+++ b/week3/project/e-commerce/src/components/Loading.jsx
@@ -0,0 +1,12 @@
+import { ScaleLoader } from "react-spinners";
+
+function Loading() {
+ return (
+
+
Loading...
+
+
+ );
+}
+
+export default Loading;
diff --git a/week3/project/e-commerce/src/components/Navbar.jsx b/week3/project/e-commerce/src/components/Navbar.jsx
new file mode 100644
index 0000000000..c763dc613d
--- /dev/null
+++ b/week3/project/e-commerce/src/components/Navbar.jsx
@@ -0,0 +1,21 @@
+import { Link } from "react-router-dom";
+
+function Navbar() {
+ return (
+
+ );
+}
+
+export default Navbar;
diff --git a/week3/project/e-commerce/src/components/ProductCard/ProductCard.jsx b/week3/project/e-commerce/src/components/ProductCard/ProductCard.jsx
new file mode 100644
index 0000000000..a12c2724b4
--- /dev/null
+++ b/week3/project/e-commerce/src/components/ProductCard/ProductCard.jsx
@@ -0,0 +1,17 @@
+import style from "./productPage.module.css";
+
+function ProductCard({ product }) {
+ const { title, image, price, description } = product;
+
+ return (
+
+

+
+
{price} EUR
+
{description}
+
+
+ );
+}
+
+export default ProductCard;
diff --git a/week3/project/e-commerce/src/components/ProductCard/productPage.module.css b/week3/project/e-commerce/src/components/ProductCard/productPage.module.css
new file mode 100644
index 0000000000..8011d45caf
--- /dev/null
+++ b/week3/project/e-commerce/src/components/ProductCard/productPage.module.css
@@ -0,0 +1,45 @@
+.productCard {
+ display: flex;
+ justify-content: space-evenly;
+ padding: 1rem;
+ margin-top: 3rem;
+ max-width: 100vw;
+}
+.image {
+ width: 50vw;
+ max-width: 70rem;
+ max-height: 60vh;
+ height: auto;
+ object-fit: contain;
+ display: block;
+}
+.productInfo {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 1rem;
+ max-width: 70rem;
+}
+.price {
+ background: var(--primary);
+ color: var(--background);
+ padding: 1rem;
+ border-radius: 5px;
+ margin: 3rem;
+}
+
+@media (max-width: 800px) {
+ .productCard {
+ flex-direction: column;
+ }
+ h3 {
+ font-size: 2rem;
+ }
+ .productCard {
+ align-items: center;
+ }
+ .image {
+ max-width: 100%;
+ }
+}
diff --git a/week3/project/e-commerce/src/components/ProductList.jsx b/week3/project/e-commerce/src/components/ProductList.jsx
new file mode 100644
index 0000000000..460bba4fa9
--- /dev/null
+++ b/week3/project/e-commerce/src/components/ProductList.jsx
@@ -0,0 +1,13 @@
+import Product from "./Products/Product.jsx";
+
+function ProductList({ products }) {
+ return (
+
+ {products.map((product) => (
+
+ ))}
+
+ );
+}
+
+export default ProductList;
diff --git a/week3/project/e-commerce/src/components/Products/Product.jsx b/week3/project/e-commerce/src/components/Products/Product.jsx
new file mode 100644
index 0000000000..e8e85d840f
--- /dev/null
+++ b/week3/project/e-commerce/src/components/Products/Product.jsx
@@ -0,0 +1,36 @@
+import style from "./products.module.css";
+import heartRegular from "../../assets/heart-regular.svg";
+import heartSolid from "../../assets/heart-solid.svg";
+import { Link } from "react-router-dom";
+import { useContext } from "react";
+import { FavouriteContext } from "../../context/favouriteContext.jsx";
+
+function Product({ id, image, title }) {
+ const { favourite, setFavourite } = useContext(FavouriteContext);
+
+ const heart = favourite.includes(id) ? heartSolid : heartRegular;
+
+ const changeFavourite = () =>
+ setFavourite(
+ favourite.includes(id)
+ ? favourite.filter((favID) => favID !== id)
+ : [...favourite, id],
+ );
+
+ return (
+
+
+
+
+ {title}
+
+
+ );
+}
+
+export default Product;
diff --git a/week3/project/e-commerce/src/components/Products/Products.jsx b/week3/project/e-commerce/src/components/Products/Products.jsx
new file mode 100644
index 0000000000..08e53b24cb
--- /dev/null
+++ b/week3/project/e-commerce/src/components/Products/Products.jsx
@@ -0,0 +1,24 @@
+import style from "./products.module.css";
+import Product from "./Product.jsx";
+import Loading from "../Loading.jsx";
+import Error from "../Error/Error.jsx";
+import ProductList from "../ProductList.jsx";
+import useFetch from "../../hooks/useFetch.js";
+
+function Products({ selectedCategory }) {
+ const url = !selectedCategory
+ ? "https://fakestoreapi.com/products"
+ : `https://fakestoreapi.com/products/category/${selectedCategory}`;
+ const { data, loading, error } = useFetch(url);
+
+ if (error) return ;
+ if (!data || loading) return ;
+
+ return (
+
+ );
+}
+
+export default Products;
diff --git a/week3/project/e-commerce/src/components/Products/products.module.css b/week3/project/e-commerce/src/components/Products/products.module.css
new file mode 100644
index 0000000000..7988fabb67
--- /dev/null
+++ b/week3/project/e-commerce/src/components/Products/products.module.css
@@ -0,0 +1,29 @@
+.products {
+ margin-top: 5rem;
+}
+.product {
+ display: flex;
+ flex-wrap: wrap;
+ width: 100%;
+ max-width: 40rem;
+ padding: 1rem;
+ cursor: pointer;
+ border: 1px solid rgba(55, 55, 55, 0.15);
+ border-radius: 5px;
+}
+.product:hover {
+ border-radius: 5px;
+ box-shadow: 0 0 10px rgba(55, 55, 55, 0.5);
+}
+.image {
+ width: 100%;
+ aspect-ratio: 3 / 4;
+ object-fit: contain;
+ display: block;
+ max-height: 50rem;
+}
+.favorite {
+ position: absolute;
+ cursor: pointer;
+ width: 2.2rem;
+}
diff --git a/week3/project/e-commerce/src/context/favouriteContext.jsx b/week3/project/e-commerce/src/context/favouriteContext.jsx
new file mode 100644
index 0000000000..2e6afc95a4
--- /dev/null
+++ b/week3/project/e-commerce/src/context/favouriteContext.jsx
@@ -0,0 +1,13 @@
+import { createContext, useState } from "react";
+
+export const FavouriteContext = createContext([]);
+
+export default function FavouriteContextProvider({ children }) {
+ const [favourite, setFavourite] = useState([]);
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/week3/project/e-commerce/src/context/statusContext.jsx b/week3/project/e-commerce/src/context/statusContext.jsx
new file mode 100644
index 0000000000..a463d4cdca
--- /dev/null
+++ b/week3/project/e-commerce/src/context/statusContext.jsx
@@ -0,0 +1,14 @@
+import { createContext, useState } from "react";
+
+export const StatusContext = createContext([]);
+
+export default function StatusContextProvider({ children }) {
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/week3/project/e-commerce/src/hooks/useFetch.js b/week3/project/e-commerce/src/hooks/useFetch.js
new file mode 100644
index 0000000000..eaca160dd8
--- /dev/null
+++ b/week3/project/e-commerce/src/hooks/useFetch.js
@@ -0,0 +1,35 @@
+import { useContext, useEffect, useState } from "react";
+import { StatusContext } from "../context/statusContext.jsx";
+
+function useFetch(url) {
+ const [data, setData] = useState(null);
+ const { loading, setLoading, error, setError } = useContext(StatusContext);
+
+ useEffect(() => {
+ setData(null);
+ setError(null);
+ setLoading(false);
+
+ setLoading(true);
+ const fetchData = async () => {
+ try {
+ const response = await fetch(url);
+ if (!response.ok) {
+ const error = response.statusText || `Error: ${response.status}`;
+ return setError(error);
+ }
+ setData(await response.json());
+ } catch (e) {
+ setError(e.message);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchData();
+ }, [url, setLoading, setError]);
+
+ return { data, loading, error };
+}
+
+export default useFetch;
diff --git a/week3/project/e-commerce/src/hooks/useFetchMany.js b/week3/project/e-commerce/src/hooks/useFetchMany.js
new file mode 100644
index 0000000000..e860ae25af
--- /dev/null
+++ b/week3/project/e-commerce/src/hooks/useFetchMany.js
@@ -0,0 +1,40 @@
+import { useContext, useEffect, useState } from "react";
+import { StatusContext } from "../context/statusContext.jsx";
+
+function useFetchMany(url, array) {
+ const [data, setData] = useState(null);
+ const { loading, setLoading, error, setError } = useContext(StatusContext);
+
+ useEffect(() => {
+ setData(null);
+ setError(null);
+ setLoading(false);
+
+ if (!array || array.length === 0) {
+ setData([]);
+ return;
+ }
+
+ setLoading(true);
+
+ const fetchData = async () => {
+ try {
+ const productPromises = array.map((id) => fetch(url + id));
+ const results = await Promise.all(productPromises);
+ const promisesArray = results.map((result) => result.json());
+ const resultsArray = await Promise.all(promisesArray);
+ setData(resultsArray);
+ } catch (e) {
+ setError(e.message);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchData();
+ }, [array, setLoading, setError, url]);
+
+ return { data, loading, error };
+}
+
+export default useFetchMany;
diff --git a/week3/project/e-commerce/src/index.css b/week3/project/e-commerce/src/index.css
new file mode 100644
index 0000000000..6613870c3f
--- /dev/null
+++ b/week3/project/e-commerce/src/index.css
@@ -0,0 +1,132 @@
+:root {
+ --background: #fff;
+ --primary: #373737;
+ --secondary: #df473b;
+}
+html {
+ font-size: 62.5%;
+}
+body {
+ font-family: sans-serif;
+ background: var(--background);
+ color: var(--primary);
+}
+* {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+}
+h1 {
+ font-size: 4.6rem;
+}
+h3 {
+ font-size: 3.2rem;
+}
+li {
+ font-size: 2.4rem;
+}
+span,
+p {
+ font-size: 2rem;
+}
+a {
+ text-decoration: none;
+ color: var(--primary);
+}
+button {
+ cursor: pointer;
+ border: none;
+ background: var(--primary);
+ color: var(--background);
+ padding: 0.5rem 1rem;
+ border-radius: 5px;
+ margin: 0.5rem;
+ font-size: 2.1rem;
+}
+#root {
+ padding: 1rem;
+}
+
+/* Navbar */
+
+.navbar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 2rem;
+ border-bottom: 1px solid var(--primary);
+}
+.logo {
+ font-size: 3.2rem;
+ border: 1px solid var(--primary);
+ padding: 0.5rem 2rem;
+ border-radius: 45px;
+ cursor: pointer;
+}
+
+/* Title */
+
+.title {
+ text-align: center;
+ margin: 2rem;
+}
+
+/* Products */
+
+.productsList {
+ list-style: none;
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(30rem, 1fr));
+ gap: 2rem;
+}
+
+/* ProductPage */
+
+.productPage {
+ display: flex;
+ flex-direction: column;
+ padding: 1rem;
+}
+
+/* Loading and error */
+
+.loading {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+.error {
+ position: fixed;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 1000;
+ padding: 5rem;
+}
+.error {
+ background: var(--background);
+}
+
+/* Media Query */
+
+@media (max-width: 800px) {
+ h1 {
+ font-size: 3rem;
+ }
+ p {
+ font-size: 1.6rem;
+ }
+ .logo {
+ font-size: 2.4rem;
+ }
+ button {
+ font-size: 1.6rem;
+ padding: 0.5rem 1rem;
+ }
+}
diff --git a/week3/project/e-commerce/src/main.jsx b/week3/project/e-commerce/src/main.jsx
new file mode 100644
index 0000000000..66e6e04456
--- /dev/null
+++ b/week3/project/e-commerce/src/main.jsx
@@ -0,0 +1,27 @@
+import { StrictMode } from "react";
+import { createRoot } from "react-dom/client";
+import { BrowserRouter, Route, Routes } from "react-router-dom";
+import "./index.css";
+import Home from "./pages/Home.jsx";
+import ProductPage from "./pages/ProductPage.jsx";
+import FavouritesPage from "./pages/FavouritesPage.jsx";
+import StatusContextProvider from "./context/statusContext.jsx";
+import FavouriteContextProvider from "./context/favouriteContext.jsx";
+import Navbar from "./components/Navbar.jsx";
+
+createRoot(document.getElementById("root")).render(
+
+
+
+
+
+
+ } />
+ } />
+ } />
+
+
+
+
+ ,
+);
diff --git a/week3/project/e-commerce/src/pages/FavouritesPage.jsx b/week3/project/e-commerce/src/pages/FavouritesPage.jsx
new file mode 100644
index 0000000000..45fb5ba943
--- /dev/null
+++ b/week3/project/e-commerce/src/pages/FavouritesPage.jsx
@@ -0,0 +1,27 @@
+import { useContext } from "react";
+import Error from "../components/Error/Error.jsx";
+import Loading from "../components/Loading.jsx";
+import Product from "../components/Products/Product.jsx";
+import { FavouriteContext } from "../context/favouriteContext.jsx";
+import useFetchMany from "../hooks/useFetchMany.js";
+import ProductList from "../components/ProductList.jsx";
+
+function FavouritesPage() {
+ const { favourite } = useContext(FavouriteContext);
+
+ const url = "https://fakestoreapi.com/products/";
+ const { data, loading, error } = useFetchMany(url, favourite);
+
+ if (error) return ;
+ if (!data || loading) return ;
+
+ return (
+
+
Favourites
+ {data.length === 0 &&
You have no favourites
}
+
+
+ );
+}
+
+export default FavouritesPage;
diff --git a/week3/project/e-commerce/src/pages/Home.jsx b/week3/project/e-commerce/src/pages/Home.jsx
new file mode 100644
index 0000000000..0c49858b7c
--- /dev/null
+++ b/week3/project/e-commerce/src/pages/Home.jsx
@@ -0,0 +1,20 @@
+import Categories from "../components/Categories/Categories.jsx";
+import Products from "../components/Products/Products.jsx";
+import { useState } from "react";
+
+function Home() {
+ const [selectedCategory, setCategory] = useState(null);
+
+ return (
+ <>
+ Products
+
+
+ >
+ );
+}
+
+export default Home;
diff --git a/week3/project/e-commerce/src/pages/ProductPage.jsx b/week3/project/e-commerce/src/pages/ProductPage.jsx
new file mode 100644
index 0000000000..f606d029d5
--- /dev/null
+++ b/week3/project/e-commerce/src/pages/ProductPage.jsx
@@ -0,0 +1,25 @@
+import { useParams } from "react-router-dom";
+import Loading from "../components/Loading.jsx";
+import Error from "../components/Error/Error.jsx";
+import ProductCard from "../components/ProductCard/ProductCard.jsx";
+import style from "../components/ProductCard/productPage.module.css";
+import useFetch from "../hooks/useFetch.js";
+
+function ProductPage() {
+ const { id } = useParams();
+
+ const url = `https://fakestoreapi.com/products/${id}`;
+ const { data, loading, error } = useFetch(url);
+
+ if (error) return ;
+ if (loading || !data) return ;
+
+ return (
+
+ );
+}
+
+export default ProductPage;
diff --git a/week3/project/e-commerce/vite.config.js b/week3/project/e-commerce/vite.config.js
new file mode 100644
index 0000000000..0e43ae8def
--- /dev/null
+++ b/week3/project/e-commerce/vite.config.js
@@ -0,0 +1,7 @@
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+
+// https://vite.dev/config/
+export default defineConfig({
+ plugins: [react()],
+});