From 6f6a74ed3e317921ac83b231c0c6fecfb588b3f3 Mon Sep 17 00:00:00 2001 From: Soy Date: Mon, 1 Jun 2026 19:07:31 +0900 Subject: [PATCH 01/48] =?UTF-8?q?chore:=20=EC=A0=84=EC=97=AD=20ignore?= =?UTF-8?q?=EC=97=90=20env=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 070608f..2a9d2b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -**/images/ \ No newline at end of file +**/images/ +.env \ No newline at end of file From 63f350a8983027d11981f6fc78bdd952cebb50cd Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 00:25:33 +0900 Subject: [PATCH 02/48] =?UTF-8?q?init:=20=ED=94=84=EB=A1=9C=EC=A0=9D?= =?UTF-8?q?=ED=8A=B8=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/.gitignore | 24 + week6/homework/README.md | 73 + week6/homework/eslint.config.js | 22 + week6/homework/index.html | 13 + week6/homework/package.json | 34 + week6/homework/pnpm-lock.yaml | 2145 ++++++++++++++++++++++++++ week6/homework/public/favicon.svg | 1 + week6/homework/public/icons.svg | 24 + week6/homework/src/App.tsx | 5 + week6/homework/src/main.tsx | 10 + week6/homework/src/routes/router.tsx | 0 week6/homework/tsconfig.app.json | 25 + week6/homework/tsconfig.json | 7 + week6/homework/tsconfig.node.json | 24 + week6/homework/vite.config.ts | 8 + 15 files changed, 2415 insertions(+) create mode 100644 week6/homework/.gitignore create mode 100644 week6/homework/README.md create mode 100644 week6/homework/eslint.config.js create mode 100644 week6/homework/index.html create mode 100644 week6/homework/package.json create mode 100644 week6/homework/pnpm-lock.yaml create mode 100644 week6/homework/public/favicon.svg create mode 100644 week6/homework/public/icons.svg create mode 100644 week6/homework/src/App.tsx create mode 100644 week6/homework/src/main.tsx create mode 100644 week6/homework/src/routes/router.tsx create mode 100644 week6/homework/tsconfig.app.json create mode 100644 week6/homework/tsconfig.json create mode 100644 week6/homework/tsconfig.node.json create mode 100644 week6/homework/vite.config.ts diff --git a/week6/homework/.gitignore b/week6/homework/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/week6/homework/.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/week6/homework/README.md b/week6/homework/README.md new file mode 100644 index 0000000..7dbf7eb --- /dev/null +++ b/week6/homework/README.md @@ -0,0 +1,73 @@ +# React + TypeScript + 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 [Oxc](https://oxc.rs) +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) + +## React Compiler + +The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: + +```js +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + + // Remove tseslint.configs.recommended and replace with this + tseslint.configs.recommendedTypeChecked, + // Alternatively, use this for stricter rules + tseslint.configs.strictTypeChecked, + // Optionally, add this for stylistic rules + tseslint.configs.stylisticTypeChecked, + + // Other configs... + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]) +``` + +You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: + +```js +// eslint.config.js +import reactX from 'eslint-plugin-react-x' +import reactDom from 'eslint-plugin-react-dom' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + // Enable lint rules for React + reactX.configs['recommended-typescript'], + // Enable lint rules for React DOM + reactDom.configs.recommended, + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]) +``` diff --git a/week6/homework/eslint.config.js b/week6/homework/eslint.config.js new file mode 100644 index 0000000..ef614d2 --- /dev/null +++ b/week6/homework/eslint.config.js @@ -0,0 +1,22 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + globals: globals.browser, + }, + }, +]) diff --git a/week6/homework/index.html b/week6/homework/index.html new file mode 100644 index 0000000..61a8c11 --- /dev/null +++ b/week6/homework/index.html @@ -0,0 +1,13 @@ + + + + + + + homework + + +
+ + + diff --git a/week6/homework/package.json b/week6/homework/package.json new file mode 100644 index 0000000..1605640 --- /dev/null +++ b/week6/homework/package.json @@ -0,0 +1,34 @@ +{ + "name": "homework", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@tailwindcss/vite": "^4.3.0", + "@tanstack/react-query": "^5.100.14", + "axios": "^1.16.1", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@types/node": "^24.12.3", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^10.3.0", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.6.0", + "tailwindcss": "^4.3.0", + "typescript": "~6.0.2", + "typescript-eslint": "^8.59.2", + "vite": "^8.0.12" + } +} diff --git a/week6/homework/pnpm-lock.yaml b/week6/homework/pnpm-lock.yaml new file mode 100644 index 0000000..3112301 --- /dev/null +++ b/week6/homework/pnpm-lock.yaml @@ -0,0 +1,2145 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@tailwindcss/vite': + specifier: ^4.3.0 + version: 4.3.0(vite@8.0.16(@types/node@24.12.4)(jiti@2.7.0)) + '@tanstack/react-query': + specifier: ^5.100.14 + version: 5.100.14(react@19.2.6) + axios: + specifier: ^1.16.1 + version: 1.16.1 + react: + specifier: ^19.2.6 + version: 19.2.6 + react-dom: + specifier: ^19.2.6 + version: 19.2.6(react@19.2.6) + devDependencies: + '@eslint/js': + specifier: ^10.0.1 + version: 10.0.1(eslint@10.4.1(jiti@2.7.0)) + '@types/node': + specifier: ^24.12.3 + version: 24.12.4 + '@types/react': + specifier: ^19.2.14 + version: 19.2.15 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.15) + '@vitejs/plugin-react': + specifier: ^6.0.1 + version: 6.0.2(vite@8.0.16(@types/node@24.12.4)(jiti@2.7.0)) + eslint: + specifier: ^10.3.0 + version: 10.4.1(jiti@2.7.0) + eslint-plugin-react-hooks: + specifier: ^7.1.1 + version: 7.1.1(eslint@10.4.1(jiti@2.7.0)) + eslint-plugin-react-refresh: + specifier: ^0.5.2 + version: 0.5.2(eslint@10.4.1(jiti@2.7.0)) + globals: + specifier: ^17.6.0 + version: 17.6.0 + tailwindcss: + specifier: ^4.3.0 + version: 4.3.0 + typescript: + specifier: ~6.0.2 + version: 6.0.3 + typescript-eslint: + specifier: ^8.59.2 + version: 8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + vite: + specifier: ^8.0.12 + version: 8.0.16(@types/node@24.12.4)(jiti@2.7.0) + +packages: + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + 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.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/config-helpers@0.6.0': + resolution: {integrity: sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/js@10.0.1': + resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + peerDependencies: + eslint: ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true + + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/plugin-kit@0.7.2': + resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@napi-rs/wasm-runtime@1.1.4': + resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@oxc-project/types@0.133.0': + resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + + '@rolldown/binding-android-arm64@1.0.3': + resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.3': + resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.3': + resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.3': + resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.3': + resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.3': + resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.3': + resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.3': + resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.3': + resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.3': + resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@tailwindcss/node@4.3.0': + resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} + + '@tailwindcss/oxide-android-arm64@4.3.0': + resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.0': + resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.0': + resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} + engines: {node: '>= 20'} + + '@tailwindcss/vite@4.3.0': + resolution: {integrity: sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 || ^8 + + '@tanstack/query-core@5.100.14': + resolution: {integrity: sha512-5X41dGpxgeaHISCRW2oYwcSycZeULZzAunaudXT9ov1KOTj9xwt0CH6hbwqP1/z74ZWF7rYFnDpyYH07XFcZew==} + + '@tanstack/react-query@5.100.14': + resolution: {integrity: sha512-oOr6aRdSFEwWhzxEkD/9ZcItM3+LjBSkeVmadWKwUssAHTsqd/7bOjWrX4AbvEkoEhgAxzN0Xk6H/aYzXiYBAw==} + peerDependencies: + react: ^18 || ^19 + + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/node@24.12.4': + resolution: {integrity: sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.15': + resolution: {integrity: sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==} + + '@typescript-eslint/eslint-plugin@8.60.0': + resolution: {integrity: sha512-QYb/sa74/s7OKMbACMjrYnGspj9Hs5YI5aaffSL65UfeBUzVzBJfVo3oWSpbzPurvm7yaCCo2Lk7lVj610HqKw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.60.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/parser@8.60.0': + resolution: {integrity: sha512-fcqpj/MyK4sxDPcbe7STNPbpQL4RLZOPWuaTmwZYuc+hJKzRf58yRxfhqGpc6PIq9ZyfSBpfHgmUHmHs0KwHwg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.60.0': + resolution: {integrity: sha512-aZu74NNKJeUWqCjDddzdiKaS82dgYgV/vmf+Ui3ZdZejmgfXR/q+pRumgobnQ2cCJTgGTWp4ypiwsuofFubavg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.60.0': + resolution: {integrity: sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.60.0': + resolution: {integrity: sha512-BZPR3RGYlAXnly6ymAxfkVn5rCbZzQNou0rxv3GfWZ8cTQp+hhVd73khbGLAd8k1TlAPLISH337M+tAgAnaJDQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.60.0': + resolution: {integrity: sha512-SX46wEUtitCpq7AN38HkUU/+zvUpdKf7ephtWAFgckH8O7PQIyL5gvrhQgBLuEYgLfuKWOVvWVskMbuFHAz5xg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.60.0': + resolution: {integrity: sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.60.0': + resolution: {integrity: sha512-3AcZNBGMClm6CXDyo8kYvVGT/sx29sS0oBsIb9oZI2gunA4Vm2M3YHzRLPvsUBBsl+yB5FPtltq7gGH0iTlp9g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.60.0': + resolution: {integrity: sha512-HtXuPfrHTyBDkameWpl+vJb1Uevu2tznAyahM1Oc4AENidCLTPiZDWIo4GfcxNdC/RcfGcadzzkqbRG87dUrQA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.60.0': + resolution: {integrity: sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@vitejs/plugin-react@6.0.2': + resolution: {integrity: sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + vite: ^8.0.0 + peerDependenciesMeta: + '@rolldown/plugin-babel': + optional: true + babel-plugin-react-compiler: + optional: true + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.16.1: + resolution: {integrity: sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + baseline-browser-mapping@2.10.33: + resolution: {integrity: sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==} + engines: {node: '>=6.0.0'} + hasBin: true + + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + engines: {node: 18 || 20 || >=22} + + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + caniuse-lite@1.0.30001793: + resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + 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==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + electron-to-chromium@1.5.364: + resolution: {integrity: sha512-G/dYE3+AYhyHwzTwg8UbnXf7zqMERYh7l2jJ3QujhFsH8agSYwtnGAR2aZ7f0AakIKJXd5En/Hre4igIUrdlYw==} + + enhanced-resolve@5.22.1: + resolution: {integrity: sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==} + engines: {node: '>=10.13.0'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + 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@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 + + eslint-plugin-react-refresh@0.5.2: + resolution: {integrity: sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==} + peerDependencies: + eslint: ^9 || ^10 + + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + 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@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@10.4.1: + resolution: {integrity: sha512-AyIKhnOBuOAdueD7RB3xB+YeAWScb9jHsJBgH2Hcde8InP5JYhqrRR6iTMHyTEwgENK54Cp44e4v8BwNhsuHuw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + 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.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + 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.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@17.6.0: + resolution: {integrity: sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==} + engines: {node: '>=18'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + 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==} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + 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'} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + 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.46: + resolution: {integrity: sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==} + engines: {node: '>=18'} + + 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'} + + 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.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + react-dom@19.2.6: + resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} + peerDependencies: + react: ^19.2.6 + + react@19.2.6: + resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} + engines: {node: '>=0.10.0'} + + rolldown@1.0.3: + resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.8.1: + resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} + engines: {node: '>=10'} + hasBin: true + + 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'} + + tailwindcss@4.3.0: + resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typescript-eslint@8.60.0: + resolution: {integrity: sha512-9f65qWLZdAW9m1JaxBDUHcqRUfL8bkxxXL7XxEfI+F09q56PkBvIfCjLF3yInsDM/BBmwkqmCQdCZe/RYlIWEw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + vite@8.0.16: + resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.18 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + 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'} + + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + +snapshots: + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.7': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/traverse@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@10.4.1(jiti@2.7.0))': + dependencies: + eslint: 10.4.1(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.23.5': + dependencies: + '@eslint/object-schema': 3.0.5 + debug: 4.4.3 + minimatch: 10.2.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.6.0': + dependencies: + '@eslint/core': 1.2.1 + + '@eslint/core@1.2.1': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/js@10.0.1(eslint@10.4.1(jiti@2.7.0))': + optionalDependencies: + eslint: 10.4.1(jiti@2.7.0) + + '@eslint/object-schema@3.0.5': {} + + '@eslint/plugin-kit@0.7.2': + dependencies: + '@eslint/core': 1.2.1 + levn: 0.4.1 + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 + optional: true + + '@oxc-project/types@0.133.0': {} + + '@rolldown/binding-android-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-x64@1.0.3': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.3': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.3': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.3': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.3': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.3': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.3': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@tailwindcss/node@4.3.0': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.22.1 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.0 + + '@tailwindcss/oxide-android-arm64@4.3.0': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.0': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + optional: true + + '@tailwindcss/oxide@4.3.0': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-x64': 4.3.0 + '@tailwindcss/oxide-freebsd-x64': 4.3.0 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.0 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.0 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-x64-musl': 4.3.0 + '@tailwindcss/oxide-wasm32-wasi': 4.3.0 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 + + '@tailwindcss/vite@4.3.0(vite@8.0.16(@types/node@24.12.4)(jiti@2.7.0))': + dependencies: + '@tailwindcss/node': 4.3.0 + '@tailwindcss/oxide': 4.3.0 + tailwindcss: 4.3.0 + vite: 8.0.16(@types/node@24.12.4)(jiti@2.7.0) + + '@tanstack/query-core@5.100.14': {} + + '@tanstack/react-query@5.100.14(react@19.2.6)': + dependencies: + '@tanstack/query-core': 5.100.14 + react: 19.2.6 + + '@tybys/wasm-util@0.10.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/esrecurse@4.3.1': {} + + '@types/estree@1.0.9': {} + + '@types/json-schema@7.0.15': {} + + '@types/node@24.12.4': + dependencies: + undici-types: 7.16.0 + + '@types/react-dom@19.2.3(@types/react@19.2.15)': + dependencies: + '@types/react': 19.2.15 + + '@types/react@19.2.15': + dependencies: + csstype: 3.2.3 + + '@typescript-eslint/eslint-plugin@8.60.0(@typescript-eslint/parser@8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.60.0 + '@typescript-eslint/type-utils': 8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.60.0 + eslint: 10.4.1(jiti@2.7.0) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.60.0 + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.60.0 + debug: 4.4.3 + eslint: 10.4.1(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.60.0(typescript@6.0.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.60.0(typescript@6.0.3) + '@typescript-eslint/types': 8.60.0 + debug: 4.4.3 + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.60.0': + dependencies: + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/visitor-keys': 8.60.0 + + '@typescript-eslint/tsconfig-utils@8.60.0(typescript@6.0.3)': + dependencies: + typescript: 6.0.3 + + '@typescript-eslint/type-utils@8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + debug: 4.4.3 + eslint: 10.4.1(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.60.0': {} + + '@typescript-eslint/typescript-estree@8.60.0(typescript@6.0.3)': + dependencies: + '@typescript-eslint/project-service': 8.60.0(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.60.0(typescript@6.0.3) + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/visitor-keys': 8.60.0 + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.8.1 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.1(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.60.0 + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) + eslint: 10.4.1(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.60.0': + dependencies: + '@typescript-eslint/types': 8.60.0 + eslint-visitor-keys: 5.0.1 + + '@vitejs/plugin-react@6.0.2(vite@8.0.16(@types/node@24.12.4)(jiti@2.7.0))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 8.0.16(@types/node@24.12.4)(jiti@2.7.0) + + acorn-jsx@5.3.2(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + + acorn@8.16.0: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ajv@6.15.0: + 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 + + asynckit@0.4.0: {} + + axios@1.16.1: + dependencies: + follow-redirects: 1.16.0 + form-data: 4.0.5 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + + balanced-match@4.0.4: {} + + baseline-browser-mapping@2.10.33: {} + + brace-expansion@5.0.6: + dependencies: + balanced-match: 4.0.4 + + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.33 + caniuse-lite: 1.0.30001793 + electron-to-chromium: 1.5.364 + node-releases: 2.0.46 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + caniuse-lite@1.0.30001793: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + convert-source-map@2.0.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + delayed-stream@1.0.0: {} + + detect-libc@2.1.2: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + electron-to-chromium@1.5.364: {} + + enhanced-resolve@5.22.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-plugin-react-hooks@7.1.1(eslint@10.4.1(jiti@2.7.0)): + dependencies: + '@babel/core': 7.29.7 + '@babel/parser': 7.29.7 + eslint: 10.4.1(jiti@2.7.0) + hermes-parser: 0.25.1 + zod: 4.4.3 + zod-validation-error: 4.0.2(zod@4.4.3) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-refresh@0.5.2(eslint@10.4.1(jiti@2.7.0)): + dependencies: + eslint: 10.4.1(jiti@2.7.0) + + eslint-scope@9.1.2: + dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.9 + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@10.4.1(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.1(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.6.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.2 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esquery: 1.7.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 + minimatch: 10.2.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + + espree@11.2.0: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 5.0.1 + + esquery@1.7.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.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + 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.4.2 + keyv: 4.5.4 + + flatted@3.4.2: {} + + follow-redirects@1.16.0: {} + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 + mime-types: 2.1.35 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@17.6.0: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + imurmurhash@0.1.4: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + isexe@2.0.0: {} + + jiti@2.7.0: {} + + js-tokens@4.0.0: {} + + 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 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + math-intrinsics@1.1.0: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.6 + + ms@2.1.3: {} + + nanoid@3.3.12: {} + + natural-compare@1.4.0: {} + + node-releases@2.0.46: {} + + 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 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + picocolors@1.1.1: {} + + picomatch@4.0.4: {} + + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + proxy-from-env@2.1.0: {} + + punycode@2.3.1: {} + + react-dom@19.2.6(react@19.2.6): + dependencies: + react: 19.2.6 + scheduler: 0.27.0 + + react@19.2.6: {} + + rolldown@1.0.3: + dependencies: + '@oxc-project/types': 0.133.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.3 + '@rolldown/binding-darwin-arm64': 1.0.3 + '@rolldown/binding-darwin-x64': 1.0.3 + '@rolldown/binding-freebsd-x64': 1.0.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 + '@rolldown/binding-linux-arm64-gnu': 1.0.3 + '@rolldown/binding-linux-arm64-musl': 1.0.3 + '@rolldown/binding-linux-ppc64-gnu': 1.0.3 + '@rolldown/binding-linux-s390x-gnu': 1.0.3 + '@rolldown/binding-linux-x64-gnu': 1.0.3 + '@rolldown/binding-linux-x64-musl': 1.0.3 + '@rolldown/binding-openharmony-arm64': 1.0.3 + '@rolldown/binding-wasm32-wasi': 1.0.3 + '@rolldown/binding-win32-arm64-msvc': 1.0.3 + '@rolldown/binding-win32-x64-msvc': 1.0.3 + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + semver@7.8.1: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + source-map-js@1.2.1: {} + + tailwindcss@4.3.0: {} + + tapable@2.3.3: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + ts-api-utils@2.5.0(typescript@6.0.3): + dependencies: + typescript: 6.0.3 + + tslib@2.8.1: + optional: true + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typescript-eslint@8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.60.0(@typescript-eslint/parser@8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.4.1(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + typescript@6.0.3: {} + + undici-types@7.16.0: {} + + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + vite@8.0.16(@types/node@24.12.4)(jiti@2.7.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.0.3 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 24.12.4 + fsevents: 2.3.3 + jiti: 2.7.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + yallist@3.1.1: {} + + yocto-queue@0.1.0: {} + + zod-validation-error@4.0.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@4.4.3: {} diff --git a/week6/homework/public/favicon.svg b/week6/homework/public/favicon.svg new file mode 100644 index 0000000..6893eb1 --- /dev/null +++ b/week6/homework/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/week6/homework/public/icons.svg b/week6/homework/public/icons.svg new file mode 100644 index 0000000..e952219 --- /dev/null +++ b/week6/homework/public/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/week6/homework/src/App.tsx b/week6/homework/src/App.tsx new file mode 100644 index 0000000..b4f6543 --- /dev/null +++ b/week6/homework/src/App.tsx @@ -0,0 +1,5 @@ +function App() { + return <>; +} + +export default App; diff --git a/week6/homework/src/main.tsx b/week6/homework/src/main.tsx new file mode 100644 index 0000000..9f78e4b --- /dev/null +++ b/week6/homework/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import "./styles/index.css"; +import App from "./App.tsx"; + +createRoot(document.getElementById("root")!).render( + + + , +); diff --git a/week6/homework/src/routes/router.tsx b/week6/homework/src/routes/router.tsx new file mode 100644 index 0000000..e69de29 diff --git a/week6/homework/tsconfig.app.json b/week6/homework/tsconfig.app.json new file mode 100644 index 0000000..7f42e5f --- /dev/null +++ b/week6/homework/tsconfig.app.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "es2023", + "lib": ["ES2023", "DOM"], + "module": "esnext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/week6/homework/tsconfig.json b/week6/homework/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/week6/homework/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/week6/homework/tsconfig.node.json b/week6/homework/tsconfig.node.json new file mode 100644 index 0000000..d3c52ea --- /dev/null +++ b/week6/homework/tsconfig.node.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "es2023", + "lib": ["ES2023"], + "module": "esnext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["vite.config.ts"] +} diff --git a/week6/homework/vite.config.ts b/week6/homework/vite.config.ts new file mode 100644 index 0000000..4ff4f8f --- /dev/null +++ b/week6/homework/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import tailwindcss from "@tailwindcss/vite"; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}); From cbb867f5768e8be8e0f1c566821e8e5d5a61e606 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 00:34:27 +0900 Subject: [PATCH 03/48] =?UTF-8?q?chore:=20=EC=A0=88=EB=8C=80=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/tsconfig.app.json | 16 +++++++++++++++- week6/homework/vite.config.ts | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/week6/homework/tsconfig.app.json b/week6/homework/tsconfig.app.json index 7f42e5f..0a7eb81 100644 --- a/week6/homework/tsconfig.app.json +++ b/week6/homework/tsconfig.app.json @@ -19,7 +19,21 @@ "noUnusedLocals": true, "noUnusedParameters": true, "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + + "paths": { + "@pages/*": ["./src/pages/*"], + "@routes/*": ["./src/routes/*"], + "@apis/*": ["./src/shared/apis/*"], + "@assets/*": ["./src/shared/assets/*"], + "@components/*": ["./src/shared/components/*"], + "@hooks/*": ["./src/shared/hooks/*"], + "@styles/*": ["./src/shared/styles/*"], + "@utils/*": ["./src/shared/utils/*"], + "@constants/*": ["./src/shared/constants/*"], + "@shared/*": ["./src/shared/*"], + "@/*": ["./src/*"] + } }, "include": ["src"] } diff --git a/week6/homework/vite.config.ts b/week6/homework/vite.config.ts index 4ff4f8f..32c65d5 100644 --- a/week6/homework/vite.config.ts +++ b/week6/homework/vite.config.ts @@ -1,8 +1,24 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; import tailwindcss from "@tailwindcss/vite"; +import path from "path"; // https://vite.dev/config/ export default defineConfig({ plugins: [react(), tailwindcss()], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + "@pages": path.resolve(__dirname, "./src/pages"), + "@routes": path.resolve(__dirname, "./src/routes"), + "@apis": path.resolve(__dirname, "./src/shared/apis"), + "@assets": path.resolve(__dirname, "./src/shared/assets"), + "@components": path.resolve(__dirname, "./src/shared/components"), + "@hooks": path.resolve(__dirname, "./src/shared/hooks"), + "@styles": path.resolve(__dirname, "./src/shared/styles"), + "@utils": path.resolve(__dirname, "./src/shared/utils"), + "@constants": path.resolve(__dirname, "./src/shared/constants"), + "@shared": path.resolve(__dirname, "./src/shared"), + }, + }, }); From f8bc4f9a4302526ece05818affe32b9ea74101d1 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 00:34:36 +0900 Subject: [PATCH 04/48] =?UTF-8?q?chore:=20=EB=9D=BC=EC=9A=B0=ED=84=B0=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/package.json | 4 +- week6/homework/pnpm-lock.yaml | 48 +++++++++++++++++++ .../src/pages/movieDetail/MovieDetailPage.tsx | 5 ++ .../src/pages/movieList/MovieListPage.tsx | 5 ++ week6/homework/src/routes/router.tsx | 29 +++++++++++ week6/homework/src/shared/constants/path.ts | 4 ++ 6 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 week6/homework/src/pages/movieDetail/MovieDetailPage.tsx create mode 100644 week6/homework/src/pages/movieList/MovieListPage.tsx create mode 100644 week6/homework/src/shared/constants/path.ts diff --git a/week6/homework/package.json b/week6/homework/package.json index 1605640..2c9494b 100644 --- a/week6/homework/package.json +++ b/week6/homework/package.json @@ -14,7 +14,9 @@ "@tanstack/react-query": "^5.100.14", "axios": "^1.16.1", "react": "^19.2.6", - "react-dom": "^19.2.6" + "react-dom": "^19.2.6", + "react-router": "^7.16.0", + "react-router-dom": "^7.16.0" }, "devDependencies": { "@eslint/js": "^10.0.1", diff --git a/week6/homework/pnpm-lock.yaml b/week6/homework/pnpm-lock.yaml index 3112301..b026370 100644 --- a/week6/homework/pnpm-lock.yaml +++ b/week6/homework/pnpm-lock.yaml @@ -23,6 +23,12 @@ importers: react-dom: specifier: ^19.2.6 version: 19.2.6(react@19.2.6) + react-router: + specifier: ^7.16.0 + version: 7.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router-dom: + specifier: ^7.16.0 + version: 7.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) devDependencies: '@eslint/js': specifier: ^10.0.1 @@ -566,6 +572,10 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -999,6 +1009,23 @@ packages: peerDependencies: react: ^19.2.6 + react-router-dom@7.16.0: + resolution: {integrity: sha512-kMUAbimWB5FVbF4Bce4bJsiKJWLIUHq/mEG8+CFDnCSgltptBiG5nguducmsJeGKytlCvQud9Qhzpn49iduTlA==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.16.0: + resolution: {integrity: sha512-wArC8lVyJb3+jM9OpDyW6hLCizACWkvQR/sSGqSs+o5uEXEtGlqdZ4v8hENR3Jad6i+LRkK93q/+bQAcvl6V1A==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + react@19.2.6: resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} engines: {node: '>=0.10.0'} @@ -1020,6 +1047,9 @@ packages: engines: {node: '>=10'} hasBin: true + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1649,6 +1679,8 @@ snapshots: convert-source-map@2.0.0: {} + cookie@1.1.1: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -2034,6 +2066,20 @@ snapshots: react: 19.2.6 scheduler: 0.27.0 + react-router-dom@7.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + dependencies: + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-router: 7.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + + react-router@7.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + dependencies: + cookie: 1.1.1 + react: 19.2.6 + set-cookie-parser: 2.7.2 + optionalDependencies: + react-dom: 19.2.6(react@19.2.6) + react@19.2.6: {} rolldown@1.0.3: @@ -2063,6 +2109,8 @@ snapshots: semver@7.8.1: {} + set-cookie-parser@2.7.2: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 diff --git a/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx b/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx new file mode 100644 index 0000000..b196867 --- /dev/null +++ b/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx @@ -0,0 +1,5 @@ +const MovieDetailPage = () => { + return
MovieDetailPage
; +}; + +export default MovieDetailPage; diff --git a/week6/homework/src/pages/movieList/MovieListPage.tsx b/week6/homework/src/pages/movieList/MovieListPage.tsx new file mode 100644 index 0000000..8339049 --- /dev/null +++ b/week6/homework/src/pages/movieList/MovieListPage.tsx @@ -0,0 +1,5 @@ +const MovieListPage = () => { + return
MovieListPage
; +}; + +export default MovieListPage; diff --git a/week6/homework/src/routes/router.tsx b/week6/homework/src/routes/router.tsx index e69de29..8fb54be 100644 --- a/week6/homework/src/routes/router.tsx +++ b/week6/homework/src/routes/router.tsx @@ -0,0 +1,29 @@ +import { createBrowserRouter } from "react-router"; + +import { ROUTES } from "@constants/path"; + +const router = createBrowserRouter([ + { + path: ROUTES.MOVIE_LIST, + children: [ + { + path: ROUTES.MOVIE_LIST, + lazy: async () => { + const { default: MovieListPage } = + await import("@pages/movieList/MovieListPage"); + return { Component: MovieListPage }; + }, + }, + { + path: ROUTES.MOVIE_DETAIL, + lazy: async () => { + const { default: MovieDetailPage } = + await import("@pages/movieDetail/MovieDetailPage"); + return { Component: MovieDetailPage }; + }, + }, + ], + }, +]); + +export default router; diff --git a/week6/homework/src/shared/constants/path.ts b/week6/homework/src/shared/constants/path.ts new file mode 100644 index 0000000..d93e269 --- /dev/null +++ b/week6/homework/src/shared/constants/path.ts @@ -0,0 +1,4 @@ +export const ROUTES = { + MOVIE_LIST: "/", + MOVIE_DETAIL: "/movie/:id", +} as const; From fbef0eb6053551495ea6d980159bc331d29f13c7 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 00:34:50 +0900 Subject: [PATCH 05/48] =?UTF-8?q?style:=20=EC=A0=84=EC=97=AD=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/styles/index.css | 52 +++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 week6/homework/src/styles/index.css diff --git a/week6/homework/src/styles/index.css b/week6/homework/src/styles/index.css new file mode 100644 index 0000000..382b263 --- /dev/null +++ b/week6/homework/src/styles/index.css @@ -0,0 +1,52 @@ +@import url('https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css'); +@import 'tailwindcss'; + +@theme { + --font-sans: 'Pretendard Variable', Pretendard, system-ui, sans-serif; + + --color-background: #f5f5f4; + --color-background-muted: #eceae7; + --color-white: #ffffff; + --color-surface-soft: #f8f7f5; + --color-surface-strong: #e7e5e4; + + --color-border: #dfdbd7; + --color-border-strong: #c7c2bc; + + --color-text: #1f1f1c; + --color-text-soft: #52504b; + --color-text-inverse: #fafaf9; + + --color-accent: #4B5694; + --color-accent-strong: #111844; + --color-accent-soft: #7288AE; + + --shadow-card: 0 18px 40px rgba(15, 23, 42, 0.06); + --radius-card: 1.5rem; + --radius-pill: 999px; +} + +:root { + color: var(--color-text); + background-color: var(--color-background); + font-family: var(--font-sans); +} + +@layer base { + * { + @apply box-border; + } + + body { + @apply bg-background text-text antialiased; + min-height: 100vh; + } + + button, + input, + textarea, + select { + font: inherit; + cursor: pointer; + } +} From cdb5a2129a36e57c028dcb07e5e90424bc2651b1 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 00:37:38 +0900 Subject: [PATCH 06/48] =?UTF-8?q?chore:=20app=EC=97=90=20=EB=9D=BC?= =?UTF-8?q?=EC=9A=B0=ED=84=B0=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/App.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/week6/homework/src/App.tsx b/week6/homework/src/App.tsx index b4f6543..8cd38ae 100644 --- a/week6/homework/src/App.tsx +++ b/week6/homework/src/App.tsx @@ -1,5 +1,12 @@ +import router from "@routes/router"; +import { RouterProvider } from "react-router"; + function App() { - return <>; + return ( + <> + + + ); } export default App; From f1d954e56a0a5d553112c69a7744fe1065503c3e Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 01:17:47 +0900 Subject: [PATCH 07/48] =?UTF-8?q?chore:=20index.html=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/week6/homework/index.html b/week6/homework/index.html index 61a8c11..3053905 100644 --- a/week6/homework/index.html +++ b/week6/homework/index.html @@ -1,10 +1,10 @@ - + - homework + 6주차 과제
From ce4a349321a21d80649d502272a251a1fcc9e91d Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 01:17:58 +0900 Subject: [PATCH 08/48] =?UTF-8?q?style:=20=EC=BB=AC=EB=9F=AC=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/styles/index.css | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/week6/homework/src/styles/index.css b/week6/homework/src/styles/index.css index 382b263..b5d25c4 100644 --- a/week6/homework/src/styles/index.css +++ b/week6/homework/src/styles/index.css @@ -4,7 +4,6 @@ @theme { --font-sans: 'Pretendard Variable', Pretendard, system-ui, sans-serif; - --color-background: #f5f5f4; --color-background-muted: #eceae7; --color-white: #ffffff; --color-surface-soft: #f8f7f5; @@ -28,7 +27,7 @@ :root { color: var(--color-text); - background-color: var(--color-background); + background-color: var(--color-background-muted); font-family: var(--font-sans); } @@ -38,7 +37,7 @@ } body { - @apply bg-background text-text antialiased; + @apply bg-background-muted text-text antialiased; min-height: 100vh; } From b2b3941c9ed8b873f28e70ff7834a4b60205484a Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 01:32:43 +0900 Subject: [PATCH 09/48] =?UTF-8?q?feat:=20=EC=98=81=ED=99=94=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=B9=B4=EB=93=9C=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/movieList/MovieListPage.tsx | 29 ++++++++++++++++- .../movieList/components/card/ListCard.tsx | 32 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 week6/homework/src/pages/movieList/components/card/ListCard.tsx diff --git a/week6/homework/src/pages/movieList/MovieListPage.tsx b/week6/homework/src/pages/movieList/MovieListPage.tsx index 8339049..ebbfa0d 100644 --- a/week6/homework/src/pages/movieList/MovieListPage.tsx +++ b/week6/homework/src/pages/movieList/MovieListPage.tsx @@ -1,5 +1,32 @@ +import ListCard from "./components/card/ListCard"; + const MovieListPage = () => { - return
MovieListPage
; + return ( +
+

Movie Explorer

+
별점 필터링
+
+ + + +
+
+ ); }; export default MovieListPage; diff --git a/week6/homework/src/pages/movieList/components/card/ListCard.tsx b/week6/homework/src/pages/movieList/components/card/ListCard.tsx new file mode 100644 index 0000000..5857e73 --- /dev/null +++ b/week6/homework/src/pages/movieList/components/card/ListCard.tsx @@ -0,0 +1,32 @@ +interface ListCardProps { + title: string; + description: string; + imageUrl: string; + releaseDate: string; +} + +const ListCard = ({ + title, + description, + imageUrl, + releaseDate, +}: ListCardProps) => { + return ( +
+
+ {title} +
+
+

{title}

+

{releaseDate}

+

{description}

+
+
+ ); +}; + +export default ListCard; From cf46317482aa5e2d3b8d06b671f7597689822ae8 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 02:00:38 +0900 Subject: [PATCH 10/48] =?UTF-8?q?chore:=20tanstack=20query=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/package.json | 1 + week6/homework/pnpm-lock.yaml | 20 +++++++++++++++++++ week6/homework/src/main.tsx | 8 +++++++- week6/homework/src/shared/apis/queryClient.ts | 16 +++++++++++++++ week6/homework/vite.config.ts | 4 ++++ 5 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 week6/homework/src/shared/apis/queryClient.ts diff --git a/week6/homework/package.json b/week6/homework/package.json index 2c9494b..4293cbf 100644 --- a/week6/homework/package.json +++ b/week6/homework/package.json @@ -20,6 +20,7 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@tanstack/react-query-devtools": "^5.100.14", "@types/node": "^24.12.3", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", diff --git a/week6/homework/pnpm-lock.yaml b/week6/homework/pnpm-lock.yaml index b026370..02b7fa1 100644 --- a/week6/homework/pnpm-lock.yaml +++ b/week6/homework/pnpm-lock.yaml @@ -33,6 +33,9 @@ importers: '@eslint/js': specifier: ^10.0.1 version: 10.0.1(eslint@10.4.1(jiti@2.7.0)) + '@tanstack/react-query-devtools': + specifier: ^5.100.14 + version: 5.100.14(@tanstack/react-query@5.100.14(react@19.2.6))(react@19.2.6) '@types/node': specifier: ^24.12.3 version: 24.12.4 @@ -417,6 +420,15 @@ packages: '@tanstack/query-core@5.100.14': resolution: {integrity: sha512-5X41dGpxgeaHISCRW2oYwcSycZeULZzAunaudXT9ov1KOTj9xwt0CH6hbwqP1/z74ZWF7rYFnDpyYH07XFcZew==} + '@tanstack/query-devtools@5.100.14': + resolution: {integrity: sha512-g96SmSSQecYTYcyuAMRXr895GplJv01UGt7qttQWPOUyZ5EGz5tbRc589bMc2m5BsPFD6O0PCEAHdbDYNP6UBw==} + + '@tanstack/react-query-devtools@5.100.14': + resolution: {integrity: sha512-JkP5VDgKOw3t/QSA1OABRHEqx8BuNs5MfvZRooNqdvN57SzTuGq3fKR1a2IH5rqa5HDLUm+FOXUEnB9ueHiLzg==} + peerDependencies: + '@tanstack/react-query': ^5.100.14 + react: ^18 || ^19 + '@tanstack/react-query@5.100.14': resolution: {integrity: sha512-oOr6aRdSFEwWhzxEkD/9ZcItM3+LjBSkeVmadWKwUssAHTsqd/7bOjWrX4AbvEkoEhgAxzN0Xk6H/aYzXiYBAw==} peerDependencies: @@ -1495,6 +1507,14 @@ snapshots: '@tanstack/query-core@5.100.14': {} + '@tanstack/query-devtools@5.100.14': {} + + '@tanstack/react-query-devtools@5.100.14(@tanstack/react-query@5.100.14(react@19.2.6))(react@19.2.6)': + dependencies: + '@tanstack/query-devtools': 5.100.14 + '@tanstack/react-query': 5.100.14(react@19.2.6) + react: 19.2.6 + '@tanstack/react-query@5.100.14(react@19.2.6)': dependencies: '@tanstack/query-core': 5.100.14 diff --git a/week6/homework/src/main.tsx b/week6/homework/src/main.tsx index 9f78e4b..fa39fd9 100644 --- a/week6/homework/src/main.tsx +++ b/week6/homework/src/main.tsx @@ -2,9 +2,15 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import "./styles/index.css"; import App from "./App.tsx"; +import { QueryClientProvider } from "@tanstack/react-query"; +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; +import { queryClient } from "@apis/queryClient.ts"; createRoot(document.getElementById("root")!).render( - + + + {import.meta.env.DEV && } + , ); diff --git a/week6/homework/src/shared/apis/queryClient.ts b/week6/homework/src/shared/apis/queryClient.ts new file mode 100644 index 0000000..8ec32f6 --- /dev/null +++ b/week6/homework/src/shared/apis/queryClient.ts @@ -0,0 +1,16 @@ +import { QueryCache, QueryClient } from "@tanstack/react-query"; + +export const queryClient = new QueryClient({ + queryCache: new QueryCache({ + onError: (error) => { + if (import.meta.env.DEV) console.error("[React Query Error]", error); + }, + }), + defaultOptions: { + queries: { + refetchOnWindowFocus: false, // 브라우저 포커싱 시 자동 재요청 방지 + retry: 1, + staleTime: 1000 * 60 * 5, // 5분 + }, + }, +}); diff --git a/week6/homework/vite.config.ts b/week6/homework/vite.config.ts index 32c65d5..d9f26b2 100644 --- a/week6/homework/vite.config.ts +++ b/week6/homework/vite.config.ts @@ -7,6 +7,7 @@ import path from "path"; export default defineConfig({ plugins: [react(), tailwindcss()], resolve: { + dedupe: ["react", "react-dom"], alias: { "@": path.resolve(__dirname, "./src"), "@pages": path.resolve(__dirname, "./src/pages"), @@ -21,4 +22,7 @@ export default defineConfig({ "@shared": path.resolve(__dirname, "./src/shared"), }, }, + optimizeDeps: { + exclude: ["@tanstack/react-query-devtools"], + }, }); From e15570872e6738fc07bdc319327dc4cde6647549 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 02:02:33 +0900 Subject: [PATCH 11/48] =?UTF-8?q?chore:=20axios=20Instance=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8?= =?UTF-8?q?=ED=8A=B8=20=EC=83=81=EC=88=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../homework/src/shared/apis/axiosInstance.ts | 42 +++++++++++++++++++ .../src/shared/constants/apiEndpoints.ts | 17 ++++++++ 2 files changed, 59 insertions(+) create mode 100644 week6/homework/src/shared/apis/axiosInstance.ts create mode 100644 week6/homework/src/shared/constants/apiEndpoints.ts diff --git a/week6/homework/src/shared/apis/axiosInstance.ts b/week6/homework/src/shared/apis/axiosInstance.ts new file mode 100644 index 0000000..b723297 --- /dev/null +++ b/week6/homework/src/shared/apis/axiosInstance.ts @@ -0,0 +1,42 @@ +import axios, { AxiosError } from "axios"; + +const apiKey = import.meta.env.VITE_API_KEY; + +const getGuestSessionId = () => { + if (typeof window === "undefined") return null; + + return window.localStorage.getItem("guest_session_id"); +}; + +const axiosInstance = axios.create({ + baseURL: import.meta.env.VITE_API_BASE_URL, + headers: { + "Content-Type": "application/json", + }, + withCredentials: true, +}); + +axiosInstance.interceptors.request.use((config) => { + const guestSessionId = getGuestSessionId(); + + config.params = { + ...config.params, + api_key: config.params?.api_key ?? apiKey, + ...(guestSessionId && { + guest_session_id: config.params?.guest_session_id ?? guestSessionId, + }), + }; + + return config; +}); + +axiosInstance.interceptors.response.use( + (response) => { + return response; + }, + (error: AxiosError) => { + return Promise.reject(error); + }, +); + +export default axiosInstance; diff --git a/week6/homework/src/shared/constants/apiEndpoints.ts b/week6/homework/src/shared/constants/apiEndpoints.ts new file mode 100644 index 0000000..3ba5a68 --- /dev/null +++ b/week6/homework/src/shared/constants/apiEndpoints.ts @@ -0,0 +1,17 @@ +export const API_ENDPOINT = { + LIST: "/discover/movie", + DETAIL: (movieId: number) => `/movie/${movieId}`, + GUEST_ID: "/authentication/guest_session/new", + RATE: (movieId: number) => `/movie/${movieId}/rating`, + RATE_LIST: (guestSessionId: string) => + `/guest_session/${guestSessionId}/rated/movies`, + RATE_DELETE: (movieId: number) => `/movie/${movieId}/rating`, +} as const; + +// 헬퍼 타입: 중첩된 객체의 모든 리프(leaf) 값들을 추출 +export type DeepValues = T extends object + ? { [K in keyof T]: DeepValues }[keyof T] + : T; + +// 자동으로 모든 엔드포인트 문자열 추출 +export type ApiEndpoint = DeepValues; From ee4dc6ed4c49d02dcf151e617f714237e46061de Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 02:02:41 +0900 Subject: [PATCH 12/48] =?UTF-8?q?style:=20=EA=B8=B0=EB=B3=B8=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/styles/index.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/week6/homework/src/styles/index.css b/week6/homework/src/styles/index.css index b5d25c4..2d251e3 100644 --- a/week6/homework/src/styles/index.css +++ b/week6/homework/src/styles/index.css @@ -5,7 +5,6 @@ --font-sans: 'Pretendard Variable', Pretendard, system-ui, sans-serif; --color-background-muted: #eceae7; - --color-white: #ffffff; --color-surface-soft: #f8f7f5; --color-surface-strong: #e7e5e4; @@ -26,7 +25,7 @@ } :root { - color: var(--color-text); + color: black; background-color: var(--color-background-muted); font-family: var(--font-sans); } From b478bd456a35bb63bf3bb871eb206ad576b1fd4b Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 02:02:52 +0900 Subject: [PATCH 13/48] =?UTF-8?q?style:=20grid=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/pages/movieList/MovieListPage.tsx | 4 ++-- .../homework/src/pages/movieList/components/card/ListCard.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/week6/homework/src/pages/movieList/MovieListPage.tsx b/week6/homework/src/pages/movieList/MovieListPage.tsx index ebbfa0d..841cf7f 100644 --- a/week6/homework/src/pages/movieList/MovieListPage.tsx +++ b/week6/homework/src/pages/movieList/MovieListPage.tsx @@ -2,10 +2,10 @@ import ListCard from "./components/card/ListCard"; const MovieListPage = () => { return ( -
+

Movie Explorer

별점 필터링
-
+
{ return ( -
+
-

{title}

+

{title}

{releaseDate}

{description}

From 92a39fa979316945e405398389a8e4ecebf8c5fa Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 02:37:25 +0900 Subject: [PATCH 14/48] =?UTF-8?q?chore:=20=EA=B3=B5=ED=86=B5=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/shared/apis/axiosInstance.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/week6/homework/src/shared/apis/axiosInstance.ts b/week6/homework/src/shared/apis/axiosInstance.ts index b723297..c91763a 100644 --- a/week6/homework/src/shared/apis/axiosInstance.ts +++ b/week6/homework/src/shared/apis/axiosInstance.ts @@ -35,6 +35,12 @@ axiosInstance.interceptors.response.use( return response; }, (error: AxiosError) => { + if (import.meta.env.DEV) { + console.error("[API Error]", { + message: error.message, + }); + } + return Promise.reject(error); }, ); From bb3bb70cfe600194c4ae3dab4b24d1dec0a610fc Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 02:37:36 +0900 Subject: [PATCH 15/48] =?UTF-8?q?chore:=20http=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EC=83=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/shared/apis/https.ts | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 week6/homework/src/shared/apis/https.ts diff --git a/week6/homework/src/shared/apis/https.ts b/week6/homework/src/shared/apis/https.ts new file mode 100644 index 0000000..c302fdf --- /dev/null +++ b/week6/homework/src/shared/apis/https.ts @@ -0,0 +1,27 @@ +import axiosInstance from "./axiosInstance"; + +export const api = { + get: async (url: string, params?: Record) => { + const response = await axiosInstance.get(url, { params }); + return response.data; + }, + post: async ( + url: string, + body?: B, + params?: Record, + ) => { + const response = await axiosInstance.post(url, body, { params }); + return response.data; + }, + delete: async ( + url: string, + body?: B, + params?: Record, + ) => { + const response = await axiosInstance.delete(url, { + data: body, + params, + }); + return response.data; + }, +}; From 9010d8b71c1028b1fca92b2f1f995deb2c31a05a Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 02:53:55 +0900 Subject: [PATCH 16/48] =?UTF-8?q?fix:=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EC=97=86=EC=9D=84=20=EB=95=8C=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../movieList/components/card/ListCard.tsx | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/week6/homework/src/pages/movieList/components/card/ListCard.tsx b/week6/homework/src/pages/movieList/components/card/ListCard.tsx index ece8520..00297cf 100644 --- a/week6/homework/src/pages/movieList/components/card/ListCard.tsx +++ b/week6/homework/src/pages/movieList/components/card/ListCard.tsx @@ -1,7 +1,7 @@ interface ListCardProps { title: string; description: string; - imageUrl: string; + imageUrl: string | null; releaseDate: string; } @@ -12,16 +12,22 @@ const ListCard = ({ releaseDate, }: ListCardProps) => { return ( -
+
- {title} + {imageUrl ? ( + {title} + ) : ( +
+ 포스터 없음 +
+ )}
-

{title}

+

{title}

{releaseDate}

{description}

From 14d3efbf973d1e4e2456e57df5012ce77229713e Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 02:54:38 +0900 Subject: [PATCH 17/48] =?UTF-8?q?fix:=20cors=20=EC=97=90=EB=9F=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/shared/apis/axiosInstance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/week6/homework/src/shared/apis/axiosInstance.ts b/week6/homework/src/shared/apis/axiosInstance.ts index c91763a..5c9c3b7 100644 --- a/week6/homework/src/shared/apis/axiosInstance.ts +++ b/week6/homework/src/shared/apis/axiosInstance.ts @@ -13,7 +13,7 @@ const axiosInstance = axios.create({ headers: { "Content-Type": "application/json", }, - withCredentials: true, + // withCredentials: true, }); axiosInstance.interceptors.request.use((config) => { From 7cbd0d6d49c655e1806a1478726904d05c99ecf8 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 02:55:22 +0900 Subject: [PATCH 18/48] =?UTF-8?q?feat:=20tmdb=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20url=20=EB=B3=80=EA=B2=BD=20=EC=9C=A0=ED=8B=B8=20?= =?UTF-8?q?=ED=95=A8=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/shared/utils/getTmdbImageUrl.ts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 week6/homework/src/shared/utils/getTmdbImageUrl.ts diff --git a/week6/homework/src/shared/utils/getTmdbImageUrl.ts b/week6/homework/src/shared/utils/getTmdbImageUrl.ts new file mode 100644 index 0000000..5f394ba --- /dev/null +++ b/week6/homework/src/shared/utils/getTmdbImageUrl.ts @@ -0,0 +1,5 @@ +export const getImageUrl = (path: string | null, size = 400) => { + if (!path) return null; + + return `https://image.tmdb.org/t/p/w${size}${path}`; +}; From 7c56cd0cc51c6765c12a3e4cff5ce850e1bc1a5d Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 02:57:38 +0900 Subject: [PATCH 19/48] =?UTF-8?q?chore:=20=EC=BF=BC=EB=A6=AC=ED=82=A4=20?= =?UTF-8?q?=EC=83=81=EC=88=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/shared/constants/queryKeys.ts | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 week6/homework/src/shared/constants/queryKeys.ts diff --git a/week6/homework/src/shared/constants/queryKeys.ts b/week6/homework/src/shared/constants/queryKeys.ts new file mode 100644 index 0000000..4b63402 --- /dev/null +++ b/week6/homework/src/shared/constants/queryKeys.ts @@ -0,0 +1,7 @@ +export const QUERY_KEY = { + MOVIE_LIST: ["movieList"] as const, + MOVIE_DETAIL: (movieId: number) => ["movieDetail", movieId] as const, + GUEST_SESSION: ["guestSession"] as const, + RATED_MOVIES: (guestSessionId: string) => + ["ratedMovies", guestSessionId] as const, +} as const; From 59ce5b9a7bc6985e10a4fa20526b92ff54d310ff Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 03:00:20 +0900 Subject: [PATCH 20/48] =?UTF-8?q?feat:=20=EC=98=81=ED=99=94=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20api=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/movieList/MovieListPage.tsx | 34 +++++++++---------- .../src/pages/movieList/apis/getMovieList.ts | 18 ++++++++++ .../src/pages/movieList/types/list.ts | 24 +++++++++++++ 3 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 week6/homework/src/pages/movieList/apis/getMovieList.ts create mode 100644 week6/homework/src/pages/movieList/types/list.ts diff --git a/week6/homework/src/pages/movieList/MovieListPage.tsx b/week6/homework/src/pages/movieList/MovieListPage.tsx index 841cf7f..2492f05 100644 --- a/week6/homework/src/pages/movieList/MovieListPage.tsx +++ b/week6/homework/src/pages/movieList/MovieListPage.tsx @@ -1,29 +1,27 @@ +import { getImageUrl } from "@utils/getTmdbImageUrl"; +import { useMovieListQuery } from "./apis/getMovieList"; import ListCard from "./components/card/ListCard"; const MovieListPage = () => { + const { data: movieList, isPending, isError } = useMovieListQuery(); + + if (isPending) return
로딩중
; + if (isError) return
에러 발생
; + return (

Movie Explorer

별점 필터링
- - - + {movieList?.results.map((movie) => ( + + ))}
); diff --git a/week6/homework/src/pages/movieList/apis/getMovieList.ts b/week6/homework/src/pages/movieList/apis/getMovieList.ts new file mode 100644 index 0000000..c5601a9 --- /dev/null +++ b/week6/homework/src/pages/movieList/apis/getMovieList.ts @@ -0,0 +1,18 @@ +import { api } from "@apis/https"; +import { useQuery } from "@tanstack/react-query"; +import type { MovieListResponse } from "../types/list"; +import { API_ENDPOINT } from "@constants/apiEndpoints"; +import { QUERY_KEY } from "@constants/queryKeys"; + +export const getMovieList = () => { + return api.get(API_ENDPOINT.LIST, { + language: "ko-KR", + }); +}; + +export const useMovieListQuery = () => { + return useQuery({ + queryKey: QUERY_KEY.MOVIE_LIST, + queryFn: () => getMovieList(), + }); +}; diff --git a/week6/homework/src/pages/movieList/types/list.ts b/week6/homework/src/pages/movieList/types/list.ts new file mode 100644 index 0000000..5375d19 --- /dev/null +++ b/week6/homework/src/pages/movieList/types/list.ts @@ -0,0 +1,24 @@ +export interface MovieListItem { + adult: boolean; + backdrop_path: string | null; + genre_ids: number[]; + id: number; + title: string; + original_language: string; + original_title: string; + overview: string; + popularity: number; + poster_path: string | null; + release_date: string; + softcore: boolean; + video: boolean; + vote_average: number; + vote_count: number; +} + +export interface MovieListResponse { + page: number; + results: MovieListItem[]; + total_pages: number; + total_results: number; +} From 84efa193dbaac800d461fe832c4206129bae3d39 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 03:11:49 +0900 Subject: [PATCH 21/48] =?UTF-8?q?feat:=20=EC=83=81=EC=84=B8=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=9D=B4=EB=8F=99=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/pages/movieList/MovieListPage.tsx | 8 ++++++++ .../src/pages/movieList/components/card/ListCard.tsx | 8 +++++++- week6/homework/src/shared/constants/path.ts | 4 ++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/week6/homework/src/pages/movieList/MovieListPage.tsx b/week6/homework/src/pages/movieList/MovieListPage.tsx index 2492f05..9794064 100644 --- a/week6/homework/src/pages/movieList/MovieListPage.tsx +++ b/week6/homework/src/pages/movieList/MovieListPage.tsx @@ -1,13 +1,20 @@ import { getImageUrl } from "@utils/getTmdbImageUrl"; import { useMovieListQuery } from "./apis/getMovieList"; import ListCard from "./components/card/ListCard"; +import { useNavigate } from "react-router-dom"; +import { ROUTE_PATH } from "@constants/path"; const MovieListPage = () => { + const navigate = useNavigate(); const { data: movieList, isPending, isError } = useMovieListQuery(); if (isPending) return
로딩중
; if (isError) return
에러 발생
; + const handleCardClick = (movieId: number) => { + navigate(ROUTE_PATH.movieDetail(movieId)); + }; + return (

Movie Explorer

@@ -20,6 +27,7 @@ const MovieListPage = () => { description={movie.overview} imageUrl={getImageUrl(movie.poster_path)} releaseDate={movie.release_date} + onClick={() => handleCardClick(movie.id)} /> ))}
diff --git a/week6/homework/src/pages/movieList/components/card/ListCard.tsx b/week6/homework/src/pages/movieList/components/card/ListCard.tsx index 00297cf..8799cfe 100644 --- a/week6/homework/src/pages/movieList/components/card/ListCard.tsx +++ b/week6/homework/src/pages/movieList/components/card/ListCard.tsx @@ -3,6 +3,7 @@ interface ListCardProps { description: string; imageUrl: string | null; releaseDate: string; + onClick?: () => void; } const ListCard = ({ @@ -10,9 +11,14 @@ const ListCard = ({ description, imageUrl, releaseDate, + onClick, }: ListCardProps) => { return ( -
+
{imageUrl ? ( `/movie/${id}`, +} as const; From e20d4f8aedf3c4463431ad7ca4ce1dd0725a82fb Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 03:14:26 +0900 Subject: [PATCH 22/48] =?UTF-8?q?style:=20=EB=B0=B0=EA=B2=BD=EC=83=89=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/styles/index.css | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/week6/homework/src/styles/index.css b/week6/homework/src/styles/index.css index 2d251e3..d641a9f 100644 --- a/week6/homework/src/styles/index.css +++ b/week6/homework/src/styles/index.css @@ -4,7 +4,6 @@ @theme { --font-sans: 'Pretendard Variable', Pretendard, system-ui, sans-serif; - --color-background-muted: #eceae7; --color-surface-soft: #f8f7f5; --color-surface-strong: #e7e5e4; @@ -26,7 +25,7 @@ :root { color: black; - background-color: var(--color-background-muted); + background-color: var(--color-surface-soft); font-family: var(--font-sans); } @@ -36,7 +35,7 @@ } body { - @apply bg-background-muted text-text antialiased; + @apply bg-surface-soft text-text antialiased; min-height: 100vh; } From 8f4293fe42d18f6b45220d07453e721d790cace2 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 03:32:36 +0900 Subject: [PATCH 23/48] =?UTF-8?q?chore:=20react=20icon=20=EC=84=A4?= =?UTF-8?q?=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/package.json | 1 + week6/homework/pnpm-lock.yaml | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/week6/homework/package.json b/week6/homework/package.json index 4293cbf..ab05bf5 100644 --- a/week6/homework/package.json +++ b/week6/homework/package.json @@ -15,6 +15,7 @@ "axios": "^1.16.1", "react": "^19.2.6", "react-dom": "^19.2.6", + "react-icons": "^5.6.0", "react-router": "^7.16.0", "react-router-dom": "^7.16.0" }, diff --git a/week6/homework/pnpm-lock.yaml b/week6/homework/pnpm-lock.yaml index 02b7fa1..3f8b6ab 100644 --- a/week6/homework/pnpm-lock.yaml +++ b/week6/homework/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: react-dom: specifier: ^19.2.6 version: 19.2.6(react@19.2.6) + react-icons: + specifier: ^5.6.0 + version: 5.6.0(react@19.2.6) react-router: specifier: ^7.16.0 version: 7.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -1021,6 +1024,11 @@ packages: peerDependencies: react: ^19.2.6 + react-icons@5.6.0: + resolution: {integrity: sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==} + peerDependencies: + react: '*' + react-router-dom@7.16.0: resolution: {integrity: sha512-kMUAbimWB5FVbF4Bce4bJsiKJWLIUHq/mEG8+CFDnCSgltptBiG5nguducmsJeGKytlCvQud9Qhzpn49iduTlA==} engines: {node: '>=20.0.0'} @@ -2086,6 +2094,10 @@ snapshots: react: 19.2.6 scheduler: 0.27.0 + react-icons@5.6.0(react@19.2.6): + dependencies: + react: 19.2.6 + react-router-dom@7.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: react: 19.2.6 From 38ea2daae2c04e423680fc88543025fbca94d8c1 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 03:47:55 +0900 Subject: [PATCH 24/48] =?UTF-8?q?chore:=20=EC=83=81=EC=84=B8=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EB=AA=A9=EB=8D=B0=EC=9D=B4=ED=84=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/movieDetail/constants/labels.ts | 15 ++++++ .../src/pages/movieDetail/mocks/detailMock.ts | 53 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 week6/homework/src/pages/movieDetail/constants/labels.ts create mode 100644 week6/homework/src/pages/movieDetail/mocks/detailMock.ts diff --git a/week6/homework/src/pages/movieDetail/constants/labels.ts b/week6/homework/src/pages/movieDetail/constants/labels.ts new file mode 100644 index 0000000..5464081 --- /dev/null +++ b/week6/homework/src/pages/movieDetail/constants/labels.ts @@ -0,0 +1,15 @@ +export const DETAIL_STAT_LABEL = { + VOTE_AVERAGE: "평점", + VOTE_COUNT: "투표 수", + RUNTIME: "상영 시간", + STATUS: "상태", +} as const; + +export const BASIC_INFO_LABEL = { + ORIGINAL_TITLE: "원제", + ORIGINAL_LANGUAGE: "원어", + PRODUCTION_COUNTRY: "제작 국가", + SPOKEN_LANGUAGE: "사용 언어", + BUDGET: "예산", + REVENUE: "수익", +} as const; diff --git a/week6/homework/src/pages/movieDetail/mocks/detailMock.ts b/week6/homework/src/pages/movieDetail/mocks/detailMock.ts new file mode 100644 index 0000000..98450b3 --- /dev/null +++ b/week6/homework/src/pages/movieDetail/mocks/detailMock.ts @@ -0,0 +1,53 @@ +import { BASIC_INFO_LABEL, DETAIL_STAT_LABEL } from "../constants/labels"; + +export const mockMovieDetail = { + title: "슈퍼 마리오 갤럭시", + originalTitle: "The Super Mario Galaxy Movie", + releaseDate: "2026.04.01", + overview: + "브루클린의 배관공에서 세계를 구한 히어로로 레벨업한 형제 '마리오'와 '루이지'는 모래 왕국에서 임무를 수행하던 중, 길을 잃은 '요시'를 구출하며 특별한 우정을 쌓게 된다. 한편, 무너진 '쿠파' 가문의 명예를 되찾기 위해 악의 왕자 '쿠파주니어'는 은하계의 수호자이자 치코들의 엄마 '로젤리나'를 납치하고, 버섯 왕국에 갇힌 아빠 '쿠파'를 되찾기 위해 행왕국을 습격한다. 다시 찾아온 위기 속에서 마리오와 루이지, 피치, 키노피오 그리고 새로 합류한 요시까지 로젤리나도 구하고, 쿠파주니어의 비밀한 계획을 막기 위해 넓은 갤럭시로 뛰어들게 되는데...", + genres: ["가족", "코미디", "모험", "판타지", "애니메이션"], + posterUrl: "https://image.tmdb.org/t/p/w500/8g7H1GQjWJY9mG9mM7i3GvJgP6x.jpg", + backdropUrl: + "https://image.tmdb.org/t/p/w1280/u53UYu5XG2hNgWGvs3xGhAVzypl.jpg", + voteAverage: 7.6, + voteCount: "1,378", + runtime: "1시간 39분", + status: "Released", + originalLanguage: "en", + countries: "Japan, United States of America", + spokenLanguages: "English", + budget: "US$110,000,000", + revenue: "US$967,144,200", +}; + +export const detailStats = [ + { + label: DETAIL_STAT_LABEL.VOTE_AVERAGE, + value: `${mockMovieDetail.voteAverage} / 10`, + }, + { label: DETAIL_STAT_LABEL.VOTE_COUNT, value: mockMovieDetail.voteCount }, + { label: DETAIL_STAT_LABEL.RUNTIME, value: mockMovieDetail.runtime }, + { label: DETAIL_STAT_LABEL.STATUS, value: mockMovieDetail.status }, +]; + +export const basicInfo = [ + { + label: BASIC_INFO_LABEL.ORIGINAL_TITLE, + value: mockMovieDetail.originalTitle, + }, + { + label: BASIC_INFO_LABEL.ORIGINAL_LANGUAGE, + value: mockMovieDetail.originalLanguage, + }, + { + label: BASIC_INFO_LABEL.PRODUCTION_COUNTRY, + value: mockMovieDetail.countries, + }, + { + label: BASIC_INFO_LABEL.SPOKEN_LANGUAGE, + value: mockMovieDetail.spokenLanguages, + }, + { label: BASIC_INFO_LABEL.BUDGET, value: mockMovieDetail.budget }, + { label: BASIC_INFO_LABEL.REVENUE, value: mockMovieDetail.revenue }, +]; From 45a2ae185f264ec659f91cfe69a140efa87a5ad6 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 03:48:05 +0900 Subject: [PATCH 25/48] =?UTF-8?q?feat:=20=EB=B2=84=ED=8A=BC=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../movieDetail/components/button/Button.tsx | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 week6/homework/src/pages/movieDetail/components/button/Button.tsx diff --git a/week6/homework/src/pages/movieDetail/components/button/Button.tsx b/week6/homework/src/pages/movieDetail/components/button/Button.tsx new file mode 100644 index 0000000..383963b --- /dev/null +++ b/week6/homework/src/pages/movieDetail/components/button/Button.tsx @@ -0,0 +1,32 @@ +import type { ButtonHTMLAttributes, ReactNode } from "react"; + +interface ButtonProps extends ButtonHTMLAttributes { + children: ReactNode; + variant?: "primary" | "secondary"; +} + +const buttonClassName = { + primary: "bg-text text-text-inverse hover:bg-accent-strong", + secondary: + "border border-border bg-white text-text-soft hover:border-border-strong hover:text-text", +} as const; + +const Button = ({ + children, + className = "", + type = "button", + variant = "primary", + ...props +}: ButtonProps) => { + return ( + + ); +}; + +export default Button; From da977d2bb3e1462a740bb7d86114b37505eb81c1 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 03:51:03 +0900 Subject: [PATCH 26/48] =?UTF-8?q?feat:=20=ED=86=B5=EA=B3=84=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/card/DetailStatCard.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 week6/homework/src/pages/movieDetail/components/card/DetailStatCard.tsx diff --git a/week6/homework/src/pages/movieDetail/components/card/DetailStatCard.tsx b/week6/homework/src/pages/movieDetail/components/card/DetailStatCard.tsx new file mode 100644 index 0000000..0486387 --- /dev/null +++ b/week6/homework/src/pages/movieDetail/components/card/DetailStatCard.tsx @@ -0,0 +1,15 @@ +interface DetailStatCardProps { + label: string; + value: string; +} + +const DetailStatCard = ({ label, value }: DetailStatCardProps) => { + return ( +
+

{label}

+

{value}

+
+ ); +}; + +export default DetailStatCard; From a6b0cd514e105f95ea35665ab219ba2b8c440be5 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 03:57:54 +0900 Subject: [PATCH 27/48] =?UTF-8?q?style:=20=ED=97=A4=EB=8D=94=20=EA=B3=B5?= =?UTF-8?q?=ED=86=B5=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/pages/movieList/constants/commonStyles.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 week6/homework/src/pages/movieList/constants/commonStyles.ts diff --git a/week6/homework/src/pages/movieList/constants/commonStyles.ts b/week6/homework/src/pages/movieList/constants/commonStyles.ts new file mode 100644 index 0000000..efd45c5 --- /dev/null +++ b/week6/homework/src/pages/movieList/constants/commonStyles.ts @@ -0,0 +1 @@ +export const sectionTitleClassName = "text-xl font-bold text-text mb-1"; From 0d48747e3d0d929ed7bb16f8ecd7352f27a2026d Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 03:58:10 +0900 Subject: [PATCH 28/48] =?UTF-8?q?feat:=20=EB=B3=84=EC=A0=90=20=EB=82=A8?= =?UTF-8?q?=EA=B8=B0=EA=B8=B0=20=EC=84=B9=EC=85=98=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/section/RatingSection.tsx | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx diff --git a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx new file mode 100644 index 0000000..d39fef7 --- /dev/null +++ b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx @@ -0,0 +1,21 @@ +import { sectionTitleClassName } from "@pages/movieList/constants/commonStyles"; +import Button from "../button/Button"; + +const RatingSection = () => { + return ( +
+

별점 남기기

+

0.5 ~ 10.0

+ +
+ + +
+
+ ); +}; + +export default RatingSection; From 78f85f9dbb1b877c92ef93c328f5c4424e85d235 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 04:04:10 +0900 Subject: [PATCH 29/48] =?UTF-8?q?feat:=20=EA=B8=B0=EB=B3=B8=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=84=B9=EC=85=98=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/section/BasicInfoSection.tsx | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 week6/homework/src/pages/movieDetail/components/section/BasicInfoSection.tsx diff --git a/week6/homework/src/pages/movieDetail/components/section/BasicInfoSection.tsx b/week6/homework/src/pages/movieDetail/components/section/BasicInfoSection.tsx new file mode 100644 index 0000000..c8fbc2c --- /dev/null +++ b/week6/homework/src/pages/movieDetail/components/section/BasicInfoSection.tsx @@ -0,0 +1,31 @@ +import { sectionTitleClassName } from "@pages/movieList/constants/commonStyles"; + +interface BasicInfoItem { + label: string; + value: string; +} + +interface BasicInfoSectionProps { + items: BasicInfoItem[]; +} + +const BasicInfoSection = ({ items }: BasicInfoSectionProps) => { + return ( +
+

기본 정보

+
+ {items.map((item) => ( +
+

{item.label}

+

{item.value}

+
+ ))} +
+
+ ); +}; + +export default BasicInfoSection; From 27517115345139b4a0affefdfe2073d41b8cc59f Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 04:04:19 +0900 Subject: [PATCH 30/48] =?UTF-8?q?style:=20=EC=A4=91=EB=B3=B5=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/movieDetail/components/card/DetailStatCard.tsx | 4 ++-- .../pages/movieDetail/components/section/RatingSection.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/week6/homework/src/pages/movieDetail/components/card/DetailStatCard.tsx b/week6/homework/src/pages/movieDetail/components/card/DetailStatCard.tsx index 0486387..42d8dfe 100644 --- a/week6/homework/src/pages/movieDetail/components/card/DetailStatCard.tsx +++ b/week6/homework/src/pages/movieDetail/components/card/DetailStatCard.tsx @@ -6,8 +6,8 @@ interface DetailStatCardProps { const DetailStatCard = ({ label, value }: DetailStatCardProps) => { return (
-

{label}

-

{value}

+

{label}

+

{value}

); }; diff --git a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx index d39fef7..e7b1ec3 100644 --- a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx +++ b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx @@ -7,7 +7,7 @@ const RatingSection = () => {

별점 남기기

0.5 ~ 10.0

From afc7feefa363d4e380c28731981620fc5c905dde Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 04:14:59 +0900 Subject: [PATCH 31/48] =?UTF-8?q?feat:=20=EC=83=81=EC=84=B8=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20UI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/movieDetail/MovieDetailPage.tsx | 92 ++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx b/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx index b196867..6d3c774 100644 --- a/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx +++ b/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx @@ -1,5 +1,95 @@ +import { ROUTES } from "@constants/path"; +import { FaArrowLeft } from "react-icons/fa"; +import { useNavigate } from "react-router-dom"; +import BasicInfoSection from "./components/section/BasicInfoSection"; +import DetailStatCard from "./components/card/DetailStatCard"; +import RatingSection from "./components/section/RatingSection"; +import { mockMovieDetail, detailStats, basicInfo } from "./mocks/detailMock"; +import { sectionTitleClassName } from "@pages/movieList/constants/commonStyles"; + const MovieDetailPage = () => { - return
MovieDetailPage
; + const navigate = useNavigate(); + + const handleGoBack = () => { + navigate(ROUTES.MOVIE_LIST); + }; + + return ( +
+ + +
+
+ {`${mockMovieDetail.title} +
+
+ +
+
+ {`${mockMovieDetail.title} +
+ +
+
+

+ {mockMovieDetail.releaseDate} +

+

+ {mockMovieDetail.title} +

+
+ +
+ {mockMovieDetail.genres.map((genre) => ( + + {genre} + + ))} +
+ +
+ {detailStats.map((item) => ( + + ))} +
+
+
+
+ +
+

줄거리

+

{mockMovieDetail.overview}

+
+ +
+ + +
+
+ ); }; export default MovieDetailPage; From 135782a8ee08137219ac2ff908539e715063e69f Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 04:20:53 +0900 Subject: [PATCH 32/48] =?UTF-8?q?chore:=20input=20=ED=83=80=EC=9E=85=20num?= =?UTF-8?q?ber=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/movieDetail/components/section/RatingSection.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx index e7b1ec3..c2adfb5 100644 --- a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx +++ b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx @@ -8,7 +8,10 @@ const RatingSection = () => {

0.5 ~ 10.0

From fba981fd7a367ae2c38b0fb8ca9767f1c64702a9 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 04:30:58 +0900 Subject: [PATCH 33/48] =?UTF-8?q?feat:=20=EC=83=81=EC=84=B8=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20api=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/movieDetail/MovieDetailPage.tsx | 46 +++++++++----- .../pages/movieDetail/apis/getMovieDetail.ts | 19 ++++++ .../src/pages/movieDetail/mocks/detailMock.ts | 53 ---------------- .../src/pages/movieDetail/types/detail.ts | 59 ++++++++++++++++++ .../utils/movieDetailViewMapper.ts | 62 +++++++++++++++++++ 5 files changed, 169 insertions(+), 70 deletions(-) create mode 100644 week6/homework/src/pages/movieDetail/apis/getMovieDetail.ts delete mode 100644 week6/homework/src/pages/movieDetail/mocks/detailMock.ts create mode 100644 week6/homework/src/pages/movieDetail/types/detail.ts create mode 100644 week6/homework/src/pages/movieDetail/utils/movieDetailViewMapper.ts diff --git a/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx b/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx index 6d3c774..6ddc2da 100644 --- a/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx +++ b/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx @@ -1,14 +1,28 @@ import { ROUTES } from "@constants/path"; +import { getImageUrl } from "@utils/getTmdbImageUrl"; import { FaArrowLeft } from "react-icons/fa"; -import { useNavigate } from "react-router-dom"; +import { useNavigate, useParams } from "react-router-dom"; import BasicInfoSection from "./components/section/BasicInfoSection"; import DetailStatCard from "./components/card/DetailStatCard"; import RatingSection from "./components/section/RatingSection"; -import { mockMovieDetail, detailStats, basicInfo } from "./mocks/detailMock"; import { sectionTitleClassName } from "@pages/movieList/constants/commonStyles"; +import { useMovieDetailQuery } from "./apis/getMovieDetail"; +import { getMovieDetailViewData } from "./utils/movieDetailViewMapper"; const MovieDetailPage = () => { const navigate = useNavigate(); + const { id } = useParams(); + const movieId = Number(id); + + const { + data: movieDetail, + isPending, + isError, + } = useMovieDetailQuery(movieId); + + if (isPending) return
로딩중
; + if (isError || !movieDetail) return
에러 발생
; + const { detailStats, basicInfo } = getMovieDetailViewData(movieDetail); const handleGoBack = () => { navigate(ROUTES.MOVIE_LIST); @@ -27,41 +41,39 @@ const MovieDetailPage = () => {
-
+
{`${mockMovieDetail.title}
-
+
{`${mockMovieDetail.title}

- {mockMovieDetail.releaseDate} + {movieDetail.release_date}

-

- {mockMovieDetail.title} -

+

{movieDetail.title}

- {mockMovieDetail.genres.map((genre) => ( + {movieDetail.genres.map((genre) => ( - {genre} + {genre.name} ))}
@@ -81,7 +93,7 @@ const MovieDetailPage = () => {

줄거리

-

{mockMovieDetail.overview}

+

{movieDetail.overview}

diff --git a/week6/homework/src/pages/movieDetail/apis/getMovieDetail.ts b/week6/homework/src/pages/movieDetail/apis/getMovieDetail.ts new file mode 100644 index 0000000..6aee087 --- /dev/null +++ b/week6/homework/src/pages/movieDetail/apis/getMovieDetail.ts @@ -0,0 +1,19 @@ +import { api } from "@apis/https"; +import { useQuery } from "@tanstack/react-query"; +import type { MovieDetailResponse } from "../types/detail"; +import { API_ENDPOINT } from "@constants/apiEndpoints"; +import { QUERY_KEY } from "@constants/queryKeys"; + +export const getMovieDetail = (id: number) => { + return api.get(API_ENDPOINT.DETAIL(id), { + language: "ko-KR", + }); +}; + +export const useMovieDetailQuery = (id: number) => { + return useQuery({ + queryKey: QUERY_KEY.MOVIE_DETAIL(id), + queryFn: () => getMovieDetail(id), + enabled: Number.isFinite(id), + }); +}; diff --git a/week6/homework/src/pages/movieDetail/mocks/detailMock.ts b/week6/homework/src/pages/movieDetail/mocks/detailMock.ts deleted file mode 100644 index 98450b3..0000000 --- a/week6/homework/src/pages/movieDetail/mocks/detailMock.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { BASIC_INFO_LABEL, DETAIL_STAT_LABEL } from "../constants/labels"; - -export const mockMovieDetail = { - title: "슈퍼 마리오 갤럭시", - originalTitle: "The Super Mario Galaxy Movie", - releaseDate: "2026.04.01", - overview: - "브루클린의 배관공에서 세계를 구한 히어로로 레벨업한 형제 '마리오'와 '루이지'는 모래 왕국에서 임무를 수행하던 중, 길을 잃은 '요시'를 구출하며 특별한 우정을 쌓게 된다. 한편, 무너진 '쿠파' 가문의 명예를 되찾기 위해 악의 왕자 '쿠파주니어'는 은하계의 수호자이자 치코들의 엄마 '로젤리나'를 납치하고, 버섯 왕국에 갇힌 아빠 '쿠파'를 되찾기 위해 행왕국을 습격한다. 다시 찾아온 위기 속에서 마리오와 루이지, 피치, 키노피오 그리고 새로 합류한 요시까지 로젤리나도 구하고, 쿠파주니어의 비밀한 계획을 막기 위해 넓은 갤럭시로 뛰어들게 되는데...", - genres: ["가족", "코미디", "모험", "판타지", "애니메이션"], - posterUrl: "https://image.tmdb.org/t/p/w500/8g7H1GQjWJY9mG9mM7i3GvJgP6x.jpg", - backdropUrl: - "https://image.tmdb.org/t/p/w1280/u53UYu5XG2hNgWGvs3xGhAVzypl.jpg", - voteAverage: 7.6, - voteCount: "1,378", - runtime: "1시간 39분", - status: "Released", - originalLanguage: "en", - countries: "Japan, United States of America", - spokenLanguages: "English", - budget: "US$110,000,000", - revenue: "US$967,144,200", -}; - -export const detailStats = [ - { - label: DETAIL_STAT_LABEL.VOTE_AVERAGE, - value: `${mockMovieDetail.voteAverage} / 10`, - }, - { label: DETAIL_STAT_LABEL.VOTE_COUNT, value: mockMovieDetail.voteCount }, - { label: DETAIL_STAT_LABEL.RUNTIME, value: mockMovieDetail.runtime }, - { label: DETAIL_STAT_LABEL.STATUS, value: mockMovieDetail.status }, -]; - -export const basicInfo = [ - { - label: BASIC_INFO_LABEL.ORIGINAL_TITLE, - value: mockMovieDetail.originalTitle, - }, - { - label: BASIC_INFO_LABEL.ORIGINAL_LANGUAGE, - value: mockMovieDetail.originalLanguage, - }, - { - label: BASIC_INFO_LABEL.PRODUCTION_COUNTRY, - value: mockMovieDetail.countries, - }, - { - label: BASIC_INFO_LABEL.SPOKEN_LANGUAGE, - value: mockMovieDetail.spokenLanguages, - }, - { label: BASIC_INFO_LABEL.BUDGET, value: mockMovieDetail.budget }, - { label: BASIC_INFO_LABEL.REVENUE, value: mockMovieDetail.revenue }, -]; diff --git a/week6/homework/src/pages/movieDetail/types/detail.ts b/week6/homework/src/pages/movieDetail/types/detail.ts new file mode 100644 index 0000000..d33dad3 --- /dev/null +++ b/week6/homework/src/pages/movieDetail/types/detail.ts @@ -0,0 +1,59 @@ +export interface MovieGenre { + id: number; + name: string; +} + +export interface MovieCollection { + id: number; + name: string; + poster_path: string | null; + backdrop_path: string | null; +} + +export interface ProductionCompany { + id: number; + logo_path: string | null; + name: string; + origin_country: string; +} + +export interface ProductionCountry { + iso_3166_1: string; + name: string; +} + +export interface SpokenLanguage { + english_name: string; + iso_639_1: string; + name: string; +} + +export interface MovieDetailResponse { + adult: boolean; + backdrop_path: string | null; + belongs_to_collection: MovieCollection | null; + budget: number; + genres: MovieGenre[]; + homepage: string; + id: number; + imdb_id: string | null; + origin_country: string[]; + original_language: string; + original_title: string; + overview: string; + popularity: number; + poster_path: string | null; + production_companies: ProductionCompany[]; + production_countries: ProductionCountry[]; + release_date: string; + revenue: number; + runtime: number; + softcore: boolean; + spoken_languages: SpokenLanguage[]; + status: string; + tagline: string; + title: string; + video: boolean; + vote_average: number; + vote_count: number; +} diff --git a/week6/homework/src/pages/movieDetail/utils/movieDetailViewMapper.ts b/week6/homework/src/pages/movieDetail/utils/movieDetailViewMapper.ts new file mode 100644 index 0000000..cba7381 --- /dev/null +++ b/week6/homework/src/pages/movieDetail/utils/movieDetailViewMapper.ts @@ -0,0 +1,62 @@ +import { BASIC_INFO_LABEL, DETAIL_STAT_LABEL } from "../constants/labels"; +import type { MovieDetailResponse } from "../types/detail"; + +// 응답을 각 라벨에 맞게 가공 +export const getMovieDetailViewData = (movieDetail: MovieDetailResponse) => { + const detailStats = [ + { + label: DETAIL_STAT_LABEL.VOTE_AVERAGE, + value: `${movieDetail.vote_average.toFixed(1)} / 10`, + }, + { + label: DETAIL_STAT_LABEL.VOTE_COUNT, + value: movieDetail.vote_count.toLocaleString("ko-KR"), + }, + { + label: DETAIL_STAT_LABEL.RUNTIME, + value: `${Math.floor(movieDetail.runtime / 60)}시간 ${movieDetail.runtime % 60}분`, + }, + { + label: DETAIL_STAT_LABEL.STATUS, + value: movieDetail.status, + }, + ]; + + const basicInfo = [ + { + label: BASIC_INFO_LABEL.ORIGINAL_TITLE, + value: movieDetail.original_title, + }, + { + label: BASIC_INFO_LABEL.ORIGINAL_LANGUAGE, + value: movieDetail.original_language, + }, + { + label: BASIC_INFO_LABEL.PRODUCTION_COUNTRY, + value: + movieDetail.production_countries + .map((country) => country.name) + .join(", ") || "-", + }, + { + label: BASIC_INFO_LABEL.SPOKEN_LANGUAGE, + value: + movieDetail.spoken_languages + .map((language) => language.english_name) + .join(", ") || "-", + }, + { + label: BASIC_INFO_LABEL.BUDGET, + value: `US$${movieDetail.budget.toLocaleString("en-US")}`, + }, + { + label: BASIC_INFO_LABEL.REVENUE, + value: `US$${movieDetail.revenue.toLocaleString("en-US")}`, + }, + ]; + + return { + detailStats, + basicInfo, + }; +}; From ca51013822e554a4e0996a690679fbe11e75ff94 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 18:00:06 +0900 Subject: [PATCH 34/48] =?UTF-8?q?feat:=20=EB=93=9C=EB=A1=AD=EB=8B=A4?= =?UTF-8?q?=EC=9A=B4=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/movieList/MovieListPage.tsx | 11 ++++++- .../components/ratingFilter/RatingFilter.tsx | 32 +++++++++++++++++++ .../pages/movieList/constants/ratingLabels.ts | 13 ++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 week6/homework/src/pages/movieList/components/ratingFilter/RatingFilter.tsx create mode 100644 week6/homework/src/pages/movieList/constants/ratingLabels.ts diff --git a/week6/homework/src/pages/movieList/MovieListPage.tsx b/week6/homework/src/pages/movieList/MovieListPage.tsx index 9794064..8892fe4 100644 --- a/week6/homework/src/pages/movieList/MovieListPage.tsx +++ b/week6/homework/src/pages/movieList/MovieListPage.tsx @@ -3,14 +3,21 @@ import { useMovieListQuery } from "./apis/getMovieList"; import ListCard from "./components/card/ListCard"; import { useNavigate } from "react-router-dom"; import { ROUTE_PATH } from "@constants/path"; +import RatingFilter from "./components/ratingFilter/RatingFilter"; +import { useState } from "react"; const MovieListPage = () => { + const [selectedRating, setSelectedRating] = useState("all"); const navigate = useNavigate(); const { data: movieList, isPending, isError } = useMovieListQuery(); if (isPending) return
로딩중
; if (isError) return
에러 발생
; + const handleRatingChange = (value: string) => { + setSelectedRating(value); + }; + const handleCardClick = (movieId: number) => { navigate(ROUTE_PATH.movieDetail(movieId)); }; @@ -18,7 +25,9 @@ const MovieListPage = () => { return (

Movie Explorer

-
별점 필터링
+
+ +
{movieList?.results.map((movie) => ( void; +} + +const RatingFilter = ({ value = "all", onChange }: RatingFilterProps) => { + return ( +
+ + +
+ ); +}; + +export default RatingFilter; diff --git a/week6/homework/src/pages/movieList/constants/ratingLabels.ts b/week6/homework/src/pages/movieList/constants/ratingLabels.ts new file mode 100644 index 0000000..0b4d325 --- /dev/null +++ b/week6/homework/src/pages/movieList/constants/ratingLabels.ts @@ -0,0 +1,13 @@ +export const ratingOptions = [ + { label: "전체 별점", value: "all" }, + { label: "1점대", value: "1" }, + { label: "2점대", value: "2" }, + { label: "3점대", value: "3" }, + { label: "4점대", value: "4" }, + { label: "5점대", value: "5" }, + { label: "6점대", value: "6" }, + { label: "7점대", value: "7" }, + { label: "8점대", value: "8" }, + { label: "9점대", value: "9" }, + { label: "10점대", value: "10" }, +]; From 2538649ed14ef7b068fa76a75dafc87e5973e686 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 18:12:21 +0900 Subject: [PATCH 35/48] =?UTF-8?q?feat:=20=ED=95=84=ED=84=B0=EB=A7=81=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/movieList/MovieListPage.tsx | 6 +++++- .../src/pages/movieList/apis/getMovieList.ts | 21 ++++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/week6/homework/src/pages/movieList/MovieListPage.tsx b/week6/homework/src/pages/movieList/MovieListPage.tsx index 8892fe4..9062cd8 100644 --- a/week6/homework/src/pages/movieList/MovieListPage.tsx +++ b/week6/homework/src/pages/movieList/MovieListPage.tsx @@ -9,7 +9,11 @@ import { useState } from "react"; const MovieListPage = () => { const [selectedRating, setSelectedRating] = useState("all"); const navigate = useNavigate(); - const { data: movieList, isPending, isError } = useMovieListQuery(); + const { + data: movieList, + isPending, + isError, + } = useMovieListQuery(selectedRating); if (isPending) return
로딩중
; if (isError) return
에러 발생
; diff --git a/week6/homework/src/pages/movieList/apis/getMovieList.ts b/week6/homework/src/pages/movieList/apis/getMovieList.ts index c5601a9..f87f3d0 100644 --- a/week6/homework/src/pages/movieList/apis/getMovieList.ts +++ b/week6/homework/src/pages/movieList/apis/getMovieList.ts @@ -3,16 +3,23 @@ import { useQuery } from "@tanstack/react-query"; import type { MovieListResponse } from "../types/list"; import { API_ENDPOINT } from "@constants/apiEndpoints"; import { QUERY_KEY } from "@constants/queryKeys"; +import type { RatingFilterValue } from "../components/ratingFilter/RatingFilter"; -export const getMovieList = () => { - return api.get(API_ENDPOINT.LIST, { - language: "ko-KR", - }); +export const getMovieList = (rating: RatingFilterValue) => { + const params = + rating === "all" + ? { language: "ko-KR" } + : { + language: "ko-KR", + "vote_average.gte": Number(rating), + "vote_average.lte": Number(rating) === 10 ? 10 : Number(rating) + 0.9, + }; + return api.get(API_ENDPOINT.LIST, params); }; -export const useMovieListQuery = () => { +export const useMovieListQuery = (rating: RatingFilterValue) => { return useQuery({ - queryKey: QUERY_KEY.MOVIE_LIST, - queryFn: () => getMovieList(), + queryKey: [...QUERY_KEY.MOVIE_LIST, rating], + queryFn: () => getMovieList(rating), }); }; From ed78886c14cb2ebd1ff7302f39b73c04b072b5a3 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 19:01:48 +0900 Subject: [PATCH 36/48] =?UTF-8?q?feat:=20session=20id=20=EB=B0=9C=EA=B8=89?= =?UTF-8?q?=20=EB=B0=8F=20=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/shared/apis/getAuth.ts | 30 +++++++++++++++++++++++ week6/homework/src/shared/types/auth.ts | 5 ++++ 2 files changed, 35 insertions(+) create mode 100644 week6/homework/src/shared/apis/getAuth.ts create mode 100644 week6/homework/src/shared/types/auth.ts diff --git a/week6/homework/src/shared/apis/getAuth.ts b/week6/homework/src/shared/apis/getAuth.ts new file mode 100644 index 0000000..cd4f132 --- /dev/null +++ b/week6/homework/src/shared/apis/getAuth.ts @@ -0,0 +1,30 @@ +import { API_ENDPOINT } from "@constants/apiEndpoints"; +import type { GuestSessionResponse } from "@shared/types/auth"; +import { api } from "./https"; +import { useQuery } from "@tanstack/react-query"; +import { QUERY_KEY } from "@constants/queryKeys"; + +const GUEST_SESSION_KEY = "guest_session_id"; + +// 게스트 세션 ID가 없을 경우 발급 받아 저장 +export const getGuestSession = () => { + return api.get(API_ENDPOINT.GUEST_ID); +}; + +export const useGuestSessionQuery = () => { + return useQuery({ + queryKey: QUERY_KEY.GUEST_SESSION, + queryFn: async () => { + const storedGuestSessionId = localStorage.getItem(GUEST_SESSION_KEY); + + if (storedGuestSessionId) { + return storedGuestSessionId; + } + + const response = await getGuestSession(); + localStorage.setItem(GUEST_SESSION_KEY, response.guest_session_id); + + return response.guest_session_id; + }, + }); +}; diff --git a/week6/homework/src/shared/types/auth.ts b/week6/homework/src/shared/types/auth.ts new file mode 100644 index 0000000..9ffbbe4 --- /dev/null +++ b/week6/homework/src/shared/types/auth.ts @@ -0,0 +1,5 @@ +export interface GuestSessionResponse { + success: boolean; + guest_session_id: string; + expires_at: string; +} From fee051b69da894c03d98137f88723ce38672f841 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 19:02:40 +0900 Subject: [PATCH 37/48] =?UTF-8?q?chore:=20instance=EC=97=90=EC=84=9C=20id?= =?UTF-8?q?=20=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8A=94=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/shared/apis/axiosInstance.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/week6/homework/src/shared/apis/axiosInstance.ts b/week6/homework/src/shared/apis/axiosInstance.ts index 5c9c3b7..1dc48f6 100644 --- a/week6/homework/src/shared/apis/axiosInstance.ts +++ b/week6/homework/src/shared/apis/axiosInstance.ts @@ -1,11 +1,11 @@ import axios, { AxiosError } from "axios"; const apiKey = import.meta.env.VITE_API_KEY; +const GUEST_SESSION_KEY = "guest_session_id"; -const getGuestSessionId = () => { - if (typeof window === "undefined") return null; - - return window.localStorage.getItem("guest_session_id"); +// 로컬 스토리지에서 게스트 세션 ID 가져오기 +const getStoredGuestSessionId = () => { + return localStorage.getItem(GUEST_SESSION_KEY); }; const axiosInstance = axios.create({ @@ -17,7 +17,7 @@ const axiosInstance = axios.create({ }); axiosInstance.interceptors.request.use((config) => { - const guestSessionId = getGuestSessionId(); + const guestSessionId = getStoredGuestSessionId(); config.params = { ...config.params, From 2dbf7c79c7aa9adfa6433b2eed41d80b406e0696 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 19:26:26 +0900 Subject: [PATCH 38/48] =?UTF-8?q?fix:=20instance=EC=97=90=EC=84=9C=20param?= =?UTF-8?q?s=EC=97=90=20=EC=95=84=EC=9D=B4=EB=94=94=20=EB=B6=99=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/shared/apis/axiosInstance.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/week6/homework/src/shared/apis/axiosInstance.ts b/week6/homework/src/shared/apis/axiosInstance.ts index 1dc48f6..b427d74 100644 --- a/week6/homework/src/shared/apis/axiosInstance.ts +++ b/week6/homework/src/shared/apis/axiosInstance.ts @@ -1,12 +1,6 @@ import axios, { AxiosError } from "axios"; const apiKey = import.meta.env.VITE_API_KEY; -const GUEST_SESSION_KEY = "guest_session_id"; - -// 로컬 스토리지에서 게스트 세션 ID 가져오기 -const getStoredGuestSessionId = () => { - return localStorage.getItem(GUEST_SESSION_KEY); -}; const axiosInstance = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, @@ -17,14 +11,9 @@ const axiosInstance = axios.create({ }); axiosInstance.interceptors.request.use((config) => { - const guestSessionId = getStoredGuestSessionId(); - config.params = { ...config.params, api_key: config.params?.api_key ?? apiKey, - ...(guestSessionId && { - guest_session_id: config.params?.guest_session_id ?? guestSessionId, - }), }; return config; From 0b267e8f1692f0a5dd9911b09b103386cc451b59 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 19:27:19 +0900 Subject: [PATCH 39/48] =?UTF-8?q?feat:=20=EC=98=81=ED=99=94=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EC=A0=95=EB=B3=B4=20=EB=B0=8F=20=EB=B3=84=EC=A0=90?= =?UTF-8?q?=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/movieDetail/MovieDetailPage.tsx | 15 +++++++++++--- .../apis/queries/getMovieDetail.ts | 19 ++++++++++++++++++ .../movieDetail/apis/queries/getRating.ts | 19 ++++++++++++++++++ .../components/section/RatingSection.tsx | 7 ++++++- .../src/pages/movieDetail/types/rating.ts | 20 +++++++++++++++++++ 5 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 week6/homework/src/pages/movieDetail/apis/queries/getMovieDetail.ts create mode 100644 week6/homework/src/pages/movieDetail/apis/queries/getRating.ts create mode 100644 week6/homework/src/pages/movieDetail/types/rating.ts diff --git a/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx b/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx index 6ddc2da..6af487e 100644 --- a/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx +++ b/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx @@ -6,8 +6,10 @@ import BasicInfoSection from "./components/section/BasicInfoSection"; import DetailStatCard from "./components/card/DetailStatCard"; import RatingSection from "./components/section/RatingSection"; import { sectionTitleClassName } from "@pages/movieList/constants/commonStyles"; -import { useMovieDetailQuery } from "./apis/getMovieDetail"; +import { useMovieDetailQuery } from "./apis/queries/getMovieDetail"; import { getMovieDetailViewData } from "./utils/movieDetailViewMapper"; +import { useMovieRatingQuery } from "./apis/queries/getRating"; +import { useGuestSessionQuery } from "@apis/getAuth"; const MovieDetailPage = () => { const navigate = useNavigate(); @@ -18,7 +20,14 @@ const MovieDetailPage = () => { data: movieDetail, isPending, isError, - } = useMovieDetailQuery(movieId); + } = useMovieDetailQuery(movieId); // 영화 상세 정보 조회 + const { data: guestSessionId } = useGuestSessionQuery(); // 게스트 세션 조회 + const { data: ratedMovies } = useMovieRatingQuery(guestSessionId ?? ""); // 사용자의 평점 조회 + + // 영화의 평점이 존재하는지 확인 + const initialRating = ratedMovies?.results.find( + (movie) => movie.id === movieId, + )?.rating; if (isPending) return
로딩중
; if (isError || !movieDetail) return
에러 발생
; @@ -98,7 +107,7 @@ const MovieDetailPage = () => {
- +
); diff --git a/week6/homework/src/pages/movieDetail/apis/queries/getMovieDetail.ts b/week6/homework/src/pages/movieDetail/apis/queries/getMovieDetail.ts new file mode 100644 index 0000000..2d3f745 --- /dev/null +++ b/week6/homework/src/pages/movieDetail/apis/queries/getMovieDetail.ts @@ -0,0 +1,19 @@ +import { api } from "@apis/https"; +import { useQuery } from "@tanstack/react-query"; +import type { MovieDetailResponse } from "../../types/detail"; +import { API_ENDPOINT } from "@constants/apiEndpoints"; +import { QUERY_KEY } from "@constants/queryKeys"; + +export const getMovieDetail = (id: number) => { + return api.get(API_ENDPOINT.DETAIL(id), { + language: "ko-KR", + }); +}; + +export const useMovieDetailQuery = (id: number) => { + return useQuery({ + queryKey: QUERY_KEY.MOVIE_DETAIL(id), + queryFn: () => getMovieDetail(id), + enabled: Number.isFinite(id), + }); +}; diff --git a/week6/homework/src/pages/movieDetail/apis/queries/getRating.ts b/week6/homework/src/pages/movieDetail/apis/queries/getRating.ts new file mode 100644 index 0000000..15e3093 --- /dev/null +++ b/week6/homework/src/pages/movieDetail/apis/queries/getRating.ts @@ -0,0 +1,19 @@ +import { api } from "@apis/https"; +import { useQuery } from "@tanstack/react-query"; +import { API_ENDPOINT } from "@constants/apiEndpoints"; +import { QUERY_KEY } from "@constants/queryKeys"; +import type { RatedMovieListResponse } from "@pages/movieDetail/types/rating"; + +export const getMovieRating = (guestSessionId: string) => { + return api.get( + API_ENDPOINT.RATE_LIST(guestSessionId), + ); +}; + +export const useMovieRatingQuery = (guestSessionId: string) => { + return useQuery({ + queryKey: QUERY_KEY.RATED_MOVIES(guestSessionId), + queryFn: () => getMovieRating(guestSessionId), + enabled: !!guestSessionId, + }); +}; diff --git a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx index c2adfb5..f7e6a6f 100644 --- a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx +++ b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx @@ -1,7 +1,11 @@ import { sectionTitleClassName } from "@pages/movieList/constants/commonStyles"; import Button from "../button/Button"; -const RatingSection = () => { +interface RatingSectionProps { + initialRating?: number; +} + +const RatingSection = ({ initialRating }: RatingSectionProps) => { return (

별점 남기기

@@ -12,6 +16,7 @@ const RatingSection = () => { min="0.5" max="10.0" step="0.5" + defaultValue={initialRating} />
diff --git a/week6/homework/src/pages/movieDetail/types/rating.ts b/week6/homework/src/pages/movieDetail/types/rating.ts new file mode 100644 index 0000000..5c58a6f --- /dev/null +++ b/week6/homework/src/pages/movieDetail/types/rating.ts @@ -0,0 +1,20 @@ +import type { MovieListItem } from "@pages/movieList/types/list"; + +// 별점 가져오기 +export interface RatedMovieItem extends MovieListItem { + rating: number; +} + +export interface RatedMovieListResponse { + page: number; + results: RatedMovieItem[]; + total_pages: number; + total_results: number; +} + +// 별점 등록/삭제 +export interface MovieRatingResponse { + success: boolean; + status_code: number; + status_message: string; +} From 7ff3310ec36b942e84edd6a358849422065f9fe2 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 20:00:43 +0900 Subject: [PATCH 40/48] =?UTF-8?q?feat:=20=EB=B3=84=EC=A0=90=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../movieDetail/apis/mutaion/postRating.ts | 28 +++++++ .../components/section/RatingSection.tsx | 74 +++++++++++++++++-- .../src/pages/movieDetail/types/rating.ts | 13 +++- 3 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 week6/homework/src/pages/movieDetail/apis/mutaion/postRating.ts diff --git a/week6/homework/src/pages/movieDetail/apis/mutaion/postRating.ts b/week6/homework/src/pages/movieDetail/apis/mutaion/postRating.ts new file mode 100644 index 0000000..ae5c707 --- /dev/null +++ b/week6/homework/src/pages/movieDetail/apis/mutaion/postRating.ts @@ -0,0 +1,28 @@ +import { api } from "@apis/https"; +import { useMutation } from "@tanstack/react-query"; +import { API_ENDPOINT } from "@constants/apiEndpoints"; + +import type { + MovieRatingResponse, + PostMovieRatingParams, +} from "@pages/movieDetail/types/rating"; + +export const postMovieRating = ({ + movie_id, + value, + guest_session_id, +}: PostMovieRatingParams) => { + return api.post( + API_ENDPOINT.RATE(movie_id), + { value }, + { + guest_session_id: guest_session_id, + }, + ); +}; + +export const useMovieRatingMutation = () => { + return useMutation({ + mutationFn: postMovieRating, + }); +}; diff --git a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx index f7e6a6f..77f2c06 100644 --- a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx +++ b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx @@ -1,11 +1,65 @@ import { sectionTitleClassName } from "@pages/movieList/constants/commonStyles"; import Button from "../button/Button"; +import { useState } from "react"; +import { useMovieRatingMutation } from "@pages/movieDetail/apis/mutaion/postRating"; interface RatingSectionProps { - initialRating?: number; + movieId: number; + guestSessionId: string; } -const RatingSection = ({ initialRating }: RatingSectionProps) => { +const RatingSection = ({ movieId, guestSessionId }: RatingSectionProps) => { + const [ratingInput, setRatingInput] = useState(""); + const [successMessage, setSuccessMessage] = useState(""); + const [errorMessage, setErrorMessage] = useState(""); + + const { mutate: saveRating, isPending: isSaving } = useMovieRatingMutation(); + + const validateRating = (value: string) => { + const rating = Number(value); + + if (Number.isNaN(rating)) { + return "숫자를 입력해주세요."; + } + + if (rating < 0.5 || rating > 10) { + return "별점은 0.5에서 10.0 사이여야 합니다."; + } + + return null; + }; + + const handleSave = () => { + setSuccessMessage(""); + setErrorMessage(""); + + const validationMessage = validateRating(ratingInput); + + if (validationMessage) { + setErrorMessage(validationMessage); + return; + } + + console.log("Saving rating:", { + movie_id: movieId, + value: Number(ratingInput), + guest_session_id: guestSessionId, + }); + + saveRating( + { + movie_id: movieId, + value: Number(ratingInput), + guest_session_id: guestSessionId, + }, + { + onSuccess: (response) => { + setSuccessMessage(response.status_message); + }, + }, + ); + }; + return (

별점 남기기

@@ -15,13 +69,23 @@ const RatingSection = ({ initialRating }: RatingSectionProps) => { type="number" min="0.5" max="10.0" - step="0.5" - defaultValue={initialRating} + value={ratingInput} + onChange={(e) => setRatingInput(e.target.value)} />
- +
+ + {errorMessage ? ( +

{errorMessage}

+ ) : null} + + {successMessage ? ( +

{successMessage}

+ ) : null}
); }; diff --git a/week6/homework/src/pages/movieDetail/types/rating.ts b/week6/homework/src/pages/movieDetail/types/rating.ts index 5c58a6f..dbfac31 100644 --- a/week6/homework/src/pages/movieDetail/types/rating.ts +++ b/week6/homework/src/pages/movieDetail/types/rating.ts @@ -12,9 +12,20 @@ export interface RatedMovieListResponse { total_results: number; } -// 별점 등록/삭제 +// 별점 등록/삭제 응답 export interface MovieRatingResponse { success: boolean; status_code: number; status_message: string; } + +export interface PostMovieRatingParams { + movie_id: number; + value: number; + guest_session_id: string; +} + +export interface DeleteMovieRatingParams { + movie_id: number; + guest_session_id: string; +} From 3d51a7a39709fe4a7d8e79b11ab6e46f53606629 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 20:07:43 +0900 Subject: [PATCH 41/48] =?UTF-8?q?feat:=20=ED=8F=89=EC=A0=90=20=EA=B0=80?= =?UTF-8?q?=EC=A0=B8=EC=98=A4=EA=B8=B0=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/movieDetail/MovieDetailPage.tsx | 11 +++++++++-- .../components/section/RatingSection.tsx | 17 +++++++++-------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx b/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx index 6af487e..4c1b6f7 100644 --- a/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx +++ b/week6/homework/src/pages/movieDetail/MovieDetailPage.tsx @@ -24,7 +24,7 @@ const MovieDetailPage = () => { const { data: guestSessionId } = useGuestSessionQuery(); // 게스트 세션 조회 const { data: ratedMovies } = useMovieRatingQuery(guestSessionId ?? ""); // 사용자의 평점 조회 - // 영화의 평점이 존재하는지 확인 + // 사용자가 이미 평점을 남긴 영화인지 확인하여 초기값으로 설정 const initialRating = ratedMovies?.results.find( (movie) => movie.id === movieId, )?.rating; @@ -107,7 +107,14 @@ const MovieDetailPage = () => {
- + {guestSessionId ? ( + + ) : null}
); diff --git a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx index 77f2c06..68ee52b 100644 --- a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx +++ b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx @@ -6,10 +6,17 @@ import { useMovieRatingMutation } from "@pages/movieDetail/apis/mutaion/postRati interface RatingSectionProps { movieId: number; guestSessionId: string; + initialRating?: number; } -const RatingSection = ({ movieId, guestSessionId }: RatingSectionProps) => { - const [ratingInput, setRatingInput] = useState(""); +const RatingSection = ({ + movieId, + guestSessionId, + initialRating, +}: RatingSectionProps) => { + const [ratingInput, setRatingInput] = useState( + initialRating !== undefined ? String(initialRating) : "", + ); const [successMessage, setSuccessMessage] = useState(""); const [errorMessage, setErrorMessage] = useState(""); @@ -40,12 +47,6 @@ const RatingSection = ({ movieId, guestSessionId }: RatingSectionProps) => { return; } - console.log("Saving rating:", { - movie_id: movieId, - value: Number(ratingInput), - guest_session_id: guestSessionId, - }); - saveRating( { movie_id: movieId, From 8c5adfaa10b95170934f93205d15a95393602016 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 20:16:22 +0900 Subject: [PATCH 42/48] =?UTF-8?q?refactor:=20errormessage=20=EC=83=81?= =?UTF-8?q?=EC=88=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../homework/src/pages/movieDetail/constants/errorMessage.ts | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 week6/homework/src/pages/movieDetail/constants/errorMessage.ts diff --git a/week6/homework/src/pages/movieDetail/constants/errorMessage.ts b/week6/homework/src/pages/movieDetail/constants/errorMessage.ts new file mode 100644 index 0000000..775b52b --- /dev/null +++ b/week6/homework/src/pages/movieDetail/constants/errorMessage.ts @@ -0,0 +1,4 @@ +export const ERROR_MESSAGE = { + IS_NOT_A_NUMBER: "숫자를 입력해주세요.", + RATING_OUT_OF_BOUNDS: "별점은 0.5에서 10.0 사이여야 합니다.", +}; From 08488c8e5fb264db0101ec201e824230bac2a13f Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 20:16:37 +0900 Subject: [PATCH 43/48] =?UTF-8?q?feat:=20=EB=B3=84=EC=A0=90=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20api=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../movieDetail/apis/mutaion/deleteRating.ts | 27 +++++++++ .../components/section/RatingSection.tsx | 55 ++++++++++++++----- 2 files changed, 68 insertions(+), 14 deletions(-) create mode 100644 week6/homework/src/pages/movieDetail/apis/mutaion/deleteRating.ts diff --git a/week6/homework/src/pages/movieDetail/apis/mutaion/deleteRating.ts b/week6/homework/src/pages/movieDetail/apis/mutaion/deleteRating.ts new file mode 100644 index 0000000..11d965e --- /dev/null +++ b/week6/homework/src/pages/movieDetail/apis/mutaion/deleteRating.ts @@ -0,0 +1,27 @@ +import { api } from "@apis/https"; +import { useMutation } from "@tanstack/react-query"; +import { API_ENDPOINT } from "@constants/apiEndpoints"; + +import type { + DeleteMovieRatingParams, + MovieRatingResponse, +} from "@pages/movieDetail/types/rating"; + +export const deleteMovieRating = ({ + movie_id, + guest_session_id, +}: DeleteMovieRatingParams) => { + return api.delete( + API_ENDPOINT.RATE_DELETE(movie_id), + undefined, + { + guest_session_id: guest_session_id, + }, + ); +}; + +export const useMovieRatingDeleteMutation = () => { + return useMutation({ + mutationFn: deleteMovieRating, + }); +}; diff --git a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx index 68ee52b..35e6fc0 100644 --- a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx +++ b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx @@ -2,6 +2,7 @@ import { sectionTitleClassName } from "@pages/movieList/constants/commonStyles"; import Button from "../button/Button"; import { useState } from "react"; import { useMovieRatingMutation } from "@pages/movieDetail/apis/mutaion/postRating"; +import { ERROR_MESSAGE } from "@pages/movieDetail/constants/errorMessage"; interface RatingSectionProps { movieId: number; @@ -21,21 +22,29 @@ const RatingSection = ({ const [errorMessage, setErrorMessage] = useState(""); const { mutate: saveRating, isPending: isSaving } = useMovieRatingMutation(); + const { mutate: deleteRating, isPending: isDeleting } = + useMovieRatingMutation(); const validateRating = (value: string) => { const rating = Number(value); if (Number.isNaN(rating)) { - return "숫자를 입력해주세요."; + return ERROR_MESSAGE.IS_NOT_A_NUMBER; } if (rating < 0.5 || rating > 10) { - return "별점은 0.5에서 10.0 사이여야 합니다."; + return ERROR_MESSAGE.RATING_OUT_OF_BOUNDS; } return null; }; + const requestData = { + movie_id: movieId, + value: Number(ratingInput), + guest_session_id: guestSessionId, + }; + const handleSave = () => { setSuccessMessage(""); setErrorMessage(""); @@ -47,18 +56,30 @@ const RatingSection = ({ return; } - saveRating( - { - movie_id: movieId, - value: Number(ratingInput), - guest_session_id: guestSessionId, + saveRating(requestData, { + onSuccess: (response) => { + setSuccessMessage(response.status_message); }, - { - onSuccess: (response) => { - setSuccessMessage(response.status_message); - }, + }); + }; + + const handleDelete = () => { + setSuccessMessage(""); + setErrorMessage(""); + + const validationMessage = validateRating(ratingInput); + + if (validationMessage) { + setErrorMessage(validationMessage); + return; + } + + deleteRating(requestData, { + onSuccess: (response) => { + setSuccessMessage(response.status_message); + setRatingInput(""); }, - ); + }); }; return ( @@ -74,10 +95,16 @@ const RatingSection = ({ onChange={(e) => setRatingInput(e.target.value)} />
- - +
{errorMessage ? ( From b9b60f86249745005267f7485e8ee65aeb99c8c4 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 20:24:30 +0900 Subject: [PATCH 44/48] =?UTF-8?q?fix:=20=EC=82=AD=EC=A0=9C=20api=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{mutaion => mutaions}/deleteRating.ts | 0 .../apis/{mutaion => mutaions}/postRating.ts | 0 .../components/section/RatingSection.tsx | 21 ++++++++++++------- 3 files changed, 14 insertions(+), 7 deletions(-) rename week6/homework/src/pages/movieDetail/apis/{mutaion => mutaions}/deleteRating.ts (100%) rename week6/homework/src/pages/movieDetail/apis/{mutaion => mutaions}/postRating.ts (100%) diff --git a/week6/homework/src/pages/movieDetail/apis/mutaion/deleteRating.ts b/week6/homework/src/pages/movieDetail/apis/mutaions/deleteRating.ts similarity index 100% rename from week6/homework/src/pages/movieDetail/apis/mutaion/deleteRating.ts rename to week6/homework/src/pages/movieDetail/apis/mutaions/deleteRating.ts diff --git a/week6/homework/src/pages/movieDetail/apis/mutaion/postRating.ts b/week6/homework/src/pages/movieDetail/apis/mutaions/postRating.ts similarity index 100% rename from week6/homework/src/pages/movieDetail/apis/mutaion/postRating.ts rename to week6/homework/src/pages/movieDetail/apis/mutaions/postRating.ts diff --git a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx index 35e6fc0..c97ba8e 100644 --- a/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx +++ b/week6/homework/src/pages/movieDetail/components/section/RatingSection.tsx @@ -1,8 +1,9 @@ import { sectionTitleClassName } from "@pages/movieList/constants/commonStyles"; import Button from "../button/Button"; import { useState } from "react"; -import { useMovieRatingMutation } from "@pages/movieDetail/apis/mutaion/postRating"; +import { useMovieRatingMutation } from "@pages/movieDetail/apis/mutaions/postRating"; import { ERROR_MESSAGE } from "@pages/movieDetail/constants/errorMessage"; +import { useMovieRatingDeleteMutation } from "@pages/movieDetail/apis/mutaions/deleteRating"; interface RatingSectionProps { movieId: number; @@ -23,7 +24,7 @@ const RatingSection = ({ const { mutate: saveRating, isPending: isSaving } = useMovieRatingMutation(); const { mutate: deleteRating, isPending: isDeleting } = - useMovieRatingMutation(); + useMovieRatingDeleteMutation(); const validateRating = (value: string) => { const rating = Number(value); @@ -74,12 +75,18 @@ const RatingSection = ({ return; } - deleteRating(requestData, { - onSuccess: (response) => { - setSuccessMessage(response.status_message); - setRatingInput(""); + deleteRating( + { + movie_id: movieId, + guest_session_id: guestSessionId, }, - }); + { + onSuccess: (response) => { + setSuccessMessage(response.status_message); + setRatingInput(""); + }, + }, + ); }; return ( From ede9c6914c29b81a395c90966e66ef6b3445818e Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 20:24:52 +0900 Subject: [PATCH 45/48] =?UTF-8?q?remove:=20=EB=B6=88=ED=95=84=EC=9A=94=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/movieDetail/apis/getMovieDetail.ts | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 week6/homework/src/pages/movieDetail/apis/getMovieDetail.ts diff --git a/week6/homework/src/pages/movieDetail/apis/getMovieDetail.ts b/week6/homework/src/pages/movieDetail/apis/getMovieDetail.ts deleted file mode 100644 index 6aee087..0000000 --- a/week6/homework/src/pages/movieDetail/apis/getMovieDetail.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { api } from "@apis/https"; -import { useQuery } from "@tanstack/react-query"; -import type { MovieDetailResponse } from "../types/detail"; -import { API_ENDPOINT } from "@constants/apiEndpoints"; -import { QUERY_KEY } from "@constants/queryKeys"; - -export const getMovieDetail = (id: number) => { - return api.get(API_ENDPOINT.DETAIL(id), { - language: "ko-KR", - }); -}; - -export const useMovieDetailQuery = (id: number) => { - return useQuery({ - queryKey: QUERY_KEY.MOVIE_DETAIL(id), - queryFn: () => getMovieDetail(id), - enabled: Number.isFinite(id), - }); -}; From aa07558abccb0557de5cf4fa4ec9f1951333bfd6 Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 20:45:24 +0900 Subject: [PATCH 46/48] =?UTF-8?q?refactor:=20=EC=96=B8=EC=96=B4=20?= =?UTF-8?q?=EA=B3=B5=ED=86=B5=EC=9C=BC=EB=A1=9C=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/movieDetail/apis/queries/getMovieDetail.ts | 4 +--- week6/homework/src/shared/apis/axiosInstance.ts | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/week6/homework/src/pages/movieDetail/apis/queries/getMovieDetail.ts b/week6/homework/src/pages/movieDetail/apis/queries/getMovieDetail.ts index 2d3f745..541927a 100644 --- a/week6/homework/src/pages/movieDetail/apis/queries/getMovieDetail.ts +++ b/week6/homework/src/pages/movieDetail/apis/queries/getMovieDetail.ts @@ -5,9 +5,7 @@ import { API_ENDPOINT } from "@constants/apiEndpoints"; import { QUERY_KEY } from "@constants/queryKeys"; export const getMovieDetail = (id: number) => { - return api.get(API_ENDPOINT.DETAIL(id), { - language: "ko-KR", - }); + return api.get(API_ENDPOINT.DETAIL(id)); }; export const useMovieDetailQuery = (id: number) => { diff --git a/week6/homework/src/shared/apis/axiosInstance.ts b/week6/homework/src/shared/apis/axiosInstance.ts index b427d74..8225533 100644 --- a/week6/homework/src/shared/apis/axiosInstance.ts +++ b/week6/homework/src/shared/apis/axiosInstance.ts @@ -1,6 +1,7 @@ import axios, { AxiosError } from "axios"; const apiKey = import.meta.env.VITE_API_KEY; +const defaultLanguage = "ko-KR"; const axiosInstance = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, @@ -14,6 +15,7 @@ axiosInstance.interceptors.request.use((config) => { config.params = { ...config.params, api_key: config.params?.api_key ?? apiKey, + language: config.params?.language ?? defaultLanguage, }; return config; From ec6b03df510fd338b4c03e97f96e8dfb7de8abbe Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 20:51:34 +0900 Subject: [PATCH 47/48] =?UTF-8?q?feat:=20=EB=AC=B4=ED=95=9C=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A1=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/movieList/MovieListPage.tsx | 33 +++++++++++++++++-- .../src/pages/movieList/apis/getMovieList.ts | 17 ++++++---- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/week6/homework/src/pages/movieList/MovieListPage.tsx b/week6/homework/src/pages/movieList/MovieListPage.tsx index 9062cd8..a485b83 100644 --- a/week6/homework/src/pages/movieList/MovieListPage.tsx +++ b/week6/homework/src/pages/movieList/MovieListPage.tsx @@ -4,17 +4,42 @@ import ListCard from "./components/card/ListCard"; import { useNavigate } from "react-router-dom"; import { ROUTE_PATH } from "@constants/path"; import RatingFilter from "./components/ratingFilter/RatingFilter"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; const MovieListPage = () => { const [selectedRating, setSelectedRating] = useState("all"); const navigate = useNavigate(); + const observerRef = useRef(null); + const { data: movieList, isPending, isError, + fetchNextPage, + hasNextPage, + isFetchingNextPage, } = useMovieListQuery(selectedRating); + useEffect(() => { + const observer = new IntersectionObserver( + (entries) => { + if (entries[0].isIntersecting && hasNextPage && !isFetchingNextPage) { + fetchNextPage(); + } + }, + { + rootMargin: "100px", + threshold: 0, + }, + ); + + if (observerRef.current) observer.observe(observerRef.current); + + return () => observer.disconnect(); + }, [hasNextPage, isFetchingNextPage, fetchNextPage]); + + const movies = movieList?.pages.flatMap((page) => page.results) ?? []; + if (isPending) return
로딩중
; if (isError) return
에러 발생
; @@ -32,8 +57,8 @@ const MovieListPage = () => {
-
- {movieList?.results.map((movie) => ( +
+ {movies.map((movie) => ( { /> ))}
+ +
{!hasNextPage &&
끝.
}
); }; diff --git a/week6/homework/src/pages/movieList/apis/getMovieList.ts b/week6/homework/src/pages/movieList/apis/getMovieList.ts index f87f3d0..3c657a5 100644 --- a/week6/homework/src/pages/movieList/apis/getMovieList.ts +++ b/week6/homework/src/pages/movieList/apis/getMovieList.ts @@ -1,25 +1,30 @@ import { api } from "@apis/https"; -import { useQuery } from "@tanstack/react-query"; +import { useInfiniteQuery } from "@tanstack/react-query"; import type { MovieListResponse } from "../types/list"; import { API_ENDPOINT } from "@constants/apiEndpoints"; import { QUERY_KEY } from "@constants/queryKeys"; import type { RatingFilterValue } from "../components/ratingFilter/RatingFilter"; -export const getMovieList = (rating: RatingFilterValue) => { +export const getMovieList = (page: number, rating: RatingFilterValue) => { const params = rating === "all" - ? { language: "ko-KR" } + ? { page } : { - language: "ko-KR", "vote_average.gte": Number(rating), "vote_average.lte": Number(rating) === 10 ? 10 : Number(rating) + 0.9, + page, }; return api.get(API_ENDPOINT.LIST, params); }; export const useMovieListQuery = (rating: RatingFilterValue) => { - return useQuery({ + return useInfiniteQuery({ queryKey: [...QUERY_KEY.MOVIE_LIST, rating], - queryFn: () => getMovieList(rating), + initialPageParam: 1, + queryFn: ({ pageParam }) => getMovieList(pageParam, rating), + getNextPageParam: (lastPage) => { + if (lastPage.page >= lastPage.total_pages) return undefined; + return lastPage.page + 1; + }, }); }; From be56b16b51f5d30cc4f98d5e550ea975ca601fbe Mon Sep 17 00:00:00 2001 From: Soy Date: Tue, 2 Jun 2026 21:28:07 +0900 Subject: [PATCH 48/48] =?UTF-8?q?chore:=20styles=20=ED=8F=B4=EB=8D=94=20sh?= =?UTF-8?q?ared=20=EC=95=88=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- week6/homework/src/main.tsx | 2 +- week6/homework/src/{ => shared}/styles/index.css | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename week6/homework/src/{ => shared}/styles/index.css (100%) diff --git a/week6/homework/src/main.tsx b/week6/homework/src/main.tsx index fa39fd9..c0b776f 100644 --- a/week6/homework/src/main.tsx +++ b/week6/homework/src/main.tsx @@ -1,6 +1,6 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; -import "./styles/index.css"; +import "@styles/index.css"; import App from "./App.tsx"; import { QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; diff --git a/week6/homework/src/styles/index.css b/week6/homework/src/shared/styles/index.css similarity index 100% rename from week6/homework/src/styles/index.css rename to week6/homework/src/shared/styles/index.css