`로 `.map()` 렌더 중. 정렬 토글(`setSort`)이나
+다음 페이지 로드(`isFetchingNextPage`) 등으로 페이지가 리렌더되면 **기존 카드 전부가 다시 렌더**된다.
+
+```tsx
+// components/LpCard.tsx (신규)
+import { memo } from "react";
+import type { Lp } from "../types/lp";
+
+interface LpCardProps {
+ lp: Lp;
+ onClick: (id: number) => void; // 인라인 navigate 대신 id만 받는 안정적 핸들러
+}
+
+function LpCardBase({ lp, onClick }: LpCardProps) {
+ return (
+
onClick(lp.id)} className="...">
+ {/* 기존 카드 마크업 */}
+
+ );
+}
+export default memo(LpCardBase); // props 같으면 리렌더 skip
+```
+
+### ② 카드 클릭 핸들러를 `useCallback`으로 고정
+
+**문제:** 기존엔 카드마다 `onClick={() => navigate(`/lps/${lp.id}`)}` 인라인 함수 → memo를 무력화.
+
+```tsx
+// LPListPage.tsx
+const handleCardClick = useCallback(
+ (id: number) => navigate(`/lps/${id}`),
+ [navigate]
+);
+// ...
+{lpList.map((lp) =>
)}
+```
+
+→ ①+② 조합으로, 정렬 토글/추가 로딩 시 **새로 들어온 카드만 렌더**되고 기존 카드는 skip.
+
+### ③ `flatMap` 결과를 `useMemo`로 메모이제이션
+
+**문제:** `const lpList = data?.pages.flatMap(...) || []` 가 **렌더마다 새 배열** 생성 →
+하위에 넘기면 참조가 매번 달라져 memo가 깨진다.
+
+```tsx
+const lpList = useMemo(
+ () => data?.pages.flatMap((page) => page.data.data) ?? [],
+ [data]
+);
+```
+
+### ④ (보너스) CommentSection 댓글 항목 분리 + memo
+
+**문제:** `CommentSection`은 `commentText`(입력창), `openMenuId`, `editingId` 등 state가 많아
+**댓글을 한 글자 타이핑할 때마다 댓글 리스트 전체가 리렌더**된다.
+
+```tsx
+// 댓글 한 개를 CommentItem으로 분리하고 memo로 감싼다.
+const CommentItem = memo(function CommentItem({ comment, myId, onEdit, onDelete }) { ... });
+// 부모에서 onEdit/onDelete는 useCallback으로 고정.
+```
+
+→ 입력창 타이핑 시 입력 영역만 리렌더되고, 기존 댓글들은 Profiler에서 회색(skip)으로 유지.
+
+---
+
+## 적용한 최적화 요약 (한 줄)
+
+- **TMDB**: `MovieCard`(memo) + `handleSelect/handleCloseModal`(useCallback) + `sortedMovies`(useMemo)
+ → 타이핑 시 카드 리렌더 20회 → 0회.
+- **LP**: 카드/댓글 컴포넌트 분리 후 `memo`, 클릭·수정·삭제 핸들러 `useCallback`, 목록 배열 `useMemo`
+ → 정렬 토글·추가 로딩·댓글 입력 시 기존 항목 리렌더 제거.
diff --git a/UMC-10th-mission-FE/.env b/UMC-10th-mission-FE/.env
deleted file mode 100644
index 286cd470..00000000
--- a/UMC-10th-mission-FE/.env
+++ /dev/null
@@ -1,2 +0,0 @@
-VITE_API_BASE_URL=http://localhost:8000
-
diff --git a/UMC-10th-mission-FE/README.md b/UMC-10th-mission-FE/README.md
deleted file mode 100644
index 7dbf7ebf..00000000
--- a/UMC-10th-mission-FE/README.md
+++ /dev/null
@@ -1,73 +0,0 @@
-# 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/UMC-10th-mission-FE/eslint.config.js b/UMC-10th-mission-FE/eslint.config.js
deleted file mode 100644
index ef614d25..00000000
--- a/UMC-10th-mission-FE/eslint.config.js
+++ /dev/null
@@ -1,22 +0,0 @@
-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/UMC-10th-mission-FE/package.json b/UMC-10th-mission-FE/package.json
deleted file mode 100644
index d73f5d9a..00000000
--- a/UMC-10th-mission-FE/package.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "name": "umc",
- "private": true,
- "version": "0.0.0",
- "type": "module",
- "scripts": {
- "dev": "vite",
- "build": "tsc -b && vite build",
- "lint": "eslint .",
- "preview": "vite preview"
- },
- "dependencies": {
- "@hookform/resolvers": "^5.2.2",
- "@tailwindcss/vite": "^4.2.4",
- "@tanstack/react-query": "^5.100.9",
- "axios": "^1.16.0",
- "lucide-react": "^1.14.0",
- "react": "^19.2.5",
- "react-dom": "^19.2.5",
- "react-hook-form": "^7.75.0",
- "react-intersection-observer": "^10.0.3",
- "react-router": "^7.15.0",
- "react-router-dom": "^7.15.0",
- "styled-components": "^6.4.1",
- "zod": "^4.4.3"
- },
- "devDependencies": {
- "@eslint/js": "^10.0.1",
- "@tanstack/react-query-devtools": "^5.100.9",
- "@types/node": "^24.12.2",
- "@types/react": "^19.2.14",
- "@types/react-dom": "^19.2.3",
- "@types/styled-components": "^5.1.36",
- "@vitejs/plugin-react": "^6.0.1",
- "autoprefixer": "^10.5.0",
- "eslint": "^10.2.1",
- "eslint-plugin-react-hooks": "^7.1.1",
- "eslint-plugin-react-refresh": "^0.5.2",
- "globals": "^17.5.0",
- "postcss": "^8.5.14",
- "tailwindcss": "^4.2.4",
- "typescript": "~6.0.2",
- "typescript-eslint": "^8.58.2",
- "vite": "^8.0.10"
- }
-}
diff --git a/UMC-10th-mission-FE/pnpm-lock.yaml b/UMC-10th-mission-FE/pnpm-lock.yaml
deleted file mode 100644
index 8a23b496..00000000
--- a/UMC-10th-mission-FE/pnpm-lock.yaml
+++ /dev/null
@@ -1,2383 +0,0 @@
-lockfileVersion: '9.0'
-
-settings:
- autoInstallPeers: true
- excludeLinksFromLockfile: false
-
-importers:
-
- .:
- dependencies:
- '@hookform/resolvers':
- specifier: ^5.2.2
- version: 5.2.2(react-hook-form@7.75.0(react@19.2.6))
- '@tailwindcss/vite':
- specifier: ^4.2.4
- version: 4.2.4(vite@8.0.11(@types/node@24.12.3)(jiti@2.7.0))
- '@tanstack/react-query':
- specifier: ^5.100.9
- version: 5.100.9(react@19.2.6)
- axios:
- specifier: ^1.16.0
- version: 1.16.0
- lucide-react:
- specifier: ^1.14.0
- version: 1.14.0(react@19.2.6)
- react:
- specifier: ^19.2.5
- version: 19.2.6
- react-dom:
- specifier: ^19.2.5
- version: 19.2.6(react@19.2.6)
- react-hook-form:
- specifier: ^7.75.0
- version: 7.75.0(react@19.2.6)
- react-intersection-observer:
- specifier: ^10.0.3
- version: 10.0.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
- react-router:
- specifier: ^7.15.0
- version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
- react-router-dom:
- specifier: ^7.15.0
- version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
- styled-components:
- specifier: ^6.4.1
- version: 6.4.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
- zod:
- specifier: ^4.4.3
- version: 4.4.3
- devDependencies:
- '@eslint/js':
- specifier: ^10.0.1
- version: 10.0.1(eslint@10.3.0(jiti@2.7.0))
- '@tanstack/react-query-devtools':
- specifier: ^5.100.9
- version: 5.100.9(@tanstack/react-query@5.100.9(react@19.2.6))(react@19.2.6)
- '@types/node':
- specifier: ^24.12.2
- version: 24.12.3
- '@types/react':
- specifier: ^19.2.14
- version: 19.2.14
- '@types/react-dom':
- specifier: ^19.2.3
- version: 19.2.3(@types/react@19.2.14)
- '@types/styled-components':
- specifier: ^5.1.36
- version: 5.1.36
- '@vitejs/plugin-react':
- specifier: ^6.0.1
- version: 6.0.1(vite@8.0.11(@types/node@24.12.3)(jiti@2.7.0))
- autoprefixer:
- specifier: ^10.5.0
- version: 10.5.0(postcss@8.5.14)
- eslint:
- specifier: ^10.2.1
- version: 10.3.0(jiti@2.7.0)
- eslint-plugin-react-hooks:
- specifier: ^7.1.1
- version: 7.1.1(eslint@10.3.0(jiti@2.7.0))
- eslint-plugin-react-refresh:
- specifier: ^0.5.2
- version: 0.5.2(eslint@10.3.0(jiti@2.7.0))
- globals:
- specifier: ^17.5.0
- version: 17.6.0
- postcss:
- specifier: ^8.5.14
- version: 8.5.14
- tailwindcss:
- specifier: ^4.2.4
- version: 4.2.4
- typescript:
- specifier: ~6.0.2
- version: 6.0.3
- typescript-eslint:
- specifier: ^8.58.2
- version: 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3)
- vite:
- specifier: ^8.0.10
- version: 8.0.11(@types/node@24.12.3)(jiti@2.7.0)
-
-packages:
-
- '@babel/code-frame@7.29.0':
- resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/compat-data@7.29.3':
- resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/core@7.29.0':
- resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/generator@7.29.1':
- resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-compilation-targets@7.28.6':
- resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-globals@7.28.0':
- resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-module-imports@7.28.6':
- resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-module-transforms@7.28.6':
- resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0
-
- '@babel/helper-string-parser@7.27.1':
- resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-validator-identifier@7.28.5':
- resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-validator-option@7.27.1':
- resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helpers@7.29.2':
- resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/parser@7.29.3':
- resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==}
- engines: {node: '>=6.0.0'}
- hasBin: true
-
- '@babel/template@7.28.6':
- resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
- engines: {node: '>=6.9.0'}
-
- '@babel/traverse@7.29.0':
- resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/types@7.29.0':
- resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
- 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==}
-
- '@emotion/is-prop-valid@1.4.0':
- resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==}
-
- '@emotion/memoize@0.9.0':
- resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==}
-
- '@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.5.5':
- resolution: {integrity: sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==}
- 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.1':
- resolution: {integrity: sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==}
- engines: {node: ^20.19.0 || ^22.13.0 || >=24}
-
- '@hookform/resolvers@5.2.2':
- resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==}
- peerDependencies:
- react-hook-form: ^7.55.0
-
- '@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.128.0':
- resolution: {integrity: sha512-huv1Y/LzBJkBVHt3OlC7u0zHBW9qXf1FdD7sGmc1rXc2P1mTwHssYv7jyGx5KAACSCH+9B3Bhn6Z9luHRvf7pQ==}
-
- '@rolldown/binding-android-arm64@1.0.0-rc.18':
- resolution: {integrity: sha512-lIDyUAfD7U3+BWKzdxMbJcsYHuqXqmGz40aeRqvuAm3y5TkJSYTBW2RDrn65DJFPQqVjUAUqq5uz8urzQ8aBdQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [android]
-
- '@rolldown/binding-darwin-arm64@1.0.0-rc.18':
- resolution: {integrity: sha512-apJq2ktnGp27nSInMR5Vcj8kY6xJzDAvfdIFlpDcAK/w4cDO58qVoi1YQsES/SKiFNge/6e4CUzgjfHduYqWpQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [darwin]
-
- '@rolldown/binding-darwin-x64@1.0.0-rc.18':
- resolution: {integrity: sha512-5Ofot8xbs+pxRHJqm9/9N/4sTQOvdrwEsmPE9pdLEEoAbdZtG6F2LMDfO1sp6ZAtXJuJV/21ew2srq3W8NXB5g==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [darwin]
-
- '@rolldown/binding-freebsd-x64@1.0.0-rc.18':
- resolution: {integrity: sha512-7h8eeOTT1eyqJyx64BFCnWZpNm486hGWt2sqeLLgDxA0xI1oGZ9H7gK1S85uNGmBhkdPwa/6reTxfFFKvIsebw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [freebsd]
-
- '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.18':
- resolution: {integrity: sha512-eRcm/HVt9U/JFu5RKAEKwGQYtDCKWLiaH6wOnsSEp6NMBb/3Os8LgHZlNyzMpFVNmiiMFlfb2zEnebfzJrHFmg==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm]
- os: [linux]
-
- '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.18':
- resolution: {integrity: sha512-SOrT/cT4ukTmgnrEz/Hg3m7LBnuCLW9psDeMKrimRWY4I8DmnO7Lco8W2vtqPmMkbVu8iJ+g4GFLVLLOVjJ9DQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- '@rolldown/binding-linux-arm64-musl@1.0.0-rc.18':
- resolution: {integrity: sha512-QWjdxN1HJCpBTAcZ5N5F7wju3gVPzRzSpmGzx7na0c/1qpN9CFil+xt+l9lV/1M6/gqHSNXCiqPfwhVJPeLnug==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.18':
- resolution: {integrity: sha512-ugCOyj7a4d9h3q9B+wXmf6g3a68UsjGh6dob5DHevHGMwDUbhsYNbSPxJsENcIttJZ9jv7qGM2UesLw5jqIhdg==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [ppc64]
- os: [linux]
- libc: [glibc]
-
- '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.18':
- resolution: {integrity: sha512-kKWRhbsotpXkGbcd5dllUWg5gEXcDAa8u5YnP9AV5DYNbvJHGzzuwv7dpmhc8NqKMJldl0a+x76IHbspEpEmdA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [s390x]
- os: [linux]
- libc: [glibc]
-
- '@rolldown/binding-linux-x64-gnu@1.0.0-rc.18':
- resolution: {integrity: sha512-uCo8ElcCIAMyYAZyuIZ81oFkhTSIllNvUCHCAlbhlN4ji3uC28h7IIdlXyIvGO7HsuqnV9p3rD/bpH7XhIyhRw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- '@rolldown/binding-linux-x64-musl@1.0.0-rc.18':
- resolution: {integrity: sha512-XNOQZtuE6yUIvx4rwGemwh8kpL1xvU41FXy/s9K7T/3JVcqGzo3NfKM2HrbrGgfPYGFW42f07Wk++aOC6B9NWA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- '@rolldown/binding-openharmony-arm64@1.0.0-rc.18':
- resolution: {integrity: sha512-tSn/kzrfa7tNOXr7sEacDBN4YsIqTyLqh45IO0nHDwtpKIDNDJr+VFojt+4klSpChxB29JLyduSsE0MKEwa65A==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [openharmony]
-
- '@rolldown/binding-wasm32-wasi@1.0.0-rc.18':
- resolution: {integrity: sha512-+J9YGmc+czgqlhYmwun3S3O0FIZhsH8ep2456xwjAdIOmuJxM7xz4P4PtrxU+Bz17a/5bqPA8o3HAAoX0teUdg==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [wasm32]
-
- '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.18':
- resolution: {integrity: sha512-zsu47DgU0FQzSwi6sU9dZoEdUv7pc1AptSEz/Z8HBg54sV0Pbs3N0+CrIbTsgiu6EyoaNN9CHboqbLaz9lhOyQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [win32]
-
- '@rolldown/binding-win32-x64-msvc@1.0.0-rc.18':
- resolution: {integrity: sha512-7H+3yqGgmnlDTRRhw/xpYY9J1kf4GC681nVc4GqKhExZTDrVVrV2tsOR9kso0fvgBdcTCcQShx4SLLoHgaLwhg==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [win32]
-
- '@rolldown/pluginutils@1.0.0-rc.18':
- resolution: {integrity: sha512-CUY5Mnhe64xQBGZEEXQ5WyZwsc1JU3vAZLIxtrsBt3LO6UOb+C8GunVKqe9sT8NeWb4lqSaoJtp2xo6GxT1MNw==}
-
- '@rolldown/pluginutils@1.0.0-rc.7':
- resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==}
-
- '@standard-schema/utils@0.3.0':
- resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
-
- '@tailwindcss/node@4.2.4':
- resolution: {integrity: sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==}
-
- '@tailwindcss/oxide-android-arm64@4.2.4':
- resolution: {integrity: sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [android]
-
- '@tailwindcss/oxide-darwin-arm64@4.2.4':
- resolution: {integrity: sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [darwin]
-
- '@tailwindcss/oxide-darwin-x64@4.2.4':
- resolution: {integrity: sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [darwin]
-
- '@tailwindcss/oxide-freebsd-x64@4.2.4':
- resolution: {integrity: sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [freebsd]
-
- '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4':
- resolution: {integrity: sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==}
- engines: {node: '>= 20'}
- cpu: [arm]
- os: [linux]
-
- '@tailwindcss/oxide-linux-arm64-gnu@4.2.4':
- resolution: {integrity: sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- '@tailwindcss/oxide-linux-arm64-musl@4.2.4':
- resolution: {integrity: sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- '@tailwindcss/oxide-linux-x64-gnu@4.2.4':
- resolution: {integrity: sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- '@tailwindcss/oxide-linux-x64-musl@4.2.4':
- resolution: {integrity: sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- '@tailwindcss/oxide-wasm32-wasi@4.2.4':
- resolution: {integrity: sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw==}
- 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.2.4':
- resolution: {integrity: sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [win32]
-
- '@tailwindcss/oxide-win32-x64-msvc@4.2.4':
- resolution: {integrity: sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [win32]
-
- '@tailwindcss/oxide@4.2.4':
- resolution: {integrity: sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==}
- engines: {node: '>= 20'}
-
- '@tailwindcss/vite@4.2.4':
- resolution: {integrity: sha512-pCvohwOCspk3ZFn6eJzrrX3g4n2JY73H6MmYC87XfGPyTty4YsCjYTMArRZm/zOI8dIt3+EcrLHAFPe5A4bgtw==}
- peerDependencies:
- vite: ^5.2.0 || ^6 || ^7 || ^8
-
- '@tanstack/query-core@5.100.9':
- resolution: {integrity: sha512-SJSFw1S8+kQ0+knv/XGfrbocWoAlT7vDKsSImtLx3ZPQmEcR46hkDjLSvynSy25N8Ms4tIEini1FuBd5k7IscQ==}
-
- '@tanstack/query-devtools@5.100.9':
- resolution: {integrity: sha512-gqiptrTIhbK2PuCaPRHmWXfJG1NGYVFpAr0HqogEqiSBNB5xDz6fmesQt7w4WgMOqOQPnPHJ3ZDMuhDaXvNO8g==}
-
- '@tanstack/react-query-devtools@5.100.9':
- resolution: {integrity: sha512-mM3slaVGXJmz+pOLgXdANj75ikgQCyudyl3kmFvm6brI1JyVeY/+IeD17uDHIvZrD8hfoO2sdZ54RFsHdYAuhA==}
- peerDependencies:
- '@tanstack/react-query': ^5.100.9
- react: ^18 || ^19
-
- '@tanstack/react-query@5.100.9':
- resolution: {integrity: sha512-Oa44XkaI3kCNN6ME0KByU3xT3SEUNOMfZpHxL6+wFoTm+OeUFYHKdeYVe0aOXlRDm/f15sgLwEt2HDorIdW8+A==}
- 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/hoist-non-react-statics@3.3.7':
- resolution: {integrity: sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==}
- peerDependencies:
- '@types/react': '*'
-
- '@types/json-schema@7.0.15':
- resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
-
- '@types/node@24.12.3':
- resolution: {integrity: sha512-8oljBDGun9cIsZRJR6fkihn0TSXJI0UDOOhncYaERq6M0JMDoPLxyscwruJcb4GKS6dvK/d8xebYBg27h/duaQ==}
-
- '@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.14':
- resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==}
-
- '@types/styled-components@5.1.36':
- resolution: {integrity: sha512-pGMRNY5G2rNDKEv2DOiFYa7Ft1r0jrhmgBwHhOMzPTgCjO76bCot0/4uEfqj7K0Jf1KdQmDtAuaDk9EAs9foSw==}
-
- '@typescript-eslint/eslint-plugin@8.59.2':
- resolution: {integrity: sha512-j/bwmkBvHUtPNxzuWe5z6BEk3q54YRyGlBXkSsmfoih7zNrBvl5A9A98anlp/7JbyZcWIJ8KXo/3Tq/DjFLtuQ==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- peerDependencies:
- '@typescript-eslint/parser': ^8.59.2
- eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
- typescript: '>=4.8.4 <6.1.0'
-
- '@typescript-eslint/parser@8.59.2':
- resolution: {integrity: sha512-plR3pp6D+SSUn1HM7xvSkx12/DhoHInI2YF35KAcVFNZvlC0gtrWqx7Qq1oH2Ssgi0vlFRCTbP+DZc7B9+TtsQ==}
- 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.59.2':
- resolution: {integrity: sha512-+2hqvEkeyf/0FBor67duF0Ll7Ot8jyKzDQOSrxazF/danillRq2DwR9dLptsXpoZQqxE1UisSmoZewrlPas9Vw==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- peerDependencies:
- typescript: '>=4.8.4 <6.1.0'
-
- '@typescript-eslint/scope-manager@8.59.2':
- resolution: {integrity: sha512-JzfyEpEtOU89CcFSwyNS3mu4MLvLSXqnmX05+aKBDM+TdR5jzcGOEBwxwGNxrEQ7p/z6kK2WyioCGBf2zZBnvg==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
- '@typescript-eslint/tsconfig-utils@8.59.2':
- resolution: {integrity: sha512-BKK4alN7oi4C/zv4VqHQ+uRU+lTa6JGIZ7s1juw7b3RHo9OfKB+bKX3u0iVZetdsUCBBkSbdWbarJbmN0fTeSw==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- peerDependencies:
- typescript: '>=4.8.4 <6.1.0'
-
- '@typescript-eslint/type-utils@8.59.2':
- resolution: {integrity: sha512-nhqaj1nmTdVVl/BP5omXNRGO38jn5iosis2vbdmupF2txCf8ylWT8lx+JlvMYYVqzGVKtjojUFoQ3JRWK+mfzQ==}
- 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.59.2':
- resolution: {integrity: sha512-e82GVOE8Ps3E++Egvb6Y3Dw0S10u8NkQ9KXmtRhCWJJ8kDhOJTvtMAWnFL16kB1583goCWXsr0NieKCZMs2/0Q==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
- '@typescript-eslint/typescript-estree@8.59.2':
- resolution: {integrity: sha512-o0XPGNwcWw+FIwStOWn+BwBuEmL6QXP0rsvAFg7ET1dey1Nr6Wb1ac8p5HEsK0ygO/6mUxlk+YWQD9xcb/nnXg==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- peerDependencies:
- typescript: '>=4.8.4 <6.1.0'
-
- '@typescript-eslint/utils@8.59.2':
- resolution: {integrity: sha512-Juw3EinkXqjaffxz6roowvV7GZT/kET5vSKKZT6upl5TXdWkLkYmNPXwDDL2Vkt2DPn0nODIS4egC/0AGxKo/Q==}
- 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.59.2':
- resolution: {integrity: sha512-NwjLUnGy8/Zfx23fl50tRC8rYaYnM52xNRYFAXvmiil9yh1+K6aRVQMnzW6gQB/1DLgWt977lYQn7C+wtgXZiA==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
- '@vitejs/plugin-react@6.0.1':
- resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==}
- 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
-
- ajv@6.15.0:
- resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==}
-
- asynckit@0.4.0:
- resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
-
- autoprefixer@10.5.0:
- resolution: {integrity: sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==}
- engines: {node: ^10 || ^12 || >=14}
- hasBin: true
- peerDependencies:
- postcss: ^8.1.0
-
- axios@1.16.0:
- resolution: {integrity: sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==}
-
- balanced-match@4.0.4:
- resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
- engines: {node: 18 || 20 || >=22}
-
- baseline-browser-mapping@2.10.27:
- resolution: {integrity: sha512-zEs/ufmZoUd7WftKpKyXaT6RFxpQ5Qm9xytKRHvJfxFV9DFJkZph9RvJ1LcOUi0Z1ZVijMte65JbILeV+8QQEA==}
- 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.30001792:
- resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==}
-
- 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==}
-
- 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'}
-
- 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.352:
- resolution: {integrity: sha512-9wHk8x6dyuimoe18EdiDPWKExNdxYqo4fn4FwOVVper6RxT3cmpBwBkWWfSOCYJjQdIco/nPhJhNLmn4Ufg1Yg==}
-
- enhanced-resolve@5.21.1:
- resolution: {integrity: sha512-8p7DUVq6XJnZEz9W4oSwiwycxBIjHjRzYb3Je3zVN+geKTRQKzAkR/K4PBExlS0090d9nshak6phMUxr3PDjmQ==}
- 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.1:
- resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
- 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.3.0:
- resolution: {integrity: sha512-XbEXaRva5cF0ZQB8w6MluHA0kZZfV2DuCMJ3ozyEOHLwDpZX2Lmm/7Pp0xdJmI0GL1W05VH5VwIFHEm1Vcw2gw==}
- 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'}
-
- fraction.js@5.3.4:
- resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==}
-
- 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.3:
- resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==}
- 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==}
-
- hoist-non-react-statics@3.3.2:
- resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
-
- 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]
- libc: [glibc]
-
- lightningcss-linux-arm64-musl@1.32.0:
- resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- lightningcss-linux-x64-gnu@1.32.0:
- resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- 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]
- libc: [musl]
-
- 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==}
-
- lucide-react@1.14.0:
- resolution: {integrity: sha512-+1mdWcfSJVUsaTIjN9zoezmUhfXo5l0vP7ekBMPo3jcS/aIkxHnXqAPsByszMZx/Y8oQBRJxJx5xg+RH3urzxA==}
- peerDependencies:
- react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
-
- 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.38:
- resolution: {integrity: sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==}
-
- 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-value-parser@4.2.0:
- resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
-
- postcss@8.5.14:
- resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==}
- 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-hook-form@7.75.0:
- resolution: {integrity: sha512-Ovv94H+0p3sJ7B9B5QxPuCP1u8V/cHuVGyH55cSwodYDtoJwK+fqk3vjfIgSX59I2U/bU4z0nRJ9HMLpNiWEmw==}
- engines: {node: '>=18.0.0'}
- peerDependencies:
- react: ^16.8.0 || ^17 || ^18 || ^19
-
- react-intersection-observer@10.0.3:
- resolution: {integrity: sha512-luICLMbs0zxTO/70Zy7K5jOXkABPEVSAF8T3FdZUlctsrIaPLmx8TZe2SSA+CY2HGWfz2INyNTnp82pxNNsShA==}
- peerDependencies:
- react: ^17.0.0 || ^18.0.0 || ^19.0.0
- react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
- peerDependenciesMeta:
- react-dom:
- optional: true
-
- react-is@16.13.1:
- resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
-
- react-router-dom@7.15.0:
- resolution: {integrity: sha512-VcrVg64Fo8nwBvDscajG8gRTLIuTC6N50nb22l2HOOV4PTOHgoGp8mUjy9wLiHYoYTSYI36tUnXZgasSRFZorQ==}
- engines: {node: '>=20.0.0'}
- peerDependencies:
- react: '>=18'
- react-dom: '>=18'
-
- react-router@7.15.0:
- resolution: {integrity: sha512-HW9vYwuM8f4yx66Izy8xfrzCM+SBJluoZcCbww9A1TySax11S5Vgw6fi3ZjMONw9J4gQwngL7PzkyIpJJpJ7RQ==}
- 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'}
-
- rolldown@1.0.0-rc.18:
- resolution: {integrity: sha512-phmyKBpuBdRYDf4hgyynGAYn/rDDe+iZXKVJ7WX5b1zQzpLkP5oJRPGsfJuHdzPMlyyEO/4sPW6yfSx2gf7lVg==}
- 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.7.4:
- resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
- 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'}
-
- 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'}
-
- styled-components@6.4.1:
- resolution: {integrity: sha512-ADu2dF53esUzzM4I0ewxhxFtsDd6v4V6dNkg3vG0iFKhnt06sJneTZnRvujAosZwW0XD58IKgGMQoqri4wHRqg==}
- engines: {node: '>= 16'}
- peerDependencies:
- css-to-react-native: '>= 3.2.0'
- react: '>= 16.8.0'
- react-dom: '>= 16.8.0'
- react-native: '>= 0.68.0'
- peerDependenciesMeta:
- css-to-react-native:
- optional: true
- react-dom:
- optional: true
- react-native:
- optional: true
-
- stylis@4.3.6:
- resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==}
-
- tailwindcss@4.2.4:
- resolution: {integrity: sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==}
-
- tapable@2.3.3:
- resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==}
- engines: {node: '>=6'}
-
- tinyglobby@0.2.16:
- resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
- 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.59.2:
- resolution: {integrity: sha512-pJw051uomb3ZeCzGTpRb8RbEqB5Y4WWet8gl/GcTlU35BSx0PVdZ86/bqkQCyKKuraVQEK7r6kBHQXF+fBhkoQ==}
- 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.11:
- resolution: {integrity: sha512-Jz1mxtUBR5xTT65VOdJZUUeoyLtqljmFkiUXhPTLZka3RDc9vpi/xXkyrnsdRcm2lIi3l3GPMnAidTsEGIj3Ow==}
- 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.0':
- dependencies:
- '@babel/helper-validator-identifier': 7.28.5
- js-tokens: 4.0.0
- picocolors: 1.1.1
-
- '@babel/compat-data@7.29.3': {}
-
- '@babel/core@7.29.0':
- dependencies:
- '@babel/code-frame': 7.29.0
- '@babel/generator': 7.29.1
- '@babel/helper-compilation-targets': 7.28.6
- '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0)
- '@babel/helpers': 7.29.2
- '@babel/parser': 7.29.3
- '@babel/template': 7.28.6
- '@babel/traverse': 7.29.0
- '@babel/types': 7.29.0
- '@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.1':
- dependencies:
- '@babel/parser': 7.29.3
- '@babel/types': 7.29.0
- '@jridgewell/gen-mapping': 0.3.13
- '@jridgewell/trace-mapping': 0.3.31
- jsesc: 3.1.0
-
- '@babel/helper-compilation-targets@7.28.6':
- dependencies:
- '@babel/compat-data': 7.29.3
- '@babel/helper-validator-option': 7.27.1
- browserslist: 4.28.2
- lru-cache: 5.1.1
- semver: 6.3.1
-
- '@babel/helper-globals@7.28.0': {}
-
- '@babel/helper-module-imports@7.28.6':
- dependencies:
- '@babel/traverse': 7.29.0
- '@babel/types': 7.29.0
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)':
- dependencies:
- '@babel/core': 7.29.0
- '@babel/helper-module-imports': 7.28.6
- '@babel/helper-validator-identifier': 7.28.5
- '@babel/traverse': 7.29.0
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-string-parser@7.27.1': {}
-
- '@babel/helper-validator-identifier@7.28.5': {}
-
- '@babel/helper-validator-option@7.27.1': {}
-
- '@babel/helpers@7.29.2':
- dependencies:
- '@babel/template': 7.28.6
- '@babel/types': 7.29.0
-
- '@babel/parser@7.29.3':
- dependencies:
- '@babel/types': 7.29.0
-
- '@babel/template@7.28.6':
- dependencies:
- '@babel/code-frame': 7.29.0
- '@babel/parser': 7.29.3
- '@babel/types': 7.29.0
-
- '@babel/traverse@7.29.0':
- dependencies:
- '@babel/code-frame': 7.29.0
- '@babel/generator': 7.29.1
- '@babel/helper-globals': 7.28.0
- '@babel/parser': 7.29.3
- '@babel/template': 7.28.6
- '@babel/types': 7.29.0
- debug: 4.4.3
- transitivePeerDependencies:
- - supports-color
-
- '@babel/types@7.29.0':
- dependencies:
- '@babel/helper-string-parser': 7.27.1
- '@babel/helper-validator-identifier': 7.28.5
-
- '@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
-
- '@emotion/is-prop-valid@1.4.0':
- dependencies:
- '@emotion/memoize': 0.9.0
-
- '@emotion/memoize@0.9.0': {}
-
- '@eslint-community/eslint-utils@4.9.1(eslint@10.3.0(jiti@2.7.0))':
- dependencies:
- eslint: 10.3.0(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.5.5':
- 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.3.0(jiti@2.7.0))':
- optionalDependencies:
- eslint: 10.3.0(jiti@2.7.0)
-
- '@eslint/object-schema@3.0.5': {}
-
- '@eslint/plugin-kit@0.7.1':
- dependencies:
- '@eslint/core': 1.2.1
- levn: 0.4.1
-
- '@hookform/resolvers@5.2.2(react-hook-form@7.75.0(react@19.2.6))':
- dependencies:
- '@standard-schema/utils': 0.3.0
- react-hook-form: 7.75.0(react@19.2.6)
-
- '@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.128.0': {}
-
- '@rolldown/binding-android-arm64@1.0.0-rc.18':
- optional: true
-
- '@rolldown/binding-darwin-arm64@1.0.0-rc.18':
- optional: true
-
- '@rolldown/binding-darwin-x64@1.0.0-rc.18':
- optional: true
-
- '@rolldown/binding-freebsd-x64@1.0.0-rc.18':
- optional: true
-
- '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.18':
- optional: true
-
- '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.18':
- optional: true
-
- '@rolldown/binding-linux-arm64-musl@1.0.0-rc.18':
- optional: true
-
- '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.18':
- optional: true
-
- '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.18':
- optional: true
-
- '@rolldown/binding-linux-x64-gnu@1.0.0-rc.18':
- optional: true
-
- '@rolldown/binding-linux-x64-musl@1.0.0-rc.18':
- optional: true
-
- '@rolldown/binding-openharmony-arm64@1.0.0-rc.18':
- optional: true
-
- '@rolldown/binding-wasm32-wasi@1.0.0-rc.18':
- 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.0-rc.18':
- optional: true
-
- '@rolldown/binding-win32-x64-msvc@1.0.0-rc.18':
- optional: true
-
- '@rolldown/pluginutils@1.0.0-rc.18': {}
-
- '@rolldown/pluginutils@1.0.0-rc.7': {}
-
- '@standard-schema/utils@0.3.0': {}
-
- '@tailwindcss/node@4.2.4':
- dependencies:
- '@jridgewell/remapping': 2.3.5
- enhanced-resolve: 5.21.1
- jiti: 2.7.0
- lightningcss: 1.32.0
- magic-string: 0.30.21
- source-map-js: 1.2.1
- tailwindcss: 4.2.4
-
- '@tailwindcss/oxide-android-arm64@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-darwin-arm64@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-darwin-x64@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-freebsd-x64@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-linux-arm64-gnu@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-linux-arm64-musl@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-linux-x64-gnu@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-linux-x64-musl@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-wasm32-wasi@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-win32-arm64-msvc@4.2.4':
- optional: true
-
- '@tailwindcss/oxide-win32-x64-msvc@4.2.4':
- optional: true
-
- '@tailwindcss/oxide@4.2.4':
- optionalDependencies:
- '@tailwindcss/oxide-android-arm64': 4.2.4
- '@tailwindcss/oxide-darwin-arm64': 4.2.4
- '@tailwindcss/oxide-darwin-x64': 4.2.4
- '@tailwindcss/oxide-freebsd-x64': 4.2.4
- '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.4
- '@tailwindcss/oxide-linux-arm64-gnu': 4.2.4
- '@tailwindcss/oxide-linux-arm64-musl': 4.2.4
- '@tailwindcss/oxide-linux-x64-gnu': 4.2.4
- '@tailwindcss/oxide-linux-x64-musl': 4.2.4
- '@tailwindcss/oxide-wasm32-wasi': 4.2.4
- '@tailwindcss/oxide-win32-arm64-msvc': 4.2.4
- '@tailwindcss/oxide-win32-x64-msvc': 4.2.4
-
- '@tailwindcss/vite@4.2.4(vite@8.0.11(@types/node@24.12.3)(jiti@2.7.0))':
- dependencies:
- '@tailwindcss/node': 4.2.4
- '@tailwindcss/oxide': 4.2.4
- tailwindcss: 4.2.4
- vite: 8.0.11(@types/node@24.12.3)(jiti@2.7.0)
-
- '@tanstack/query-core@5.100.9': {}
-
- '@tanstack/query-devtools@5.100.9': {}
-
- '@tanstack/react-query-devtools@5.100.9(@tanstack/react-query@5.100.9(react@19.2.6))(react@19.2.6)':
- dependencies:
- '@tanstack/query-devtools': 5.100.9
- '@tanstack/react-query': 5.100.9(react@19.2.6)
- react: 19.2.6
-
- '@tanstack/react-query@5.100.9(react@19.2.6)':
- dependencies:
- '@tanstack/query-core': 5.100.9
- 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/hoist-non-react-statics@3.3.7(@types/react@19.2.14)':
- dependencies:
- '@types/react': 19.2.14
- hoist-non-react-statics: 3.3.2
-
- '@types/json-schema@7.0.15': {}
-
- '@types/node@24.12.3':
- dependencies:
- undici-types: 7.16.0
-
- '@types/react-dom@19.2.3(@types/react@19.2.14)':
- dependencies:
- '@types/react': 19.2.14
-
- '@types/react@19.2.14':
- dependencies:
- csstype: 3.2.3
-
- '@types/styled-components@5.1.36':
- dependencies:
- '@types/hoist-non-react-statics': 3.3.7(@types/react@19.2.14)
- '@types/react': 19.2.14
- csstype: 3.2.3
-
- '@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3)':
- dependencies:
- '@eslint-community/regexpp': 4.12.2
- '@typescript-eslint/parser': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3)
- '@typescript-eslint/scope-manager': 8.59.2
- '@typescript-eslint/type-utils': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3)
- '@typescript-eslint/utils': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3)
- '@typescript-eslint/visitor-keys': 8.59.2
- eslint: 10.3.0(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.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3)':
- dependencies:
- '@typescript-eslint/scope-manager': 8.59.2
- '@typescript-eslint/types': 8.59.2
- '@typescript-eslint/typescript-estree': 8.59.2(typescript@6.0.3)
- '@typescript-eslint/visitor-keys': 8.59.2
- debug: 4.4.3
- eslint: 10.3.0(jiti@2.7.0)
- typescript: 6.0.3
- transitivePeerDependencies:
- - supports-color
-
- '@typescript-eslint/project-service@8.59.2(typescript@6.0.3)':
- dependencies:
- '@typescript-eslint/tsconfig-utils': 8.59.2(typescript@6.0.3)
- '@typescript-eslint/types': 8.59.2
- debug: 4.4.3
- typescript: 6.0.3
- transitivePeerDependencies:
- - supports-color
-
- '@typescript-eslint/scope-manager@8.59.2':
- dependencies:
- '@typescript-eslint/types': 8.59.2
- '@typescript-eslint/visitor-keys': 8.59.2
-
- '@typescript-eslint/tsconfig-utils@8.59.2(typescript@6.0.3)':
- dependencies:
- typescript: 6.0.3
-
- '@typescript-eslint/type-utils@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3)':
- dependencies:
- '@typescript-eslint/types': 8.59.2
- '@typescript-eslint/typescript-estree': 8.59.2(typescript@6.0.3)
- '@typescript-eslint/utils': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3)
- debug: 4.4.3
- eslint: 10.3.0(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.59.2': {}
-
- '@typescript-eslint/typescript-estree@8.59.2(typescript@6.0.3)':
- dependencies:
- '@typescript-eslint/project-service': 8.59.2(typescript@6.0.3)
- '@typescript-eslint/tsconfig-utils': 8.59.2(typescript@6.0.3)
- '@typescript-eslint/types': 8.59.2
- '@typescript-eslint/visitor-keys': 8.59.2
- debug: 4.4.3
- minimatch: 10.2.5
- semver: 7.7.4
- tinyglobby: 0.2.16
- ts-api-utils: 2.5.0(typescript@6.0.3)
- typescript: 6.0.3
- transitivePeerDependencies:
- - supports-color
-
- '@typescript-eslint/utils@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3)':
- dependencies:
- '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.7.0))
- '@typescript-eslint/scope-manager': 8.59.2
- '@typescript-eslint/types': 8.59.2
- '@typescript-eslint/typescript-estree': 8.59.2(typescript@6.0.3)
- eslint: 10.3.0(jiti@2.7.0)
- typescript: 6.0.3
- transitivePeerDependencies:
- - supports-color
-
- '@typescript-eslint/visitor-keys@8.59.2':
- dependencies:
- '@typescript-eslint/types': 8.59.2
- eslint-visitor-keys: 5.0.1
-
- '@vitejs/plugin-react@6.0.1(vite@8.0.11(@types/node@24.12.3)(jiti@2.7.0))':
- dependencies:
- '@rolldown/pluginutils': 1.0.0-rc.7
- vite: 8.0.11(@types/node@24.12.3)(jiti@2.7.0)
-
- acorn-jsx@5.3.2(acorn@8.16.0):
- dependencies:
- acorn: 8.16.0
-
- acorn@8.16.0: {}
-
- 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: {}
-
- autoprefixer@10.5.0(postcss@8.5.14):
- dependencies:
- browserslist: 4.28.2
- caniuse-lite: 1.0.30001792
- fraction.js: 5.3.4
- picocolors: 1.1.1
- postcss: 8.5.14
- postcss-value-parser: 4.2.0
-
- axios@1.16.0:
- dependencies:
- follow-redirects: 1.16.0
- form-data: 4.0.5
- proxy-from-env: 2.1.0
- transitivePeerDependencies:
- - debug
-
- balanced-match@4.0.4: {}
-
- baseline-browser-mapping@2.10.27: {}
-
- brace-expansion@5.0.6:
- dependencies:
- balanced-match: 4.0.4
-
- browserslist@4.28.2:
- dependencies:
- baseline-browser-mapping: 2.10.27
- caniuse-lite: 1.0.30001792
- electron-to-chromium: 1.5.352
- node-releases: 2.0.38
- 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.30001792: {}
-
- combined-stream@1.0.8:
- dependencies:
- delayed-stream: 1.0.0
-
- convert-source-map@2.0.0: {}
-
- cookie@1.1.1: {}
-
- 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.352: {}
-
- enhanced-resolve@5.21.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.1:
- 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.3
-
- escalade@3.2.0: {}
-
- escape-string-regexp@4.0.0: {}
-
- eslint-plugin-react-hooks@7.1.1(eslint@10.3.0(jiti@2.7.0)):
- dependencies:
- '@babel/core': 7.29.0
- '@babel/parser': 7.29.3
- eslint: 10.3.0(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.3.0(jiti@2.7.0)):
- dependencies:
- eslint: 10.3.0(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.3.0(jiti@2.7.0):
- dependencies:
- '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.7.0))
- '@eslint-community/regexpp': 4.12.2
- '@eslint/config-array': 0.23.5
- '@eslint/config-helpers': 0.5.5
- '@eslint/core': 1.2.1
- '@eslint/plugin-kit': 0.7.1
- '@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.3
- mime-types: 2.1.35
-
- fraction.js@5.3.4: {}
-
- 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.1
- function-bind: 1.1.2
- get-proto: 1.0.1
- gopd: 1.2.0
- has-symbols: 1.1.0
- hasown: 2.0.3
- math-intrinsics: 1.1.0
-
- get-proto@1.0.1:
- dependencies:
- dunder-proto: 1.0.1
- es-object-atoms: 1.1.1
-
- 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.3:
- dependencies:
- function-bind: 1.1.2
-
- hermes-estree@0.25.1: {}
-
- hermes-parser@0.25.1:
- dependencies:
- hermes-estree: 0.25.1
-
- hoist-non-react-statics@3.3.2:
- dependencies:
- react-is: 16.13.1
-
- 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
-
- lucide-react@1.14.0(react@19.2.6):
- dependencies:
- react: 19.2.6
-
- 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.38: {}
-
- 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-value-parser@4.2.0: {}
-
- postcss@8.5.14:
- 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-hook-form@7.75.0(react@19.2.6):
- dependencies:
- react: 19.2.6
-
- react-intersection-observer@10.0.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
- dependencies:
- react: 19.2.6
- optionalDependencies:
- react-dom: 19.2.6(react@19.2.6)
-
- react-is@16.13.1: {}
-
- react-router-dom@7.15.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.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
-
- react-router@7.15.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.0-rc.18:
- dependencies:
- '@oxc-project/types': 0.128.0
- '@rolldown/pluginutils': 1.0.0-rc.18
- optionalDependencies:
- '@rolldown/binding-android-arm64': 1.0.0-rc.18
- '@rolldown/binding-darwin-arm64': 1.0.0-rc.18
- '@rolldown/binding-darwin-x64': 1.0.0-rc.18
- '@rolldown/binding-freebsd-x64': 1.0.0-rc.18
- '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.18
- '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.18
- '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.18
- '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.18
- '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.18
- '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.18
- '@rolldown/binding-linux-x64-musl': 1.0.0-rc.18
- '@rolldown/binding-openharmony-arm64': 1.0.0-rc.18
- '@rolldown/binding-wasm32-wasi': 1.0.0-rc.18
- '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.18
- '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.18
-
- scheduler@0.27.0: {}
-
- semver@6.3.1: {}
-
- semver@7.7.4: {}
-
- set-cookie-parser@2.7.2: {}
-
- shebang-command@2.0.0:
- dependencies:
- shebang-regex: 3.0.0
-
- shebang-regex@3.0.0: {}
-
- source-map-js@1.2.1: {}
-
- styled-components@6.4.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
- dependencies:
- '@emotion/is-prop-valid': 1.4.0
- csstype: 3.2.3
- react: 19.2.6
- stylis: 4.3.6
- optionalDependencies:
- react-dom: 19.2.6(react@19.2.6)
-
- stylis@4.3.6: {}
-
- tailwindcss@4.2.4: {}
-
- tapable@2.3.3: {}
-
- tinyglobby@0.2.16:
- 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.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3):
- dependencies:
- '@typescript-eslint/eslint-plugin': 8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3)
- '@typescript-eslint/parser': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3)
- '@typescript-eslint/typescript-estree': 8.59.2(typescript@6.0.3)
- '@typescript-eslint/utils': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3)
- eslint: 10.3.0(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.11(@types/node@24.12.3)(jiti@2.7.0):
- dependencies:
- lightningcss: 1.32.0
- picomatch: 4.0.4
- postcss: 8.5.14
- rolldown: 1.0.0-rc.18
- tinyglobby: 0.2.16
- optionalDependencies:
- '@types/node': 24.12.3
- 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/UMC-10th-mission-FE/public/favicon.svg b/UMC-10th-mission-FE/public/favicon.svg
deleted file mode 100644
index 6893eb13..00000000
--- a/UMC-10th-mission-FE/public/favicon.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/public/icons.svg b/UMC-10th-mission-FE/public/icons.svg
deleted file mode 100644
index e9522193..00000000
--- a/UMC-10th-mission-FE/public/icons.svg
+++ /dev/null
@@ -1,24 +0,0 @@
-
diff --git a/UMC-10th-mission-FE/src/App.css b/UMC-10th-mission-FE/src/App.css
deleted file mode 100644
index af499fbc..00000000
--- a/UMC-10th-mission-FE/src/App.css
+++ /dev/null
@@ -1,60 +0,0 @@
-.login-container {
- width: 100%;
- max-width: 400px;
- padding: 20px;
- display: flex;
- flex-direction: column;
-}
-
-.login-header {
- display: flex;
- align-items: center;
- margin-bottom: 30px;
-}
-
-.back-button {
- background: none;
- border: none;
- color: white;
- font-size: 24px;
- cursor: pointer;
- margin-right: 10px;
-}
-
-input {
- width: 100%;
- padding: 15px;
- margin-bottom: 10px;
- border-radius: 8px;
- border: 1px solid #333;
- background-color: white;
- box-sizing: border-box;
-}
-
-.error-input {
- border: 2px solid #ff4d4d;
-}
-
-.error-msg {
- color: #ff4d4d;
- font-size: 12px;
- margin-top: -5px;
- margin-bottom: 10px;
-}
-
-.login-submit-btn {
- width: 100%;
- padding: 15px;
- border-radius: 8px;
- border: none;
- background-color: #444; /* 비활성화 상태 */
- color: white;
- font-weight: bold;
- cursor: not-allowed;
-}
-
-/* 유효성 검사 통과 시 활성화 (이미지 속 핑크색) */
-.login-submit-btn.active {
- background-color: #ff2d78;
- cursor: pointer;
-}
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/App.tsx b/UMC-10th-mission-FE/src/App.tsx
deleted file mode 100644
index 01a9ec82..00000000
--- a/UMC-10th-mission-FE/src/App.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-// src/App.tsx
-import "./App.css";
-import {
- createBrowserRouter,
- RouterProvider,
- type RouteObject,
- Outlet,
-} from "react-router-dom";
-import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; // 👈 추가!
-import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; // 👈 추가!
-
-import Home from "./pages/HomePage";
-import NotFoundPage from "./pages/NotFoundPage";
-import LoginPage from "./pages/LoginPage";
-import HomeLayout from "./layouts/HomeLayout";
-import SignUpPage from "./pages/SignupPage";
-import MyPage from "./pages/MyPage";
-import { AuthProvider } from "./context/AuthContext";
-import PrivateLayout from "./layouts/PrivateLayout";
-import GoogleLoginRedirectPage from "./pages/GoogleLoginRedirectPage";
-import LPListPage from "./pages/LPListPage"; // 👈 목록 페이지 임포트
-import LPDetailPage from "./pages/LPDetailPage"; // 👈 (나중에 만들) 상세 페이지 임포트
-import WritePage from "./pages/WritePage";
-
-const queryClient = new QueryClient({
- defaultOptions: {
- queries: {
- retry: 1,
- },
- },
-});
-
-const AppRoot = () => {
- return (
-
-
-
-
- {import.meta.env.DEV && }
-
- );
-};
-
-const routes: RouteObject[] = [
- {
- path: "/",
- element:
,
- errorElement:
,
- children: [
- {
- path: "/",
- element:
,
- children: [
- { index: true, element:
},
- { path: "login", element:
},
- { path: "signup", element:
},
- { path: "v1/auth/google/callback", element:
},
- { path: "lps", element:
},
- { path: "lps/:lpid", element:
},
- {
- element:
,
- children: [
- { path: "mypage", element:
},
- { path: "write", element:
},
- ],
- },
- ],
- },
- ],
- },
-];
-
-const router = createBrowserRouter(routes);
-
-function App() {
- return
;
-}
-
-export default App;
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/apis/auth.ts b/UMC-10th-mission-FE/src/apis/auth.ts
deleted file mode 100644
index 7ae0504c..00000000
--- a/UMC-10th-mission-FE/src/apis/auth.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import axios from "axios";
-import type {
- ReqSignInDto,
- ReqSignUpDto,
- ReqUpdateProfileDto,
- ResMyInfoDto,
- ResSignInDto,
- ResSignUpDto,
-} from "../types/auth";
-import { axiosInstance } from "./axios";
-
-const BASE_URL = import.meta.env.VITE_API_BASE_URL;
-
-// 회원가입 (토큰 불필요 → 기본 axios)
-export const postSignup = async (body: ReqSignUpDto): Promise
=> {
- const { data } = await axios.post(`${BASE_URL}/v1/auth/signup`, body);
- return data;
-};
-
-// 로그인 (토큰 불필요 → 기본 axios)
-export const postSignin = async (body: ReqSignInDto): Promise => {
- const { data } = await axios.post(`${BASE_URL}/v1/auth/signin`, body);
- return data;
-};
-
-// 내 정보 조회 (토큰 필요 → axiosInstance 사용, Hook 규칙 위반 제거)
-export const getMyInfo = async (): Promise => {
- const { data } = await axiosInstance.get("/v1/users/me");
- return data;
-};
-
-// 로그아웃 (서버에 알림, 토큰 필요할 수 있음 → axiosInstance)
-export const postLogout = async () => {
- const { data } = await axiosInstance.post("/v1/auth/signout");
- return data;
-};
-
-// 회원 탈퇴
-export const deleteMyAccount = async () => {
- const { data } = await axiosInstance.delete("/v1/users/me");
- return data;
-};
-
-// 프로필 수정
-// - name, bio는 항상 전송 (bio 빈 문자열 → 서버에서 초기화)
-// - avatar는 새 파일을 선택했을 때만 포함 (없으면 기존 이미지 유지)
-export const patchMyProfile = async (
- body: ReqUpdateProfileDto
-): Promise => {
- const formData = new FormData();
- formData.append("name", body.name);
- formData.append("bio", body.bio);
- if (body.avatar) formData.append("avatar", body.avatar);
-
- const { data } = await axiosInstance.patch("/v1/users/me", formData, {
- headers: { "Content-Type": "multipart/form-data" },
- });
- return data;
-};
diff --git a/UMC-10th-mission-FE/src/apis/axios.ts b/UMC-10th-mission-FE/src/apis/axios.ts
deleted file mode 100644
index 876bbce5..00000000
--- a/UMC-10th-mission-FE/src/apis/axios.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-import axios, { type InternalAxiosRequestConfig } from "axios";
-import { LOCAL_STORAGE_KEY } from "../constants/key";
-
-interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig {
- _retry?: boolean;
-}
-
-let refreshPromise: Promise | null = null;
-
-// 환경변수를 하나로 통일 (VITE_API_BASE_URL)
-const BASE_URL = import.meta.env.VITE_API_BASE_URL;
-
-export const axiosInstance = axios.create({
- baseURL: import.meta.env.VITE_API_BASE_URL || "http://localhost:8080",
-});
-
-// 요청 인터셉터: 모든 요청에 액세스 토큰 자동 첨부
-axiosInstance.interceptors.request.use(
- (config) => {
- const token = localStorage.getItem(LOCAL_STORAGE_KEY.ACCESS_TOKEN);
- if (token) {
- config.headers.Authorization = `Bearer ${token}`;
- }
- return config;
- },
- (err) => Promise.reject(err)
-);
-
-// 응답 인터셉터: 401 발생 시 토큰 자동 갱신
-axiosInstance.interceptors.response.use(
- (res) => res,
- async (err) => {
- const originalRequest = err.config as CustomAxiosRequestConfig;
-
- if (
- err.response?.status === 401 &&
- !originalRequest._retry &&
- !originalRequest.url?.includes("/v1/auth/refresh")
- ) {
- originalRequest._retry = true;
-
- if (!refreshPromise) {
- refreshPromise = axios
- .post(`${BASE_URL}/v1/auth/refresh`, {
- refreshToken: localStorage.getItem(LOCAL_STORAGE_KEY.REFRESH_TOKEN),
- })
- .then(({ data }) => {
- const { accessToken: newAccess, refreshToken: newRefresh } =
- data.data;
- localStorage.setItem(LOCAL_STORAGE_KEY.ACCESS_TOKEN, newAccess);
- localStorage.setItem(LOCAL_STORAGE_KEY.REFRESH_TOKEN, newRefresh);
- return newAccess;
- })
- .catch((refreshErr) => {
- localStorage.removeItem(LOCAL_STORAGE_KEY.ACCESS_TOKEN);
- localStorage.removeItem(LOCAL_STORAGE_KEY.REFRESH_TOKEN);
- window.location.href = "/login";
- return Promise.reject(refreshErr);
- })
- .finally(() => {
- refreshPromise = null;
- });
- }
-
- return refreshPromise.then((newAccessToken) => {
- originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
- return axiosInstance.request(originalRequest);
- });
- }
-
- return Promise.reject(err);
- }
-);
diff --git a/UMC-10th-mission-FE/src/apis/lp.ts b/UMC-10th-mission-FE/src/apis/lp.ts
deleted file mode 100644
index 22b099ed..00000000
--- a/UMC-10th-mission-FE/src/apis/lp.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-import { axiosInstance } from "./axios";
-import type {
- CreateLpResponse,
- GetLpsResponse,
- LpDetailResponse,
- ReqCreateCommentDto,
- ReqCreateLpDto,
- ReqUpdateCommentDto,
- ReqUpdateLpDto,
-} from "../types/lp";
-
-// 이름을 getLps로 통일 (query hook과 일치)
-export const getLps = async (
- sort: "latest" | "oldest" = "latest",
- cursor: number = 0
-): Promise => {
- const { data } = await axiosInstance.get("/v1/lps", {
- params: { sort, cursor, limit: 10 },
- });
- return data;
-};
-
-export const getLpDetail = async (id: number): Promise => {
- const { data } = await axiosInstance.get(`/v1/lps/${id}`);
- return data;
-};
-
-export const getLpComments = async (
- lpId: number,
- order: "latest" | "oldest" = "latest",
- cursor: number = 0
-) => {
- const { data } = await axiosInstance.get(`/v1/lps/${lpId}/comments`, {
- params: { order, cursor, limit: 10 },
- });
- return data;
-};
-
-export const postComment = async (lpId: number, body: ReqCreateCommentDto) => {
- const { data } = await axiosInstance.post(`/v1/lps/${lpId}/comments`, body);
- return data;
-};
-
-export const patchComment = async (
- lpId: number,
- commentId: number,
- body: ReqUpdateCommentDto
-) => {
- const { data } = await axiosInstance.patch(
- `/v1/lps/${lpId}/comments/${commentId}`,
- body
- );
- return data;
-};
-
-export const deleteComment = async (lpId: number, commentId: number) => {
- const { data } = await axiosInstance.delete(
- `/v1/lps/${lpId}/comments/${commentId}`
- );
- return data;
-};
-
-const buildLpFormData = (body: ReqCreateLpDto | ReqUpdateLpDto): FormData => {
- const formData = new FormData();
- formData.append("title", body.title);
- formData.append("content", body.content);
- if (body.thumbnail) formData.append("thumbnail", body.thumbnail);
- body.tags.forEach((tag) => formData.append("tags", tag));
- return formData;
-};
-
-export const postLp = async (body: ReqCreateLpDto): Promise => {
- const { data } = await axiosInstance.post("/v1/lps", buildLpFormData(body), {
- headers: { "Content-Type": "multipart/form-data" },
- });
- return data;
-};
-
-export const patchLp = async (
- id: number,
- body: ReqUpdateLpDto
-): Promise => {
- const { data } = await axiosInstance.patch(`/v1/lps/${id}`, buildLpFormData(body), {
- headers: { "Content-Type": "multipart/form-data" },
- });
- return data;
-};
-
-export const deleteLp = async (id: number) => {
- const { data } = await axiosInstance.delete(`/v1/lps/${id}`);
- return data;
-};
-
-export const postLpLike = async (id: number) => {
- const { data } = await axiosInstance.post(`/v1/lps/${id}/likes`);
- return data;
-};
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/assets/hero.png b/UMC-10th-mission-FE/src/assets/hero.png
deleted file mode 100644
index 02251f4b..00000000
Binary files a/UMC-10th-mission-FE/src/assets/hero.png and /dev/null differ
diff --git a/UMC-10th-mission-FE/src/assets/react.svg b/UMC-10th-mission-FE/src/assets/react.svg
deleted file mode 100644
index 6c87de9b..00000000
--- a/UMC-10th-mission-FE/src/assets/react.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/assets/vite.svg b/UMC-10th-mission-FE/src/assets/vite.svg
deleted file mode 100644
index 5101b674..00000000
--- a/UMC-10th-mission-FE/src/assets/vite.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/UMC-10th-mission-FE/src/components/CommentSection.tsx b/UMC-10th-mission-FE/src/components/CommentSection.tsx
deleted file mode 100644
index bfc4415c..00000000
--- a/UMC-10th-mission-FE/src/components/CommentSection.tsx
+++ /dev/null
@@ -1,258 +0,0 @@
-import { useState, useEffect } from "react";
-import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { useInView } from "react-intersection-observer";
-import { MoreVertical } from "lucide-react";
-import { useGetLpComments } from "../hooks/useGetLpComments";
-import { useGetMyInfo } from "../hooks/useGetMyInfo";
-import { useAuth } from "../context/AuthContext";
-import { postComment, patchComment, deleteComment } from "../apis/lp";
-import type { Comment } from "../types/lp";
-
-const CommentSkeleton = () => (
-
-);
-
-interface CommentSectionProps {
- lpId: string;
-}
-
-const CommentSection = ({ lpId }: CommentSectionProps) => {
- const queryClient = useQueryClient();
- const { accessToken } = useAuth();
- const { data: myInfo } = useGetMyInfo(accessToken);
- const myId = myInfo?.data?.id;
-
- const [order, setOrder] = useState<"latest" | "oldest">("latest");
- const [commentText, setCommentText] = useState("");
- const [openMenuId, setOpenMenuId] = useState(null);
- const [editingId, setEditingId] = useState(null);
- const [editText, setEditText] = useState("");
-
- const { ref, inView } = useInView();
-
- const {
- data: commentsData,
- isPending: isCommentsPending,
- fetchNextPage,
- hasNextPage,
- isFetchingNextPage,
- } = useGetLpComments(lpId, order);
-
- useEffect(() => {
- if (inView && hasNextPage && !isFetchingNextPage) fetchNextPage();
- }, [inView, hasNextPage, isFetchingNextPage, fetchNextPage]);
-
- // 외부 클릭 시 메뉴 닫기
- useEffect(() => {
- const handler = () => setOpenMenuId(null);
- document.addEventListener("click", handler);
- return () => document.removeEventListener("click", handler);
- }, []);
-
- const commentsList: Comment[] =
- commentsData?.pages.flatMap((page) => page.data.data) ?? [];
-
- // 댓글 작성
- const { mutate: createComment, isPending: isCreating } = useMutation({
- mutationFn: (content: string) => postComment(Number(lpId), { content }),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["lpComments", lpId] });
- setCommentText("");
- },
- });
-
- // 댓글 수정
- const { mutate: updateComment, isPending: isUpdating } = useMutation({
- mutationFn: ({ commentId, content }: { commentId: number; content: string }) =>
- patchComment(Number(lpId), commentId, { content }),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["lpComments", lpId] });
- setEditingId(null);
- },
- });
-
- // 댓글 삭제
- const { mutate: removeComment } = useMutation({
- mutationFn: (commentId: number) => deleteComment(Number(lpId), commentId),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["lpComments", lpId] });
- },
- });
-
- return (
-
-
-
- 댓글 ({commentsList.length})
-
-
-
-
- {/* 댓글 작성란 */}
-
-
- {/* 초기 로딩 스켈레톤 */}
- {isCommentsPending ? (
-
-
-
-
-
- ) : commentsList.length === 0 ? (
-
- 아직 작성된 댓글이 없습니다. 첫 댓글의 주인공이 되어보세요!
-
- ) : (
-
- {commentsList.map((comment) => (
-
-
-
-
- {comment.author?.name || "익명"}
-
-
- {comment.createdAt
- ? new Date(comment.createdAt).toLocaleDateString()
- : ""}
-
-
-
- {/* 본인 댓글에만 ... 메뉴 표시 */}
- {myId === comment.author?.id && (
-
-
-
- {openMenuId === comment.id && (
-
e.stopPropagation()}
- className="absolute right-0 top-7 w-24 bg-[#2a2a2a] border border-[#444] rounded-lg overflow-hidden z-10 shadow-lg"
- >
-
-
-
- )}
-
- )}
-
-
- {/* 수정 모드 vs 읽기 모드 */}
- {editingId === comment.id ? (
-
- ) : (
-
{comment.content}
- )}
-
- ))}
-
- )}
-
- {/* 추가 로딩 스켈레톤 */}
- {isFetchingNextPage && (
-
-
-
-
- )}
-
- {/* 무한스크롤 트리거 */}
-
-
- );
-};
-
-export default CommentSection;
diff --git a/UMC-10th-mission-FE/src/components/ConfirmModal.tsx b/UMC-10th-mission-FE/src/components/ConfirmModal.tsx
deleted file mode 100644
index 39d2aafa..00000000
--- a/UMC-10th-mission-FE/src/components/ConfirmModal.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-import { useEffect, useRef } from "react";
-import { X } from "lucide-react";
-
-interface ConfirmModalProps {
- message: string;
- confirmLabel?: string;
- cancelLabel?: string;
- isPending?: boolean;
- onConfirm: () => void;
- onCancel: () => void;
-}
-
-const ConfirmModal = ({
- message,
- confirmLabel = "예",
- cancelLabel = "아니오",
- isPending = false,
- onConfirm,
- onCancel,
-}: ConfirmModalProps) => {
- const backdropRef = useRef(null);
-
- useEffect(() => {
- const handler = (e: globalThis.KeyboardEvent) => {
- if (e.key === "Escape") onCancel();
- };
- window.addEventListener("keydown", handler);
- return () => window.removeEventListener("keydown", handler);
- }, [onCancel]);
-
- return (
- { if (e.target === backdropRef.current) onCancel(); }}
- className="fixed inset-0 bg-black/70 z-[60] flex items-center justify-center"
- >
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default ConfirmModal;
diff --git a/UMC-10th-mission-FE/src/components/EditProfileModal.tsx b/UMC-10th-mission-FE/src/components/EditProfileModal.tsx
deleted file mode 100644
index 8db34a88..00000000
--- a/UMC-10th-mission-FE/src/components/EditProfileModal.tsx
+++ /dev/null
@@ -1,198 +0,0 @@
-import { useState, useEffect, type ChangeEvent } from "react";
-import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { X } from "lucide-react";
-import { patchMyProfile } from "../apis/auth";
-import type { ResMyInfoDto } from "../types/auth";
-
-interface EditProfileModalProps {
- userInfo: ResMyInfoDto["data"];
- onClose: () => void;
-}
-
-const EditProfileModal = ({ userInfo, onClose }: EditProfileModalProps) => {
- const queryClient = useQueryClient();
-
- const [name, setName] = useState(userInfo.name);
- const [bio, setBio] = useState(userInfo.bio ?? "");
- const [avatarFile, setAvatarFile] = useState(undefined);
- const [avatarPreview, setAvatarPreview] = useState(
- userInfo.avatar ?? null
- );
-
- useEffect(() => {
- const handler = (e: globalThis.KeyboardEvent) => {
- if (e.key === "Escape") onClose();
- };
- window.addEventListener("keydown", handler);
- return () => window.removeEventListener("keydown", handler);
- }, [onClose]);
-
- const handleAvatarChange = (e: ChangeEvent) => {
- const file = e.target.files?.[0];
- if (!file) return;
- if (avatarPreview && avatarPreview !== userInfo.avatar)
- URL.revokeObjectURL(avatarPreview);
- setAvatarFile(file);
- setAvatarPreview(URL.createObjectURL(file));
- };
-
- const { mutate: updateProfile, isPending } = useMutation({
- mutationFn: patchMyProfile,
- onMutate: async (variables) => {
- // 진행 중인 내 정보 쿼리 취소 (race condition 방지)
- await queryClient.cancelQueries({ queryKey: ["user", "me"] });
-
- // 롤백용 스냅샷 저장
- const previousData = queryClient.getQueryData(["user", "me"]);
-
- // 서버 응답 전에 UI 즉시 반영
- queryClient.setQueryData(["user", "me"], (old) => {
- if (!old) return old;
- return {
- ...old,
- data: {
- ...old.data,
- name: variables.name,
- bio: variables.bio || null,
- },
- };
- });
-
- return { previousData };
- },
- onError: (_error, _variables, context) => {
- // 요청 실패 시 스냅샷으로 롤백
- if (context?.previousData) {
- queryClient.setQueryData(["user", "me"], context.previousData);
- }
- },
- onSuccess: () => {
- onClose();
- },
- onSettled: () => {
- // 성공·실패 무관하게 서버 최신 데이터로 동기화
- queryClient.invalidateQueries({ queryKey: ["user", "me"] });
- },
- });
-
- const handleSubmit = () => {
- if (!name.trim()) return;
- updateProfile({
- name: name.trim(),
- bio, // 빈 문자열도 그대로 전송 → bio 초기화 허용
- avatar: avatarFile, // 선택 안 했으면 undefined → 서버에서 기존 유지
- });
- };
-
- return (
-
-
e.stopPropagation()}
- >
- {/* Header */}
-
-
프로필 수정
-
-
-
- {/* Avatar */}
-
-
-
- 클릭해서 사진 변경 (선택 사항)
-
-
-
- {/* Name */}
-
-
- setName(e.target.value)}
- placeholder="이름을 입력하세요"
- className="bg-[#111] text-white border border-[#333] rounded-lg px-3 py-2 text-sm placeholder-gray-600 focus:outline-none focus:border-[#FF1493] transition-colors"
- />
-
-
- {/* Bio */}
-
-
-
-
- {/* Buttons */}
-
-
-
-
-
-
- );
-};
-
-export default EditProfileModal;
diff --git a/UMC-10th-mission-FE/src/components/EditProfileModel.tsx b/UMC-10th-mission-FE/src/components/EditProfileModel.tsx
deleted file mode 100644
index 59899d5e..00000000
--- a/UMC-10th-mission-FE/src/components/EditProfileModel.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-// EditProfileModal 구조 예시
-interface EditProfileModalProps {
- userInfo: { name: string; email: string; avatar?: string; bio?: string };
- onClose: () => void;
- onSave: (newNickname: string) => void; // 👈 새로 추가된 프롭스
- isSubmitting: boolean;
-}
-
-const EditProfileModal = ({ userInfo, onClose, onSave, isSubmitting }: EditProfileModalProps) => {
- const [nickname, setNickname] = useState(userInfo.name);
-
- const handleSubmit = (e: React.FormEvent) => {
- e.preventDefault(); // 폼 제출 시 페이지 새로고침 방지 (초요구사항)
- if (!nickname.trim()) return;
-
- onSave(nickname); // 마이페이지에 있는 낙관적 업데이트 Mutation 작동!
- };
-
- return (
-
- );
-};
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/components/LpCardSkeleton.tsx b/UMC-10th-mission-FE/src/components/LpCardSkeleton.tsx
deleted file mode 100644
index 7dc2e594..00000000
--- a/UMC-10th-mission-FE/src/components/LpCardSkeleton.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-// src/components/LpCardSkeleton.tsx
-export const LpCardSkeleton = () => {
- return (
-
- {/* 썸네일 뼈대 */}
-
- {/* 제목 뼈대 */}
-
-
- );
-};
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/components/LpWriteModal.tsx b/UMC-10th-mission-FE/src/components/LpWriteModal.tsx
deleted file mode 100644
index e27b423c..00000000
--- a/UMC-10th-mission-FE/src/components/LpWriteModal.tsx
+++ /dev/null
@@ -1,241 +0,0 @@
-import {
- useState,
- useRef,
- useEffect,
- type ChangeEvent,
- type KeyboardEvent,
-} from "react";
-import { X } from "lucide-react";
-import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { postLp, patchLp } from "../apis/lp";
-
-interface InitialData {
- title: string;
- content: string;
- thumbnail?: string | null;
- tags: string[];
-}
-
-interface LpWriteModalProps {
- onClose: () => void;
- mode?: "create" | "edit";
- lpId?: number;
- initialData?: InitialData;
-}
-
-const LpWriteModal = ({
- onClose,
- mode = "create",
- lpId,
- initialData,
-}: LpWriteModalProps) => {
- const queryClient = useQueryClient();
-
- const [title, setTitle] = useState(initialData?.title ?? "");
- const [content, setContent] = useState(initialData?.content ?? "");
- // 수정 모드: 기존 URL로 미리보기, 새 파일 선택 전까지 File은 null
- const [thumbnailFile, setThumbnailFile] = useState(null);
- const [imagePreview, setImagePreview] = useState(
- initialData?.thumbnail ?? null
- );
- const [tags, setTags] = useState(initialData?.tags ?? []);
- const [tagInput, setTagInput] = useState("");
-
- const backdropRef = useRef(null);
-
- useEffect(() => {
- const handleKeyDown = (e: globalThis.KeyboardEvent) => {
- if (e.key === "Escape") onClose();
- };
- window.addEventListener("keydown", handleKeyDown);
- return () => window.removeEventListener("keydown", handleKeyDown);
- }, [onClose]);
-
- const handleBackdropClick = (e: React.MouseEvent) => {
- if (e.target === backdropRef.current) onClose();
- };
-
- const handleImageChange = (e: ChangeEvent) => {
- const file = e.target.files?.[0];
- if (!file) return;
- // blob URL인 경우에만 revoke (http URL은 revoke 불필요)
- if (imagePreview?.startsWith("blob:")) URL.revokeObjectURL(imagePreview);
- setThumbnailFile(file);
- setImagePreview(URL.createObjectURL(file));
- };
-
- const addTag = () => {
- const trimmed = tagInput.trim();
- if (trimmed && !tags.includes(trimmed)) {
- setTags((prev) => [...prev, trimmed]);
- }
- setTagInput("");
- };
-
- const removeTag = (target: string) => {
- setTags((prev) => prev.filter((t) => t !== target));
- };
-
- const handleTagKeyDown = (e: KeyboardEvent) => {
- if (e.key === "Enter") {
- e.preventDefault();
- addTag();
- }
- };
-
- const isEdit = mode === "edit" && lpId !== undefined;
-
- const { mutate: saveLp, isPending } = useMutation({
- mutationFn: (body: { title: string; content: string; thumbnail: File | null; tags: string[] }) =>
- isEdit
- ? patchLp(lpId!, { ...body, thumbnail: body.thumbnail ?? null })
- : postLp({ ...body, thumbnail: body.thumbnail ?? null }),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["lps"] });
- if (isEdit) {
- queryClient.invalidateQueries({ queryKey: ["lp", String(lpId)] });
- }
- onClose();
- },
- });
-
- const handleSubmit = () => {
- if (!title.trim()) return;
- saveLp({ title: title.trim(), content: content.trim(), thumbnail: thumbnailFile, tags });
- };
-
- return (
-
-
- {/* Header */}
-
-
- {isEdit ? "LP 수정" : "새 LP 등록"}
-
-
-
-
- {/* Image upload */}
-
-
LP 사진
-
-
-
- {/* Title */}
-
-
- setTitle(e.target.value)}
- placeholder="LP 제목을 입력하세요"
- className="bg-[#111] text-white border border-[#333] rounded-lg px-3 py-2 text-sm placeholder-gray-600 focus:outline-none focus:border-[#FF1493] transition-colors"
- />
-
-
- {/* Content */}
-
-
-
-
- {/* Tag input */}
-
-
태그
-
- setTagInput(e.target.value)}
- onKeyDown={handleTagKeyDown}
- placeholder="태그 입력 후 추가 또는 엔터"
- className="flex-1 bg-[#111] text-white border border-[#333] rounded-lg px-3 py-2 text-sm placeholder-gray-600 focus:outline-none focus:border-[#FF1493] transition-colors"
- />
-
-
-
- {tags.length > 0 && (
-
- {tags.map((tag) => (
-
- #{tag}
-
-
- ))}
-
- )}
-
-
- {/* Submit */}
-
-
-
- );
-};
-
-export default LpWriteModal;
diff --git a/UMC-10th-mission-FE/src/constants/key.ts b/UMC-10th-mission-FE/src/constants/key.ts
deleted file mode 100644
index 93fadd58..00000000
--- a/UMC-10th-mission-FE/src/constants/key.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export const LOCAL_STORAGE_KEY = {
- ACCESS_TOKEN: "accessToken",
- REFRESH_TOKEN: "refreshToken",
-} as const;
diff --git a/UMC-10th-mission-FE/src/context/AuthContext.tsx b/UMC-10th-mission-FE/src/context/AuthContext.tsx
deleted file mode 100644
index 64d224f3..00000000
--- a/UMC-10th-mission-FE/src/context/AuthContext.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import {
- createContext,
- useState,
- useContext,
- type PropsWithChildren,
-} from "react";
-import { postSignin, postLogout } from "../apis/auth";
-import { LOCAL_STORAGE_KEY } from "../constants/key";
-import { useLocalStorage } from "../hooks/useLocalStorage";
-import type { ReqSignInDto } from "../types/auth";
-
-interface AuthContextType {
- accessToken: string | null;
- login: (signInData: ReqSignInDto) => Promise;
- logout: () => Promise;
- clearAuth: () => void;
-}
-
-const AuthContext = createContext(null);
-
-export const AuthProvider = ({ children }: PropsWithChildren) => {
- const {
- getItem: getAccessToken,
- setItem: setAccessTokenStorage,
- removeItem: removeAccessToken,
- } = useLocalStorage(LOCAL_STORAGE_KEY.ACCESS_TOKEN);
-
- const {
- setItem: setRefreshTokenStorage,
- removeItem: removeRefreshToken,
- } = useLocalStorage(LOCAL_STORAGE_KEY.REFRESH_TOKEN);
-
- const [accessToken, setAccessToken] = useState(
- getAccessToken()
- );
-
- const login = async (signInData: ReqSignInDto) => {
- // 에러를 호출부로 전파하여 UI에서 처리할 수 있도록 try/catch 제거
- const response = await postSignin(signInData);
- const { accessToken: newAccess, refreshToken: newRefresh } = response.data;
-
- setAccessTokenStorage(newAccess);
- setRefreshTokenStorage(newRefresh);
- setAccessToken(newAccess);
- };
-
- const logout = async () => {
- try {
- await postLogout();
- } catch (err) {
- // 서버 로그아웃 실패해도 클라이언트는 정리
- console.error("서버 로그아웃 실패:", err);
- } finally {
- removeAccessToken();
- removeRefreshToken();
- setAccessToken(null);
- }
- };
-
- const clearAuth = () => {
- removeAccessToken();
- removeRefreshToken();
- setAccessToken(null);
- };
-
- return (
-
- {children}
-
- );
-};
-
-export const useAuth = () => {
- const context = useContext(AuthContext);
- if (!context) {
- throw new Error("useAuth는 AuthProvider 안에서만 사용할 수 있습니다.");
- }
- return context;
-};
diff --git a/UMC-10th-mission-FE/src/hooks/useForm.ts b/UMC-10th-mission-FE/src/hooks/useForm.ts
deleted file mode 100644
index 56eda62a..00000000
--- a/UMC-10th-mission-FE/src/hooks/useForm.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { useEffect, useState, type ChangeEvent } from "react";
-
-interface UseFormProps {
- init_val: T;
- validate: (values: T) => Record;
-}
-
-function useForm>({
- init_val,
- validate,
-}: UseFormProps) {
- const [values, setValues] = useState(init_val);
- const [touched, setTouched] = useState>({});
- const [errors, setErrors] = useState>({});
-
- const handleChange = (name: keyof T, text: string) => {
- setValues((prev) => ({ ...prev, [name]: text }));
- };
-
- const handleBlur = (name: keyof T) => {
- setTouched((prev) => ({ ...prev, [name]: true }));
- };
-
- const getInputProps = (name: keyof T) => {
- return {
- value: values[name] as string,
- onChange: (e: ChangeEvent) => {
- handleChange(name, e.target.value);
- },
- onBlur: () => {
- handleBlur(name);
- },
- };
- };
-
- useEffect(() => {
- setErrors(validate(values));
- }, [values]); // validate를 deps에서 제거 - 매 렌더마다 새 함수 참조로 무한루프 방지
-
- return { values, errors, touched, getInputProps };
-}
-
-export default useForm;
diff --git a/UMC-10th-mission-FE/src/hooks/useGetLPDetail.ts b/UMC-10th-mission-FE/src/hooks/useGetLPDetail.ts
deleted file mode 100644
index a534e33f..00000000
--- a/UMC-10th-mission-FE/src/hooks/useGetLPDetail.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-// src/hooks/useGetLpDetail.ts
-import { useQuery } from "@tanstack/react-query";
-import { getLpDetail } from "../apis/lp"; // 👈 경로가 맞는지 확인해줘!
-
-export const useGetLpDetail = (lpid: string | undefined) => {
- return useQuery({
- // 💡 퀄리 키에 lpid를 넣어야 "1번 LP"랑 "2번 LP"를 헷갈리지 않아!
- queryKey: ["lp", lpid],
- queryFn: () => getLpDetail(Number(lpid)),
- enabled: !!lpid, // lpid가 있을 때만 비서가 출발하도록 설정!
- staleTime: 1000 * 60 * 5, // 5분 동안은 신선하게 유지
- });
-};
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/hooks/useGetLpComments.ts b/UMC-10th-mission-FE/src/hooks/useGetLpComments.ts
deleted file mode 100644
index cd56895f..00000000
--- a/UMC-10th-mission-FE/src/hooks/useGetLpComments.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-// src/hooks/useGetLpComments.ts
-import { useInfiniteQuery } from "@tanstack/react-query";
-import { getLpComments } from "../apis/lp";
-
-export const useGetLpComments = (lpId: string | undefined, order: "latest" | "oldest") => {
- return useInfiniteQuery({
- // 💡 [체크리스트 달성] queryKey에 lpId와 order 포함! (정렬 바뀌면 알아서 리패치)
- queryKey: ['lpComments', lpId, order],
- queryFn: ({ pageParam = 0 }) => getLpComments(Number(lpId), order, pageParam),
- initialPageParam: 0,
- getNextPageParam: (lastPage) => {
- // 서버에서 다음 댓글이 있다고 하면 다음 커서를 반환!
- return lastPage?.data?.hasNext ? lastPage.data.cursor : undefined;
- },
- enabled: !!lpId, // lpId가 있을 때만 작동!
- });
-};
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/hooks/useGetLpList.ts b/UMC-10th-mission-FE/src/hooks/useGetLpList.ts
deleted file mode 100644
index 789ffb7f..00000000
--- a/UMC-10th-mission-FE/src/hooks/useGetLpList.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { useInfiniteQuery } from "@tanstack/react-query";
-import { getLps } from "../apis/lp";
-
-export const useGetLpList = (sort: "latest" | "oldest" = "latest") => {
- return useInfiniteQuery({
- queryKey: ["lps", sort], // 정렬 기준이 바뀌면 새로 캐싱
- queryFn: ({ pageParam = 0 }) => getLps(sort, pageParam), // pageParam이 바로 cursor 역할!
- initialPageParam: 0, // 첫 시작 커서는 0번
- getNextPageParam: (lastPage) => {
- // 💡 서버에서 "다음 데이터 있어!(hasNext)"라고 하면 다음 커서 번호를 주고, 없으면 undefined!
- return lastPage.data.hasNext ? (lastPage.data.cursor ?? undefined) : undefined;
- },
- staleTime: 1000 * 60,
- gcTime: 1000 * 60 * 5,
- });
-};
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/hooks/useGetMyInfo.ts b/UMC-10th-mission-FE/src/hooks/useGetMyInfo.ts
deleted file mode 100644
index 4f2b4275..00000000
--- a/UMC-10th-mission-FE/src/hooks/useGetMyInfo.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-// src/hooks/useGetMyInfo.ts
-import { useQuery } from "@tanstack/react-query";
-import { getMyInfo } from "../apis/auth";
-
-export const useGetMyInfo = (accessToken: string | null) => {
- return useQuery({
- queryKey: ["user", "me"],
- queryFn: getMyInfo,
- enabled: !!accessToken,
- staleTime: 1000 * 60 * 60,
- });
-};
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/hooks/useLocalStorage.ts b/UMC-10th-mission-FE/src/hooks/useLocalStorage.ts
deleted file mode 100644
index b7edc4aa..00000000
--- a/UMC-10th-mission-FE/src/hooks/useLocalStorage.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-export const useLocalStorage = (key: string) => {
- const setItem = (value: unknown) => {
- try {
- const valueToStore =
- typeof value === "string" ? value : JSON.stringify(value);
- localStorage.setItem(key, valueToStore);
- } catch (err) {
- console.error(err);
- }
- };
-
- const getItem = (): string | null => {
- try {
- const item = localStorage.getItem(key);
- if (!item) return null;
- try {
- return JSON.parse(item);
- } catch {
- return item;
- }
- } catch (err) {
- console.error(err);
- return null;
- }
- };
-
- const removeItem = () => {
- try {
- localStorage.removeItem(key);
- } catch (err) {
- console.error(err);
- }
- };
-
- return { setItem, getItem, removeItem };
-};
diff --git a/UMC-10th-mission-FE/src/imgs/google.png b/UMC-10th-mission-FE/src/imgs/google.png
deleted file mode 100644
index f1afa00e..00000000
Binary files a/UMC-10th-mission-FE/src/imgs/google.png and /dev/null differ
diff --git a/UMC-10th-mission-FE/src/index.css b/UMC-10th-mission-FE/src/index.css
deleted file mode 100644
index cc90b88b..00000000
--- a/UMC-10th-mission-FE/src/index.css
+++ /dev/null
@@ -1,36 +0,0 @@
-@import "tailwindcss";
-
-html, body {
- background-color: #0f1014 !important;
- color: white !important;
- margin: 0;
- padding: 0;
- width: 100%;
- height: 100%;
-}
-
-body {
- display: flex;
- justify-content: center;
- align-items: center;
- width: 100%;
- min-height: 100vh;
- font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, system-ui, Roboto, 'Helvetica Neue', 'Segoe UI', 'Apple SD Gothic Neo', 'Noto Sans KR', 'Malgun Gothic', sans-serif;
-}
-
-#root {
- width: 100%;
- min-height: 100vh;
- display: flex;
- justify-content: center;
- flex-direction: column;
-}
-
-a {
- color: inherit;
- text-decoration: none;
-}
-
-button {
- cursor: pointer;
-}
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/layouts/HomeLayout.tsx b/UMC-10th-mission-FE/src/layouts/HomeLayout.tsx
deleted file mode 100644
index 7dabc4f8..00000000
--- a/UMC-10th-mission-FE/src/layouts/HomeLayout.tsx
+++ /dev/null
@@ -1,164 +0,0 @@
-// src/layouts/HomeLayout.tsx
-import { useState } from "react";
-import { Outlet, useNavigate } from "react-router-dom";
-import { useMutation } from "@tanstack/react-query";
-import { useAuth } from "../context/AuthContext";
-import { useGetMyInfo } from "../hooks/useGetMyInfo";
-import { postLogout, deleteMyAccount } from "../apis/auth";
-import LpWriteModal from "../components/LpWriteModal";
-import ConfirmModal from "../components/ConfirmModal";
-
-export default function HomeLayout() {
- const navigate = useNavigate();
- const { accessToken, clearAuth } = useAuth();
- const { data: userInfo } = useGetMyInfo(accessToken);
-
- const [isSidebarOpen, setIsSidebarOpen] = useState(false);
- const [isWriteModalOpen, setIsWriteModalOpen] = useState(false);
- const [isWithdrawModalOpen, setIsWithdrawModalOpen] = useState(false);
-
- // 로그아웃: API 호출 후 클라이언트 상태 초기화
- const { mutate: handleLogout, isPending: isLoggingOut } = useMutation({
- mutationFn: postLogout,
- onSettled: () => {
- // 성공/실패 무관하게 항상 토큰 삭제 후 홈으로
- clearAuth();
- navigate("/");
- },
- });
-
- // 회원 탈퇴: API 호출 성공 시만 상태 초기화
- const { mutate: handleWithdraw, isPending: isWithdrawing } = useMutation({
- mutationFn: deleteMyAccount,
- onSuccess: () => {
- clearAuth();
- navigate("/login");
- },
- });
-
- return (
-
-
- {/* --- 상단 네비게이션 헤더 --- */}
-
-
-
- {/* 사이드바 백드롭 (모바일) */}
- {isSidebarOpen && (
-
setIsSidebarOpen(false)}
- />
- )}
-
- {/* --- 사이드바 --- */}
-
-
- {/* --- 메인 콘텐츠 --- */}
-
-
-
-
-
- {/* --- 우측 하단 플로팅 버튼 (+) --- */}
-
-
- {isWriteModalOpen && (
-
setIsWriteModalOpen(false)} />
- )}
-
- {isWithdrawModalOpen && (
- handleWithdraw()}
- onCancel={() => setIsWithdrawModalOpen(false)}
- />
- )}
-
- );
-}
diff --git a/UMC-10th-mission-FE/src/layouts/PrivateLayout.tsx b/UMC-10th-mission-FE/src/layouts/PrivateLayout.tsx
deleted file mode 100644
index 5d44360e..00000000
--- a/UMC-10th-mission-FE/src/layouts/PrivateLayout.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Navigate, Outlet } from "react-router-dom";
-import { useAuth } from "../context/AuthContext";
-
-const PrivateLayout = () => {
- const { accessToken } = useAuth();
-
- if (!accessToken) {
- return
;
- }
-
- return
;
-};
-
-export default PrivateLayout;
diff --git a/UMC-10th-mission-FE/src/layouts/ProtectedLayout.tsx b/UMC-10th-mission-FE/src/layouts/ProtectedLayout.tsx
deleted file mode 100644
index dfd03564..00000000
--- a/UMC-10th-mission-FE/src/layouts/ProtectedLayout.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { useAuth } from "../context/AuthContext";
-import { Navigate, Outlet } from "react-router-dom";
-
-export const ProtectedLayout = () => {
- const { accessToken } = useAuth(); // AuthContext에서 토큰 상태 구독 [cite: 116]
-
- if (!accessToken) {
- alert("로그인이 필요한 서비스입니다."); // 사용자 경험 고려 [cite: 120]
- return
; // 리다이렉트 처리 [cite: 110, 119]
- }
-
- return
; // 인증된 경우 하위 경로(LPListPage 등) 렌더링
-};
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/main.tsx b/UMC-10th-mission-FE/src/main.tsx
deleted file mode 100644
index 3d4bdea4..00000000
--- a/UMC-10th-mission-FE/src/main.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import { StrictMode } from 'react'
-import { createRoot } from 'react-dom/client'
-import './index.css'
-import App from './App.tsx'
-
-createRoot(document.getElementById('root')!).render(
-
-
- ,
-)
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/pages/GoogleLoginRedirectPage.tsx b/UMC-10th-mission-FE/src/pages/GoogleLoginRedirectPage.tsx
deleted file mode 100644
index 94407e7a..00000000
--- a/UMC-10th-mission-FE/src/pages/GoogleLoginRedirectPage.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import { useEffect } from "react";
-import { useLocalStorage } from "../hooks/useLocalStorage";
-import { LOCAL_STORAGE_KEY } from "../constants/key";
-import { useNavigate } from "react-router-dom";
-
-const GoogleLoginRedirectPage = () => {
- const { setItem: setAccessToken } = useLocalStorage(
- LOCAL_STORAGE_KEY.ACCESS_TOKEN
- );
- const { setItem: setRefreshToken } = useLocalStorage(
- LOCAL_STORAGE_KEY.REFRESH_TOKEN
- );
- const navigate = useNavigate();
-
- useEffect(() => {
- const params = new URLSearchParams(window.location.search);
- const accessToken = params.get("accessToken");
- const refreshToken = params.get("refreshToken");
-
- if (accessToken) {
- setAccessToken(accessToken);
- if (refreshToken) setRefreshToken(refreshToken);
- // window.location.href 대신 navigate 사용 (SPA 방식 유지)
- navigate("/mypage", { replace: true });
- } else {
- // 토큰이 없으면 로그인 페이지로
- navigate("/login", { replace: true });
- }
- }, []);
-
- return (
-
- );
-};
-
-export default GoogleLoginRedirectPage;
diff --git a/UMC-10th-mission-FE/src/pages/HomePage.tsx b/UMC-10th-mission-FE/src/pages/HomePage.tsx
deleted file mode 100644
index e16165c4..00000000
--- a/UMC-10th-mission-FE/src/pages/HomePage.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import { useNavigate } from "react-router-dom";
-import { useAuth } from "../context/AuthContext";
-
-const HomePage = () => {
- const navigate = useNavigate();
- const { accessToken } = useAuth();
-
- return (
-
-
- 돌려돌려LP판
-
-
당신의 LP 컬렉션을 관리하세요
- {!accessToken && (
-
-
-
- )}
-
- );
-};
-
-export default HomePage;
diff --git a/UMC-10th-mission-FE/src/pages/LPDetailPage.tsx b/UMC-10th-mission-FE/src/pages/LPDetailPage.tsx
deleted file mode 100644
index 3d5ae1e1..00000000
--- a/UMC-10th-mission-FE/src/pages/LPDetailPage.tsx
+++ /dev/null
@@ -1,241 +0,0 @@
-// src/pages/LPDetailPage.tsx
-import { useState, useEffect } from "react";
-import { useParams, useNavigate, useLocation } from "react-router-dom";
-import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { Heart } from "lucide-react";
-import { useAuth } from "../context/AuthContext";
-import { useGetLpDetail } from "../hooks/useGetLPDetail";
-import { deleteLp, postLpLike } from "../apis/lp";
-import type { LpDetailResponse } from "../types/lp";
-import CommentSection from "../components/CommentSection";
-import LpWriteModal from "../components/LpWriteModal";
-import ConfirmModal from "../components/ConfirmModal";
-
-const LPDetailPage = () => {
- const { lpid } = useParams();
- const navigate = useNavigate();
- const location = useLocation();
- const queryClient = useQueryClient();
- const { accessToken } = useAuth();
-
- const [isEditModalOpen, setIsEditModalOpen] = useState(false);
- const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
-
- useEffect(() => {
- if (!accessToken) {
- alert("로그인이 필요한 서비스입니다. 로그인 페이지로 이동합니다! 🚨");
- navigate("/login", {
- state: { from: location.pathname },
- replace: true,
- });
- }
- // location은 navigate 시 현재 pathname을 state에 담기 위한 값이므로
- // 의존성 배열에서 제외해 쿼리 상태 변화로 인한 불필요한 effect 재실행을 방지
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [accessToken]);
-
- const { data: response, isPending, isError, refetch } = useGetLpDetail(lpid);
-
- // LP 삭제
- const { mutate: handleDelete, isPending: isDeleting } = useMutation({
- mutationFn: () => deleteLp(Number(lpid)),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ["lps"] });
- navigate("/lps");
- },
- });
-
- // 좋아요 토글 (낙관적 업데이트)
- const { mutate: handleLike, isPending: isLiking } = useMutation({
- mutationFn: () => postLpLike(Number(lpid)),
- onMutate: async () => {
- // 진행 중인 상세 조회 쿼리 취소 (race condition 방지)
- await queryClient.cancelQueries({ queryKey: ["lp", lpid] });
-
- // 롤백용 스냅샷 저장
- const previousData = queryClient.getQueryData
(["lp", lpid]);
-
- // 좋아요 상태 즉시 토글
- queryClient.setQueryData(["lp", lpid], (old) => {
- if (!old) return old;
- const liked = old.data.isLiked ?? false;
- return {
- ...old,
- data: {
- ...old.data,
- isLiked: !liked,
- likes: (old.data.likes ?? 0) + (liked ? -1 : 1),
- },
- };
- });
-
- return { previousData };
- },
- onError: (_error, _variables, context) => {
- // 요청 실패 시 스냅샷으로 롤백 (에러 시 재요청 없이 롤백만 수행)
- if (context?.previousData) {
- queryClient.setQueryData(["lp", lpid], context.previousData);
- }
- },
- onSuccess: () => {
- // 성공 시에만 서버 최신 데이터로 동기화
- // (실패 시 재요청을 막아 LP 상세 오류 화면으로 튕기는 현상 방지)
- queryClient.invalidateQueries({ queryKey: ["lp", lpid] });
- },
- });
-
- if (!accessToken) return null;
-
- if (isError) {
- return (
-
-
데이터를 불러오는데 실패했습니다 😭
-
-
- );
- }
-
- if (isPending) {
- return (
-
- );
- }
-
- const lp = response?.data;
-
- return (
-
-
-
- {/* LP 썸네일 */}
- {lp?.thumbnail ? (
-

- ) : (
-
- 이미지가 없습니다
-
- )}
-
- {/* LP 메타 정보 */}
-
-
- {lp?.title || "제목 없음"}
-
-
-
- 📅{" "}
- {lp?.createdAt
- ? new Date(lp.createdAt).toLocaleDateString()
- : "업로드일 모름"}
-
- ❤️ 좋아요 {lp?.likes ?? 0}개
- {lp?.artist && 🎤 아티스트: {lp.artist}}
-
- {lp?.tags && lp.tags.length > 0 && (
-
- {lp.tags.map((tag: string) => (
-
- #{tag}
-
- ))}
-
- )}
-
-
-
-
-
- {lp?.content || "본문 내용이 없습니다."}
-
-
- {/* 액션 버튼 */}
-
- {/* 좋아요 */}
-
-
- {/* 수정 */}
-
-
- {/* 삭제 */}
-
-
-
- {/* 댓글 영역 */}
-
-
-
-
-
- {/* LP 수정 모달 — LpWriteModal을 edit 모드로 재사용 */}
- {isEditModalOpen && lp && (
-
setIsEditModalOpen(false)}
- />
- )}
-
- {/* 삭제 확인 모달 */}
- {isDeleteModalOpen && (
- handleDelete()}
- onCancel={() => setIsDeleteModalOpen(false)}
- />
- )}
-
- );
-};
-
-export default LPDetailPage;
diff --git a/UMC-10th-mission-FE/src/pages/LPListPage.tsx b/UMC-10th-mission-FE/src/pages/LPListPage.tsx
deleted file mode 100644
index c4167588..00000000
--- a/UMC-10th-mission-FE/src/pages/LPListPage.tsx
+++ /dev/null
@@ -1,106 +0,0 @@
-// src/pages/LPListPage.tsx
-import { useState, useEffect } from "react";
-import { useNavigate } from "react-router-dom";
-import { useInView } from "react-intersection-observer"; // 👈 마법의 관찰 카메라
-import { useGetLpList } from "../hooks/useGetLpList";
-import { LpCardSkeleton } from "../components/LpCardSkeleton"; // 👈 스켈레톤 가져오기
-
-const LPListPage = () => {
- const navigate = useNavigate();
- const [sort, setSort] = useState<"latest" | "oldest">("latest");
-
- // 📸 관찰 카메라 달기 (맨 밑에 닿으면 inView가 true가 됨!)
- const { ref, inView } = useInView();
-
- // 🏃♂️ 무한 배달 비서 호출!
- const {
- data,
- isPending, // 첫 로딩 중인지
- isError,
- fetchNextPage, // 다음 10개 가져와!
- hasNextPage, // 더 가져올 게 남았어?
- isFetchingNextPage, // 지금 다음 페이지 가져오는 중이야?
- refetch
- } = useGetLpList(sort);
-
- // 💡 [핵심] 카메라에 맨 밑 요소가 보이고, 더 가져올 게 있고, 현재 로딩 중이 아니라면? -> 다음 페이지 호출!
- useEffect(() => {
- if (inView && hasNextPage && !isFetchingNextPage) {
- fetchNextPage();
- }
- }, [inView, hasNextPage, isFetchingNextPage, fetchNextPage]);
-
- // 페이지 데이터들을 하나로 쭉 합쳐주기 (플랫하게 펴기!)
- const lpList = data?.pages.flatMap((page) => page.data.data) || [];
-
- if (isError) {
- return (
-
-
데이터를 불러오는데 실패했습니다 😭
-
-
- );
- }
-
- return (
-
-
-
나의 LP 보관함
-
-
-
- {/* 1. 최초 로딩 시 (상단 스켈레톤) */}
- {isPending ? (
-
- {[1, 2, 3, 4, 5, 6].map((n) => )}
-
- ) : lpList.length === 0 ? (
-
보관된 LP가 없습니다.
- ) : (
-
- {/* 실제 데이터 렌더링 (카드 오버레이는 유지!) */}
- {lpList.map((lp) => (
-
navigate(`/lps/${lp.id}`)}
- className="group border border-[#FF1493] rounded-xl p-4 bg-[#111] flex flex-col cursor-pointer transition-transform duration-300 hover:scale-105"
- >
-
- {lp.thumbnail ? (
-

- ) : (
-
No Image
- )}
-
-
{lp.title}
-
- 📅 {lp.createdAt ? new Date(lp.createdAt).toLocaleDateString() : "날짜 모름"}
-
-
❤️ 좋아요 {lp.likes || 0}개
-
-
-
{lp.title}
-
- ))}
-
- )}
-
- {/* 2. 추가 로딩 시 (하단 스켈레톤) */}
- {isFetchingNextPage && (
-
- {[1, 2].map((n) => )}
-
- )}
-
- {/* 📸 관찰용 투명 div (여기에 스크롤이 닿으면 다음 페이지 호출) */}
-
-
- );
-};
-
-export default LPListPage;
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/pages/LoginPage.tsx b/UMC-10th-mission-FE/src/pages/LoginPage.tsx
deleted file mode 100644
index b9e1e3fd..00000000
--- a/UMC-10th-mission-FE/src/pages/LoginPage.tsx
+++ /dev/null
@@ -1,117 +0,0 @@
-import { useNavigate, useLocation } from "react-router-dom";
-import { useMutation } from "@tanstack/react-query";
-import { useAuth } from "../context/AuthContext";
-import useForm from "../hooks/useForm";
-import { validateSignin } from "../utils/validate";
-import { ChevronLeft } from "lucide-react";
-import type { AxiosError } from "axios";
-
-const LoginPage = () => {
- const navigate = useNavigate();
- const location = useLocation();
- const { login } = useAuth();
-
- const { values, errors, touched, getInputProps } = useForm({
- init_val: { email: "", password: "" },
- validate: validateSignin,
- });
-
- const isFormValid =
- !errors.email && !errors.password && !!values.email && !!values.password;
-
- const { mutate: handleLogin, isPending, error } = useMutation({
- mutationFn: login,
- onSuccess: () => {
- const from = (location.state as { from?: string })?.from ?? "/";
- navigate(from, { replace: true });
- },
- });
-
- const serverError = error
- ? ((error as AxiosError<{ message: string }>).response?.data?.message ??
- "로그인 중 오류가 발생했습니다.")
- : null;
-
- const handleSubmit = (e: React.FormEvent) => {
- e.preventDefault();
- if (!isFormValid || isPending) return;
- handleLogin(values);
- };
-
- return (
-
- {/* 헤더 */}
-
-
-
로그인
-
-
-
-
- );
-};
-
-export default LoginPage;
diff --git a/UMC-10th-mission-FE/src/pages/MyPage.tsx b/UMC-10th-mission-FE/src/pages/MyPage.tsx
deleted file mode 100644
index 320f3562..00000000
--- a/UMC-10th-mission-FE/src/pages/MyPage.tsx
+++ /dev/null
@@ -1,111 +0,0 @@
-import { useState } from "react";
-import { useNavigate } from "react-router-dom";
-import { Settings } from "lucide-react";
-import { useAuth } from "../context/AuthContext";
-import { useGetMyInfo } from "../hooks/useGetMyInfo";
-import EditProfileModal from "../components/EditProfileModal";
-
-const MyPage = () => {
- const navigate = useNavigate();
- const { accessToken, logout } = useAuth();
-
- const { data: response, isPending } = useGetMyInfo(accessToken);
- const userInfo = response?.data ?? null;
-
- const [isEditModalOpen, setIsEditModalOpen] = useState(false);
-
- const handleLogout = async () => {
- await logout();
- navigate("/", { replace: true });
- };
-
- if (isPending) {
- return (
-
- );
- }
-
- return (
-
-
마이페이지
-
- {userInfo ? (
-
-
- {userInfo.avatar ? (
-

- ) : (
-
- {userInfo.name?.charAt(0).toUpperCase()}
-
- )}
-
-
-
- {userInfo.name}
-
-
{userInfo.email}
-
-
-
-
-
- {userInfo.bio ? (
-
- {userInfo.bio}
-
- ) : (
-
- 아직 자기소개가 없습니다.
-
- )}
-
-
-
- ) : (
-
-
- 사용자 정보를 불러올 수 없습니다.
-
-
-
- )}
-
- {isEditModalOpen && userInfo && (
-
setIsEditModalOpen(false)}
- />
- )}
-
- );
-};
-
-export default MyPage;
diff --git a/UMC-10th-mission-FE/src/pages/NotFoundPage.tsx b/UMC-10th-mission-FE/src/pages/NotFoundPage.tsx
deleted file mode 100644
index 39f8c70e..00000000
--- a/UMC-10th-mission-FE/src/pages/NotFoundPage.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import { useNavigate } from "react-router-dom";
-
-const NotFoundPage = () => {
- const navigate = useNavigate();
-
- return (
-
-
404
-
페이지를 찾을 수 없습니다.
-
-
- );
-};
-
-export default NotFoundPage;
diff --git a/UMC-10th-mission-FE/src/pages/SignupPage.tsx b/UMC-10th-mission-FE/src/pages/SignupPage.tsx
deleted file mode 100644
index 28a87c3d..00000000
--- a/UMC-10th-mission-FE/src/pages/SignupPage.tsx
+++ /dev/null
@@ -1,262 +0,0 @@
-import { useState } from "react";
-import { z } from "zod";
-import { useForm, type SubmitHandler } from "react-hook-form";
-import { zodResolver } from "@hookform/resolvers/zod";
-import { postSignup } from "../apis/auth";
-import { useNavigate } from "react-router-dom";
-import { Eye, EyeOff, ChevronLeft, User } from "lucide-react";
-
-const schema = z
- .object({
- email: z.string().email({ message: "올바른 이메일 형식이 아닙니다!" }),
- password: z
- .string()
- .min(8, { message: "비밀번호는 8자 이상이어야 합니다!" })
- .max(20, { message: "비밀번호는 20자 이하여야 합니다!" }),
- passwordCheck: z.string(),
- name: z
- .string()
- .min(2, { message: "닉네임은 2자 이상이어야 합니다." })
- .max(10, { message: "닉네임은 10자 이하로 설정해주세요." }),
- })
- .refine((data) => data.password === data.passwordCheck, {
- message: "비밀번호가 일치하지 않습니다.",
- path: ["passwordCheck"],
- });
-
-type FormFields = z.infer;
-
-export default function SignUp() {
- const [step, setStep] = useState<1 | 2 | 3>(1);
- const [showPw, setShowPw] = useState(false);
- const [showPwCheck, setShowPwCheck] = useState(false);
- const navigate = useNavigate();
-
- const {
- register,
- handleSubmit,
- trigger,
- watch,
- formState: { errors, isSubmitting, isValid },
- } = useForm({
- mode: "onChange",
- defaultValues: { email: "", password: "", passwordCheck: "", name: "" },
- resolver: zodResolver(schema),
- });
-
- const emailValue = watch("email");
-
- const goNext = async (
- fields: (keyof FormFields)[],
- nextStep: 1 | 2 | 3
- ) => {
- const valid = await trigger(fields);
- if (valid) setStep(nextStep);
- };
-
- const onSubmit: SubmitHandler = async (data) => {
- try {
- const { passwordCheck: _, ...rest } = data;
- await postSignup(rest);
- alert("회원가입이 완료되었습니다!");
- navigate("/login");
- } catch (error: any) {
- const msg =
- error.response?.data?.message || "회원가입 중 오류가 발생했습니다.";
- alert(msg);
- }
- };
-
- const stepBack = () => {
- if (step === 1) navigate(-1);
- else setStep((prev) => (prev - 1) as 1 | 2 | 3);
- };
-
- return (
-
- {/* 헤더 */}
-
-
-
회원가입
- {/* 스텝 인디케이터 */}
-
- {[1, 2, 3].map((s) => (
-
- ))}
-
-
-
-
- {/* Step 1: 이메일 */}
- {step === 1 && (
-
-
-
- 구글로 시작하기
-
-
-
-
- OR
-
-
-
-
-
- {errors.email && (
-
- {errors.email.message}
-
- )}
-
-
-
-
- )}
-
- {/* Step 2: 비밀번호 */}
- {step === 2 && (
-
-
-
-
-
-
-
-
- {errors.password && (
-
- {errors.password.message}
-
- )}
-
-
-
-
-
-
-
- {errors.passwordCheck && (
-
- {errors.passwordCheck.message}
-
- )}
-
-
-
-
- )}
-
- {/* Step 3: 닉네임 */}
- {step === 3 && (
-
-
-
- 거의 다 왔어요!
-
-
- 사용하실 닉네임을 설정해주세요.
-
-
-
- {/* 아바타 자리 */}
-
-
-
-
-
-
- {errors.name && (
-
- {errors.name.message}
-
- )}
-
-
-
-
- )}
-
-
- );
-}
diff --git a/UMC-10th-mission-FE/src/pages/WritePage.tsx b/UMC-10th-mission-FE/src/pages/WritePage.tsx
deleted file mode 100644
index 697bfcb3..00000000
--- a/UMC-10th-mission-FE/src/pages/WritePage.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-const WritePage = () => {
- return (
-
-
새로운 LP 등록 페이지 (준비 중!)
-
- );
-};
-export default WritePage;
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/src/types/auth.ts b/UMC-10th-mission-FE/src/types/auth.ts
deleted file mode 100644
index 3439501e..00000000
--- a/UMC-10th-mission-FE/src/types/auth.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import type { CommonRes } from "./common";
-
-export type ReqSignUpDto = {
- name: string;
- email: string;
- bio?: string;
- avatar?: string;
- password: string;
-};
-
-export type ResSignUpDto = CommonRes<{
- id: number;
- name: string;
- email: string;
- bio: string | null;
- avatar: string | null;
- createdAt: Date;
- updatedAt: Date;
-}>;
-
-export type ReqSignInDto = {
- email: string;
- password: string;
-};
-
-export type ResSignInDto = CommonRes<{
- id: number;
- name: string;
- accessToken: string;
- refreshToken: string;
-}>;
-
-export type ResMyInfoDto = CommonRes<{
- id: number;
- name: string;
- email: string;
- bio: string | null;
- avatar: string | null;
- createdAt: Date;
- updatedAt: Date;
-}>;
-
-export type ReqUpdateProfileDto = {
- name: string;
- bio: string; // 빈 문자열로 보내면 서버에서 bio 초기화
- avatar?: File; // 새 파일을 선택했을 때만 포함
-};
diff --git a/UMC-10th-mission-FE/src/types/common.ts b/UMC-10th-mission-FE/src/types/common.ts
deleted file mode 100644
index 5e306ecd..00000000
--- a/UMC-10th-mission-FE/src/types/common.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export type CommonRes = {
- status: boolean;
- message: string;
- data: T;
-};
diff --git a/UMC-10th-mission-FE/src/types/lp.ts b/UMC-10th-mission-FE/src/types/lp.ts
deleted file mode 100644
index aa775ccc..00000000
--- a/UMC-10th-mission-FE/src/types/lp.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-// src/types/lp.ts
-import type { CommonRes } from "./common";
-
-export type Lp = {
- id: number;
- title: string;
- content?: string;
- thumbnail?: string;
- artist?: string;
- createdAt?: string;
- updatedAt?: string;
- likes?: number;
- isLiked?: boolean;
- tags?: string[];
- author?: { id: number; name: string };
-};
-
-export type LpDetailResponse = CommonRes;
-
-export type GetLpsResponse = CommonRes<{
- data: Lp[];
- cursor: number | null;
- hasNext: boolean;
-}>;
-
-export type ReqCreateLpDto = {
- title: string;
- content: string;
- thumbnail?: File | null;
- tags: string[];
-};
-
-export type ReqUpdateLpDto = ReqCreateLpDto;
-
-export type CreateLpResponse = CommonRes;
-
-export type Comment = {
- id: number;
- content: string;
- createdAt: string;
- updatedAt?: string;
- author: {
- id: number;
- name: string;
- };
-};
-
-export type ReqCreateCommentDto = { content: string };
-export type ReqUpdateCommentDto = { content: string };
diff --git a/UMC-10th-mission-FE/src/utils/validate.ts b/UMC-10th-mission-FE/src/utils/validate.ts
deleted file mode 100644
index f1d574ca..00000000
--- a/UMC-10th-mission-FE/src/utils/validate.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-export type UserSigninInfo = {
- email: string;
- password: string;
-};
-
-const EMAIL_REGEX =
- /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i;
-
-function validateUser(vals: UserSigninInfo) {
- const errors: Record = {
- email: "",
- password: "",
- };
-
- if (!EMAIL_REGEX.test(vals.email)) {
- errors.email = "올바른 이메일 형식이 아닙니다!";
- }
-
- // 수정: 빈 문자열(length=0)도 잡히도록 >= 8 조건만으로 충분하지 않았음
- if (vals.password.length < 8 || vals.password.length >= 20) {
- errors.password = "비밀번호는 8 ~ 20자 사이로 입력해주세요!";
- }
-
- return errors;
-}
-
-export function validateSignin(vals: UserSigninInfo) {
- return validateUser(vals);
-}
diff --git a/UMC-10th-mission-FE/src/vite-env.d.ts b/UMC-10th-mission-FE/src/vite-env.d.ts
deleted file mode 100644
index f59599ab..00000000
--- a/UMC-10th-mission-FE/src/vite-env.d.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-interface ImportMetaEnv {
- readonly VITE_SERVER_API_URL: string;
-}
-
-interface ImportMeta {
- readonly env: ImportMetaEnv;
-}
\ No newline at end of file
diff --git a/UMC-10th-mission-FE/tsconfig.json b/UMC-10th-mission-FE/tsconfig.json
deleted file mode 100644
index 1ffef600..00000000
--- a/UMC-10th-mission-FE/tsconfig.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "files": [],
- "references": [
- { "path": "./tsconfig.app.json" },
- { "path": "./tsconfig.node.json" }
- ]
-}
diff --git a/UMC-10th-mission-FE/tsconfig.node.json b/UMC-10th-mission-FE/tsconfig.node.json
deleted file mode 100644
index d3c52ea6..00000000
--- a/UMC-10th-mission-FE/tsconfig.node.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "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/UMC-10th-mission-FE/vite.config.ts b/UMC-10th-mission-FE/vite.config.ts
deleted file mode 100644
index c4069b77..00000000
--- a/UMC-10th-mission-FE/vite.config.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-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()],
-})
diff --git a/UMC-10th-mission-FE/index.html b/index.html
similarity index 68%
rename from UMC-10th-mission-FE/index.html
rename to index.html
index 2bce0e63..43f5c985 100644
--- a/UMC-10th-mission-FE/index.html
+++ b/index.html
@@ -1,10 +1,10 @@
-
+
-
+
- umc
+ TMDB 영화 검색
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..695e358d
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1823 @@
+{
+ "name": "tmdb-movie-search",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "tmdb-movie-search",
+ "version": "0.0.0",
+ "dependencies": {
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
+ },
+ "devDependencies": {
+ "@types/react": "^19.0.0",
+ "@types/react-dom": "^19.0.0",
+ "@vitejs/plugin-react": "^4.3.4",
+ "typescript": "~5.7.2",
+ "vite": "^6.0.5"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
+ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
+ "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
+ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
+ "dev": true,
+ "license": "MIT",
+ "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/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.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz",
+ "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
+ "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.29.7",
+ "@babel/helper-validator-option": "^7.29.7",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
+ "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
+ "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
+ "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz",
+ "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
+ "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
+ "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
+ "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz",
+ "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.7"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz",
+ "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz",
+ "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
+ "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz",
+ "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==",
+ "dev": true,
+ "license": "MIT",
+ "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.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz",
+ "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
+ "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.27",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
+ "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.0.tgz",
+ "integrity": "sha512-IPIQ55ythEHkfEd9jMEi32OQ7SxURsGA43JI22lj01OLZNt2NUbJX8YUHxkVWyQ6daHPNn0truF5nSj3DQp6YQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.0.tgz",
+ "integrity": "sha512-M6s9cr10MibETyo8JsOkq+Lo1+lU6hcvb1MApnUql5qte/5hMEgzlN8/ReIKNfRV8rrqX50W1BX9zoUhC192RA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.0.tgz",
+ "integrity": "sha512-BqCoMoIbn0keKys+dEAdBa70EtOwV1bEsQCUgU9FdiZmmMge/Zk7LlkYGqbrdHR+Frnt0E1FOanly+rlwvvQzw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.0.tgz",
+ "integrity": "sha512-SIMzST3VFNXDAbeIWDWiFCNM5qncUBDWaEV7NfE7oZbDt2mgfW4MvbKdbYiGOLoM32gbTv608UMd0XktEYSD7w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.0.tgz",
+ "integrity": "sha512-ezjfSQMP7ArdUsbBwbQIfwAlhE84I2iVnzQNCFSveqV42q+BmKlzVpf7mxv5EchLcoWU4y6/heFzVg1F+hodUQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.0.tgz",
+ "integrity": "sha512-9+qTWGW9AZRhnUgwtTwzNwcPlL87ngkeN0LA+q1bADvmY9aNvWaF2TFW8BZgnQPYxpDI7+rMVLivcd4V737TAQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.0.tgz",
+ "integrity": "sha512-T1dMEQhXA/jkJ/jyMIw9IovK8bSUq7A8kLIlvZTb/6YIVsp2zLavr4F3oyllHWo7eIVJRyE5n3tUjQJEbE1IuQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.0.tgz",
+ "integrity": "sha512-2as0LgT7qQpyceQq6VUJYnumUMUrgGQCWIiDIN9DE0/tglsk6o66uCB4f3djRawAltvfCNLyZZrsqbPA6inCsA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.0.tgz",
+ "integrity": "sha512-bVURMg+6eNN9C/yc0aVjooZcwTTtYF4YW3xta5pP0//r3o1V8gXEHXWCndj47w/HhwsFroZrFhR+6uQP5T0n0g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.0.tgz",
+ "integrity": "sha512-Ful8pM/2yYI83PViWdFdpZhdI8HJ5qsXANe5atypbHDf+KIBBDsZsbyy8hbXnULVvW9NsTh5DHwbcBftyLTfiw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.0.tgz",
+ "integrity": "sha512-9Gp/DgrkzfUBmNPVTyPTvay+4xEP7M/clXpj3efXBcm6uTIVIgDg4rqUpqKXvLEuFRVuEpSAOkhgNeecvaZ4Cg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.0.tgz",
+ "integrity": "sha512-m9tsJz54LUXkSYM8+8PG81B9IKK5r+2T0clMq4QrS16xFosufU7firBDAZEsDheDs7wTlP7h3++S7lMsU955HA==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.0.tgz",
+ "integrity": "sha512-3UvJ5PNVU16aJf6M3tFI24pWzAl2/ynfbyRN3ICyQajK1lSkrnVYNnLz3v04J32qKa0FczJc22zeToc0lr2A3w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.0.tgz",
+ "integrity": "sha512-vRWUAbYLGHBZS6Q8Msb2sfnf1fvJf+47t8l/TwOerM2qArzy+IeNMTHrYLHXh95h8MoatPHI5hhSZNs+mGXKPg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.0.tgz",
+ "integrity": "sha512-c00T5SYENHAt86cfW47URaP3Us5vLC/4QO7GYud1G5VNRffCwwCuBspwqYrriuJB+5m0WFzClCn9wed0FBjKvg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.0.tgz",
+ "integrity": "sha512-krrCDilhXOwFkSkO3Wm9I/f9H0L92XHHwy2fwxjukxIbh0dem8gZqOW5Y8BsHrpJv5qwlRBV+Wl4ZFyRWhUpwg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.0.tgz",
+ "integrity": "sha512-7pfYFSTc4/rUC/FtAI0Qp6QthDBCIi6/AuP1xYqFk5vanI6KnL5dWKP60OM/05LOsbwTmIcvr6eXC4CJuJ75IA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.0.tgz",
+ "integrity": "sha512-7SDIalKeIpG0Ifogbbdn58HmSotYMlf23K3dCJEmiVd9Fg36Vmni82iPQec27N3wY4Bvbxftkxz6vSx9OcouTg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.0.tgz",
+ "integrity": "sha512-eRZevouTH2i1HeAVLqJuLnt256krQkGY0TN6WsTmsIhuzbh457HuWDMakKwmi0Cjadux983CoSr8Lim2QhUIFw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openbsd-x64": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.0.tgz",
+ "integrity": "sha512-3oVS7FLGa4U1qcvao9ylGxrjXZyUQqR8UwxEcnUEyPX53O/C/mKDZegNXTdHCP+h3e6ta/f1EN38Yif1mmZHYg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.0.tgz",
+ "integrity": "sha512-yTB9TgfWj5wHe5QgktAgXTLLot1gvEjl1NiPPAUiCs4oPrIWFl5V4nC3GrkNdj9LaAU4s94nVrGbGOCqUpyWsg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.0.tgz",
+ "integrity": "sha512-5LOhoaesY3doG1c+ac/2JtgREpKoJr5bUHH8tKY0V8di7+uSV6BwLs2PlR0/yzefGOkR+wE7ZolZphHCsyG5Rw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.0.tgz",
+ "integrity": "sha512-yYkWHhmbhRTWTnWos5HC4GcPQfjlzzCNbM9e/+GXrLuaBXYA3qSDR9f0Vgufd5S8yX81U8jPKp7ZnAjZFMtRnw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.0.tgz",
+ "integrity": "sha512-SoTb6lPg25xZlA2ibwQ++ahCCnH+FP0qmEuafMJ4gznZKOlXioKEAeJLgCrqjM98ACziXM9V1amFjICVL4IFoA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.0.tgz",
+ "integrity": "sha512-5L+T1fMX4RIEBoZzT0+sQ0PhTS36NULFmMXtl1TZo44TMAROIMHbZufSOjVWt/Y622BtxgxtaNOokbTDvfsrZA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.2"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.17",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz",
+ "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.3",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
+ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/@vitejs/plugin-react": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
+ "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.28.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-beta.27",
+ "@types/babel__core": "^7.20.5",
+ "react-refresh": "^0.17.0"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
+ }
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.10.37",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.37.tgz",
+ "integrity": "sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
+ "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.10.12",
+ "caniuse-lite": "^1.0.30001782",
+ "electron-to-chromium": "^1.5.328",
+ "node-releases": "^2.0.36",
+ "update-browserslist-db": "^1.2.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001799",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz",
+ "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.372",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.372.tgz",
+ "integrity": "sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.12",
+ "@esbuild/android-arm": "0.25.12",
+ "@esbuild/android-arm64": "0.25.12",
+ "@esbuild/android-x64": "0.25.12",
+ "@esbuild/darwin-arm64": "0.25.12",
+ "@esbuild/darwin-x64": "0.25.12",
+ "@esbuild/freebsd-arm64": "0.25.12",
+ "@esbuild/freebsd-x64": "0.25.12",
+ "@esbuild/linux-arm": "0.25.12",
+ "@esbuild/linux-arm64": "0.25.12",
+ "@esbuild/linux-ia32": "0.25.12",
+ "@esbuild/linux-loong64": "0.25.12",
+ "@esbuild/linux-mips64el": "0.25.12",
+ "@esbuild/linux-ppc64": "0.25.12",
+ "@esbuild/linux-riscv64": "0.25.12",
+ "@esbuild/linux-s390x": "0.25.12",
+ "@esbuild/linux-x64": "0.25.12",
+ "@esbuild/netbsd-arm64": "0.25.12",
+ "@esbuild/netbsd-x64": "0.25.12",
+ "@esbuild/openbsd-arm64": "0.25.12",
+ "@esbuild/openbsd-x64": "0.25.12",
+ "@esbuild/openharmony-arm64": "0.25.12",
+ "@esbuild/sunos-x64": "0.25.12",
+ "@esbuild/win32-arm64": "0.25.12",
+ "@esbuild/win32-ia32": "0.25.12",
+ "@esbuild/win32-x64": "0.25.12"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.12",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
+ "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.47",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz",
+ "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.15",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
+ "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.12",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/react": {
+ "version": "19.2.7",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz",
+ "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.2.7",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz",
+ "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.27.0"
+ },
+ "peerDependencies": {
+ "react": "^19.2.7"
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
+ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.0.tgz",
+ "integrity": "sha512-nc72Wgq62I7rtDV4izT5/aaS0zxy3kttkinf9586ApknY3jZO9NYsmtc24fUckA0X7Q2v+ML4a15pdUlV5V/jA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.9"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.62.0",
+ "@rollup/rollup-android-arm64": "4.62.0",
+ "@rollup/rollup-darwin-arm64": "4.62.0",
+ "@rollup/rollup-darwin-x64": "4.62.0",
+ "@rollup/rollup-freebsd-arm64": "4.62.0",
+ "@rollup/rollup-freebsd-x64": "4.62.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.62.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.62.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.62.0",
+ "@rollup/rollup-linux-arm64-musl": "4.62.0",
+ "@rollup/rollup-linux-loong64-gnu": "4.62.0",
+ "@rollup/rollup-linux-loong64-musl": "4.62.0",
+ "@rollup/rollup-linux-ppc64-gnu": "4.62.0",
+ "@rollup/rollup-linux-ppc64-musl": "4.62.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.62.0",
+ "@rollup/rollup-linux-riscv64-musl": "4.62.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.62.0",
+ "@rollup/rollup-linux-x64-gnu": "4.62.0",
+ "@rollup/rollup-linux-x64-musl": "4.62.0",
+ "@rollup/rollup-openbsd-x64": "4.62.0",
+ "@rollup/rollup-openharmony-arm64": "4.62.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.62.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.62.0",
+ "@rollup/rollup-win32-x64-gnu": "4.62.0",
+ "@rollup/rollup-win32-x64-msvc": "4.62.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.17",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
+ "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.7.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
+ "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/vite": {
+ "version": "6.4.3",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz",
+ "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.25.0",
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2",
+ "postcss": "^8.5.3",
+ "rollup": "^4.34.9",
+ "tinyglobby": "^0.2.13"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "jiti": ">=1.21.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..f3069135
--- /dev/null
+++ b/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "tmdb-movie-search",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc --noEmit && vite build",
+ "preview": "vite preview",
+ "lint": "tsc --noEmit"
+ },
+ "dependencies": {
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
+ },
+ "devDependencies": {
+ "@types/react": "^19.0.0",
+ "@types/react-dom": "^19.0.0",
+ "@vitejs/plugin-react": "^4.3.4",
+ "typescript": "~5.7.2",
+ "vite": "^6.0.5"
+ }
+}
diff --git a/src/App.tsx b/src/App.tsx
new file mode 100644
index 00000000..6f7ce904
--- /dev/null
+++ b/src/App.tsx
@@ -0,0 +1,7 @@
+import MovieSearch from "./components/MovieSearch";
+
+function App() {
+ return ;
+}
+
+export default App;
diff --git a/src/apis/tmdb.ts b/src/apis/tmdb.ts
new file mode 100644
index 00000000..e2cd4a16
--- /dev/null
+++ b/src/apis/tmdb.ts
@@ -0,0 +1,44 @@
+import type { Language, Movie, SearchMoviesResponse } from "../types/movie";
+
+// 키는 절대 하드코딩하지 않고 환경변수로만 읽는다. (.env -> import.meta.env)
+const API_KEY = import.meta.env.VITE_TMDB_API_KEY;
+const BASE_URL = "https://api.themoviedb.org/3";
+
+// 포스터 이미지 베이스 URL (카드용 w342)
+export const POSTER_BASE_URL = "https://image.tmdb.org/t/p/w342";
+// 모달용 큰 포스터 (w500)
+export const POSTER_BASE_URL_LARGE = "https://image.tmdb.org/t/p/w500";
+
+interface SearchParams {
+ query: string;
+ includeAdult: boolean;
+ language: Language;
+}
+
+export async function searchMovies({
+ query,
+ includeAdult,
+ language,
+}: SearchParams): Promise {
+ if (!API_KEY) {
+ throw new Error(
+ "VITE_TMDB_API_KEY 가 설정되지 않았습니다. 루트의 .env 파일을 확인하세요."
+ );
+ }
+
+ const url = new URL(`${BASE_URL}/search/movie`);
+ url.searchParams.set("api_key", API_KEY);
+ url.searchParams.set("query", query);
+ // 성인 콘텐츠 포함 여부 (checkbox state 반영)
+ url.searchParams.set("include_adult", String(includeAdult));
+ // 언어 (select state 반영)
+ url.searchParams.set("language", language);
+
+ const res = await fetch(url);
+ if (!res.ok) {
+ throw new Error(`TMDB 요청 실패: ${res.status}`);
+ }
+
+ const data: SearchMoviesResponse = await res.json();
+ return data.results;
+}
diff --git a/src/components/MovieCard.tsx b/src/components/MovieCard.tsx
new file mode 100644
index 00000000..d6b0c8c1
--- /dev/null
+++ b/src/components/MovieCard.tsx
@@ -0,0 +1,45 @@
+import { memo } from "react";
+import type { Movie } from "../types/movie";
+import { POSTER_BASE_URL } from "../apis/tmdb";
+
+interface MovieCardProps {
+ movie: Movie;
+ // 부모에서 useCallback으로 참조를 고정해 넘겨야 memo가 제대로 동작한다.
+ onSelect: (movie: Movie) => void;
+}
+
+function MovieCardBase({ movie, onSelect }: MovieCardProps) {
+ // [2단계] 자식 렌더 추적용 로그.
+ // 최적화 전: 부모에서 검색어를 타이핑할 때마다 이 로그가 카드 수만큼 찍힌다.
+ // 최적화 후(memo + useCallback): props가 같으면 이 로그가 더 이상 찍히지 않는다.
+ console.log("🎬 [MovieCard] render:", movie.title);
+
+ return (
+ onSelect(movie)}>
+ {movie.poster_path ? (
+
+ ) : (
+
+ No Image
+
+ )}
+
+
{movie.title}
+
⭐ {movie.vote_average.toFixed(1)}
+
+ {movie.overview || "개요 정보가 없습니다."}
+
+
+
+ );
+}
+
+// [3단계] memo: props(movie, onSelect)가 얕은 비교로 같으면 리렌더를 건너뛴다.
+// onSelect가 매 렌더마다 새 함수면 memo가 무력화되므로 부모에서 useCallback 필수.
+const MovieCard = memo(MovieCardBase);
+export default MovieCard;
diff --git a/src/components/MovieModal.tsx b/src/components/MovieModal.tsx
new file mode 100644
index 00000000..1740d780
--- /dev/null
+++ b/src/components/MovieModal.tsx
@@ -0,0 +1,100 @@
+import { useEffect } from "react";
+import type { Movie } from "../types/movie";
+import { POSTER_BASE_URL_LARGE } from "../apis/tmdb";
+
+interface MovieModalProps {
+ movie: Movie;
+ onClose: () => void;
+}
+
+function MovieModal({ movie, onClose }: MovieModalProps) {
+ // ESC 키로 닫기 + 모달이 열린 동안 배경 스크롤 잠금
+ useEffect(() => {
+ const handleKeyDown = (e: KeyboardEvent) => {
+ if (e.key === "Escape") onClose();
+ };
+ window.addEventListener("keydown", handleKeyDown);
+ document.body.style.overflow = "hidden";
+
+ return () => {
+ window.removeEventListener("keydown", handleKeyDown);
+ document.body.style.overflow = "";
+ };
+ }, [onClose]);
+
+ // IMDb 검색 URL (영화 제목을 인코딩)
+ const imdbUrl = `https://www.imdb.com/find?q=${encodeURIComponent(
+ movie.title
+ )}`;
+
+ return (
+ // overlay 클릭 시 닫힘
+
+ {/* 모달 박스 내부 클릭은 닫히지 않도록 버블링 차단 */}
+
e.stopPropagation()}
+ >
+
+
+ {/* 상단 포스터 (없으면 placeholder) */}
+ {movie.poster_path ? (
+

+ ) : (
+
No Image
+ )}
+
+
+
{movie.title}
+
+
+
+ ⭐ {movie.vote_average.toFixed(1)}
+
+
+ 개봉일: {movie.release_date || "정보 없음"}
+
+
+
+
+ {movie.overview || "줄거리 정보가 없습니다."}
+
+
+
+
+
+
+ );
+}
+
+export default MovieModal;
diff --git a/src/components/MovieSearch.tsx b/src/components/MovieSearch.tsx
new file mode 100644
index 00000000..ab276c17
--- /dev/null
+++ b/src/components/MovieSearch.tsx
@@ -0,0 +1,132 @@
+import { useCallback, useMemo, useState, type FormEvent } from "react";
+import type { Language, Movie } from "../types/movie";
+import { searchMovies } from "../apis/tmdb";
+import MovieCard from "./MovieCard";
+import MovieModal from "./MovieModal";
+
+function MovieSearch() {
+ // [1단계] 검색 폼 상태들
+ const [title, setTitle] = useState(""); // text input 값
+ const [includeAdult, setIncludeAdult] = useState(false); // checkbox 값
+ const [language, setLanguage] = useState("ko-KR"); // select 값
+
+ // 검색 결과 / 로딩 / 에러 상태
+ const [movies, setMovies] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+ const [error, setError] = useState(null);
+
+ // 상세 모달에 띄울 영화. null이면 모달이 닫힌 상태.
+ const [selectedMovie, setSelectedMovie] = useState(null);
+
+ // [2단계] 부모 렌더 추적용 로그.
+ // 검색어를 한 글자 칠 때마다 title state가 바뀌어 이 로그가 찍힌다(부모 리렌더).
+ console.log("👪 [MovieSearch] render. title =", title);
+
+ // form 제출 시에만 실제 검색을 수행한다 (엔터 입력만으로도 동작).
+ // 주의: handleSubmit은 form에서만 쓰고 memo된 자식에게 넘기지 않으므로
+ // useCallback으로 감싸도 이득이 없다 -> 일부러 감싸지 않는다.
+ const handleSubmit = async (e: FormEvent) => {
+ e.preventDefault();
+
+ const trimmed = title.trim();
+ if (!trimmed) return; // 빈 검색어는 API 호출하지 않음
+
+ setIsLoading(true);
+ setError(null);
+ try {
+ const results = await searchMovies({
+ query: trimmed,
+ includeAdult,
+ language,
+ });
+ setMovies(results);
+ } catch (err) {
+ setError(err instanceof Error ? err.message : "검색 중 오류가 발생했습니다.");
+ setMovies([]);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ // [3단계] useCallback: memo된 MovieCard에 넘기는 핸들러의 참조를 고정한다.
+ // setState 함수만 사용하고 외부 값에 의존하지 않으므로 deps는 빈 배열 -> 참조가 항상 동일.
+ // 이렇게 해야 타이핑(부모 리렌더) 시에도 카드의 onSelect prop이 바뀌지 않아 memo가 유지된다.
+ // 카드를 클릭하면 해당 영화를 selectedMovie로 지정 -> 상세 모달 오픈.
+ const handleSelect = useCallback((movie: Movie) => {
+ setSelectedMovie(movie);
+ }, []);
+
+ // 모달 닫기: selectedMovie를 null로. 마찬가지로 참조 고정.
+ const handleCloseModal = useCallback(() => {
+ setSelectedMovie(null);
+ }, []);
+
+ // [3단계] useMemo: 평점순(내림차순) 정렬은 movies가 바뀔 때만 다시 계산한다.
+ // 타이핑으로 부모가 리렌더돼도 movies 참조가 그대로면 정렬을 재실행하지 않고,
+ // 같은 배열 참조를 반환하므로 카드들의 movie prop도 안정적으로 유지된다.
+ const sortedMovies = useMemo(() => {
+ console.log("🧮 [useMemo] 평점순 정렬 계산");
+ return [...movies].sort((a, b) => b.vote_average - a.vote_average);
+ }, [movies]);
+
+ return (
+
+ 🎥 TMDB 영화 검색
+
+ {/* 검색 영역: form으로 감싸 엔터만으로도 검색 */}
+
+
+ {/* 상태 표시 */}
+ {isLoading && 불러오는 중...
}
+ {error && {error}
}
+ {!isLoading && !error && sortedMovies.length === 0 && (
+ 검색 결과가 여기에 표시됩니다.
+ )}
+
+ {/* 결과 리스트 (평점순 정렬된 sortedMovies 사용) */}
+
+ {sortedMovies.map((movie) => (
+
+ ))}
+
+
+ {/* selectedMovie가 있을 때만 상세 모달 렌더 */}
+ {selectedMovie && (
+
+ )}
+
+ );
+}
+
+export default MovieSearch;
diff --git a/src/index.css b/src/index.css
new file mode 100644
index 00000000..0db5b4fa
--- /dev/null
+++ b/src/index.css
@@ -0,0 +1,295 @@
+:root {
+ /* 밝은 테마 팔레트 */
+ --bg: #f4f5f8;
+ --surface: #ffffff;
+ --border: #e4e6eb;
+ --accent: #ff1493;
+ --text: #1c1d21;
+ --muted: #6b7280;
+ --shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
+
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
+ color: var(--text);
+ background-color: var(--bg);
+}
+
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ background-color: var(--bg);
+}
+
+.container {
+ max-width: 1100px;
+ margin: 0 auto;
+ padding: 32px 20px 64px;
+}
+
+.heading {
+ text-align: center;
+ margin-bottom: 24px;
+}
+
+.search-form {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+ align-items: center;
+ justify-content: center;
+ margin-bottom: 32px;
+}
+
+.search-form__input {
+ flex: 1 1 280px;
+ padding: 10px 14px;
+ border-radius: 8px;
+ border: 1px solid var(--border);
+ background: var(--surface);
+ color: var(--text);
+ font-size: 15px;
+}
+
+.search-form__input::placeholder {
+ color: var(--muted);
+}
+
+.search-form__select {
+ padding: 10px 12px;
+ border-radius: 8px;
+ border: 1px solid var(--border);
+ background: var(--surface);
+ color: var(--text);
+ font-size: 15px;
+}
+
+.search-form__checkbox {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ color: var(--muted);
+ font-size: 14px;
+ white-space: nowrap;
+}
+
+.search-form__button {
+ padding: 10px 22px;
+ border-radius: 8px;
+ border: none;
+ background: var(--accent);
+ color: white;
+ font-size: 15px;
+ font-weight: 600;
+ cursor: pointer;
+}
+
+.search-form__button:hover {
+ opacity: 0.9;
+}
+
+.status {
+ text-align: center;
+ color: var(--muted);
+ margin-top: 24px;
+}
+
+.status--error {
+ color: #e0245e;
+}
+
+.movie-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
+ gap: 20px;
+}
+
+.movie-card {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: 12px;
+ overflow: hidden;
+ cursor: pointer;
+ display: flex;
+ flex-direction: column;
+ box-shadow: var(--shadow);
+ transition: transform 0.15s ease, border-color 0.15s ease;
+}
+
+.movie-card:hover {
+ transform: translateY(-4px);
+ border-color: var(--accent);
+}
+
+.movie-card__poster {
+ width: 100%;
+ aspect-ratio: 2 / 3;
+ object-fit: cover;
+ display: block;
+}
+
+.movie-card__poster--empty {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--muted);
+ background: #eceef2;
+}
+
+.movie-card__body {
+ padding: 12px 14px 16px;
+}
+
+.movie-card__title {
+ margin: 0 0 6px;
+ font-size: 16px;
+}
+
+.movie-card__rating {
+ margin: 0 0 8px;
+ color: #e0a800;
+ font-size: 14px;
+}
+
+.movie-card__overview {
+ margin: 0;
+ color: var(--muted);
+ font-size: 13px;
+ line-height: 1.4;
+ display: -webkit-box;
+ -webkit-line-clamp: 4;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+/* ===== 상세 모달 ===== */
+.modal-overlay {
+ position: fixed;
+ inset: 0;
+ background: rgba(0, 0, 0, 0.5); /* 반투명 어두운 배경 */
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 20px;
+ z-index: 1000;
+}
+
+.modal {
+ position: relative;
+ background: var(--surface);
+ color: var(--text);
+ border-radius: 16px;
+ box-shadow: 0 20px 50px rgba(0, 0, 0, 0.25);
+ width: 100%;
+ max-width: 520px;
+ max-height: 85vh;
+ overflow-y: auto; /* 정보가 길면 모달 내부 스크롤 */
+}
+
+.modal__close {
+ position: absolute;
+ top: 12px;
+ right: 12px;
+ width: 34px;
+ height: 34px;
+ border: none;
+ border-radius: 50%;
+ background: rgba(0, 0, 0, 0.55);
+ color: #fff;
+ font-size: 16px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.modal__close:hover {
+ background: rgba(0, 0, 0, 0.75);
+}
+
+.modal__poster {
+ width: 100%;
+ max-height: 420px;
+ object-fit: cover;
+ display: block;
+ border-radius: 16px 16px 0 0;
+}
+
+.modal__poster--empty {
+ width: 100%;
+ height: 280px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--muted);
+ background: #eceef2;
+ border-radius: 16px 16px 0 0;
+}
+
+.modal__body {
+ padding: 20px 24px 24px;
+}
+
+.modal__title {
+ margin: 0 0 12px;
+ font-size: 22px;
+}
+
+.modal__meta {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16px;
+ margin-bottom: 16px;
+ font-size: 14px;
+ color: var(--muted);
+}
+
+.modal__rating {
+ color: #e0a800;
+ font-weight: 600;
+}
+
+.modal__overview {
+ margin: 0 0 24px;
+ line-height: 1.6;
+ font-size: 15px;
+}
+
+.modal__actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+}
+
+.modal__imdb {
+ flex: 1 1 auto;
+ text-align: center;
+ padding: 11px 18px;
+ border-radius: 8px;
+ background: #f5c518; /* IMDb 옐로우 */
+ color: #1c1d21;
+ font-weight: 700;
+ text-decoration: none;
+}
+
+.modal__imdb:hover {
+ opacity: 0.9;
+}
+
+.modal__close-btn {
+ padding: 11px 22px;
+ border-radius: 8px;
+ border: 1px solid var(--border);
+ background: var(--surface);
+ color: var(--text);
+ font-size: 15px;
+ cursor: pointer;
+}
+
+.modal__close-btn:hover {
+ background: #f0f1f4;
+}
diff --git a/src/main.tsx b/src/main.tsx
new file mode 100644
index 00000000..10ed13e0
--- /dev/null
+++ b/src/main.tsx
@@ -0,0 +1,10 @@
+import { StrictMode } from "react";
+import { createRoot } from "react-dom/client";
+import "./index.css";
+import App from "./App.tsx";
+
+createRoot(document.getElementById("root")!).render(
+
+
+
+);
diff --git a/src/types/movie.ts b/src/types/movie.ts
new file mode 100644
index 00000000..89d3c5cc
--- /dev/null
+++ b/src/types/movie.ts
@@ -0,0 +1,19 @@
+// TMDB search/movie 응답에서 우리가 사용하는 필드만 추린 타입
+export interface Movie {
+ id: number;
+ title: string;
+ overview: string;
+ poster_path: string | null;
+ vote_average: number;
+ adult: boolean;
+ release_date?: string;
+}
+
+export interface SearchMoviesResponse {
+ page: number;
+ results: Movie[];
+ total_pages: number;
+ total_results: number;
+}
+
+export type Language = "ko-KR" | "en-US" | "ja-JP";
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
new file mode 100644
index 00000000..ca54fec6
--- /dev/null
+++ b/src/vite-env.d.ts
@@ -0,0 +1,10 @@
+///
+
+// import.meta.env.VITE_TMDB_API_KEY 에 타입을 부여한다.
+interface ImportMetaEnv {
+ readonly VITE_TMDB_API_KEY: string;
+}
+
+interface ImportMeta {
+ readonly env: ImportMetaEnv;
+}
diff --git a/UMC-10th-mission-FE/tsconfig.app.json b/tsconfig.json
similarity index 53%
rename from UMC-10th-mission-FE/tsconfig.app.json
rename to tsconfig.json
index 7f42e5f7..54053432 100644
--- a/UMC-10th-mission-FE/tsconfig.app.json
+++ b/tsconfig.json
@@ -1,24 +1,21 @@
{
"compilerOptions": {
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
- "target": "es2023",
- "lib": ["ES2023", "DOM"],
- "module": "esnext",
- "types": ["vite/client"],
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
"skipLibCheck": true,
- /* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
- "verbatimModuleSyntax": true,
+ "isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
- /* Linting */
+ "strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
- "erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 00000000..b2c2d6b7
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+
+// Vite는 프로젝트 루트의 .env에서 VITE_ 접두사 변수를 자동으로 로드한다.
+export default defineConfig({
+ plugins: [react()],
+});
diff --git a/week1/dist/index.js b/week1/dist/index.js
deleted file mode 100644
index 5beb347a..00000000
--- a/week1/dist/index.js
+++ /dev/null
@@ -1,69 +0,0 @@
-"use strict";
-const todoInput = document.getElementById('todo-input');
-const todoForm = document.getElementById('todo-form');
-const todoList = document.getElementById('todo-list');
-const doneList = document.getElementById('done-list');
-let todos = [];
-let doneTasks = [];
-const renderTasks = () => {
- todoList.innerHTML = '';
- doneList.innerHTML = '';
- todos.forEach((todo) => {
- const li = createTodoElement(todo, false);
- todoList.appendChild(li);
- });
- doneTasks.forEach((todo) => {
- const li = createTodoElement(todo, true);
- doneList.appendChild(li);
- });
-};
-const getTodoText = () => {
- return todoInput.value.trim();
-};
-const addTodo = (text) => {
- todos.push({ id: Date.now(), text });
- todoInput.value = '';
- renderTasks();
-};
-const compleTodo = (todo) => {
- todos = todos.filter((t) => t.id !== todo.id);
- doneTasks.push(todo);
- renderTasks();
-};
-const deleteTodo = (todo) => {
- doneTasks = doneTasks.filter((t) => t.id !== todo.id);
- renderTasks();
-};
-const createTodoElement = (todo, isDone) => {
- const li = document.createElement('li');
- li.classList.add('render-container__item');
- li.textContent = todo.text;
- const button = document.createElement('button');
- button.classList.add('render-container__item-button');
- if (isDone) {
- button.textContent = '삭제';
- button.style.backgroundColor = '#dc3545';
- }
- else {
- button.textContent = '완료';
- button.style.backgroundColor = '#28a745';
- }
- button.addEventListener('click', () => {
- if (isDone) {
- deleteTodo(todo);
- }
- else {
- compleTodo(todo);
- }
- });
- li.appendChild(button);
- return li;
-};
-todoForm.addEventListener('submit', (event) => {
- event.preventDefault();
- const text = getTodoText();
- if (text) {
- addTodo(text);
- }
-});
-renderTasks();
diff --git a/week1/index.html b/week1/index.html
deleted file mode 100644
index 766bcfba..00000000
--- a/week1/index.html
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
-
-
-
-
- UMC TODO
-
-
-
-
-
\ No newline at end of file
diff --git a/week1/src/index.ts b/week1/src/index.ts
deleted file mode 100644
index 852d12b9..00000000
--- a/week1/src/index.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-// 1. HTML 요소 선택(핸드북 자바 스크립트 편 참고)
-const todoInput = document.getElementById('todo-input') as HTMLInputElement;
-const todoForm = document.getElementById('todo-form') as HTMLFormElement;
-const todoList = document.getElementById('todo-list') as HTMLUListElement;
-const doneList = document.getElementById('done-list') as HTMLUListElement;
-
-//2. 할 일이 어떻게 생긴애인지 Type을 정의
-type Todo = {
- id: number;
- text: string;
-};
-
-let todos: Todo[] = [];
-let doneTasks: Todo[] = [];
-
-//- 할 일 목록 렌더링 하는 함수를 정의
-const renderTasks = (): void => {
- todoList.innerHTML = '';
- doneList.innerHTML = '';
-
- todos.forEach((todo): void => {
- const li = createTodoElement(todo, false);
- todoList.appendChild(li);
- });
-
- doneTasks.forEach((todo): void => {
- const li = createTodoElement(todo, true);
- doneList.appendChild(li);
- })
-};
-
-//3. 할 일 텍스트 입력 처리 함수(공백 잘라줌)
-const getTodoText = (): string => {
- return todoInput.value.trim();
-};
-
-//4. 할 일 추가 처리 함수
-const addTodo = (text: string) : void => {
- todos.push({id: Date.now(), text});
- todoInput.value = '';
- renderTasks();
-};
-
-//5. 할 일 상태 변경(완료로 이동)
-const compleTodo = (todo: Todo): void => {
- todos = todos.filter((t): boolean => t.id !== todo.id);
- doneTasks.push(todo);
- renderTasks();
-};
-
-//6. 완료된 할 일 삭제 함수
-const deleteTodo = (todo: Todo): void => {
- doneTasks = doneTasks.filter((t): boolean => t.id !== todo.id);
- renderTasks();
-}
-
-//7. 할 일 아이템 생성 함수(완료 여부에 따라 버튼 텍스트나 색상 설정)
-const createTodoElement = (todo: Todo, isDone: boolean): HTMLLIElement =>{
- const li = document.createElement('li');
- li.classList.add('render-container__item');
- li.textContent = todo.text;
-
- const button = document.createElement('button');
- button.classList.add('render-container__item-button');
-
- if(isDone){
- button.textContent = '삭제';
- button.style.backgroundColor = '#dc3545';
- } else{
- button.textContent = '완료';
- button.style.backgroundColor = '#28a745';
- }
-
- button.addEventListener('click', ():void =>{
- if(isDone){
- deleteTodo(todo);
- } else {
- compleTodo(todo);
- }
- });
-
- li.appendChild(button);
- return li;
-};
-
-//8. 폼 제출 이벤트 리스너
-todoForm.addEventListener('submit', (event: Event): void =>{
- event.preventDefault();
- const text = getTodoText();
- if(text){
- addTodo(text);
- }
-});
-
-renderTasks();
\ No newline at end of file
diff --git a/week1/style.css b/week1/style.css
deleted file mode 100644
index 00c6fdb6..00000000
--- a/week1/style.css
+++ /dev/null
@@ -1,121 +0,0 @@
-*{
- margin: 0;
- padding: 0;
- box-sizing: border-box;
-}
-
-body{
- font-family: 'Roboto', sans-serif;
- display: flex;
- justify-content: center;
- align-items: center;
- height: 100vh;
- background-color: #f1f1f1;
-}
-
-.todo-container{
- background: white;
- padding: 20px;
- border-radius: 12px;
- box-shadow: 0 4px 10px rgb(0, 0, 0, 0.1);
- width: 350px;
- text-align: center
-}
-
-.todo-container__header{
- font-size: 24px;
- margin-bottom: 16px;
-}
-
-.todo-container__form{
- display: flex;
- gap: 10px;
- margin-bottom: 20px;
-}
-
-.todo-container__input{
- flex: 1;
- padding: 8px;
- border: 1px solid #ccc;
- border-radius: 6px;
- font-size: 14px;
-}
-
-.todo-container__button{
- background-color: #28a745;
- color: white;
- border: none;
- padding: 8px 12px;
- cursor: pointer;
- border-radius: 6px;
- transition: background-color 0.3s ease;
-}
-
-.todo-container__button:hover{
- background-color: #218838;
-}
-
-.render-container{
- display: flex;
- justify-content: space-between;
- gap: 20px;
-}
-
-.render-container__title{
- font-size: 18px;
- margin-bottom: 10px;
-
- display: flex;
- justify-content: center;
-}
-
-.render-container__section{
- width: 100%;
- text-align: left;
-}
-
-.render-container__title{
- font-size: 18px;
- margin-bottom: 10px;
-
- display: flex;
- justify-content: center;
-}
-
-.render-container__list{
- list-style: none;
- padding: 0;
- margin: 0;
-}
-
-.render-container__item{
- display: flex;
- justify-content: space-between;
- align-items: center;
-
- padding: 8px;
- border-bottom: 1px solid #ddd;
- background-color: #f9f9f9;
- border-radius: 6px;
- margin-bottom: 6px;
- width: 100%;
-}
-
-.render-container__item-text{
- flex: 1;
-}
-
-.render-container__item-button{
- background-color: #dc3545;
- color: white;
- border: none;
- padding: 6px 10px;
- cursor: pointer;
- border-radius: 6px;
- font-size: 12px;
- transition: background-color 0.3s ease;
-}
-
-.render-container__item-button:hover {
- background-color: #c82333;
-}
\ No newline at end of file
diff --git a/week1/tsconfig.json b/week1/tsconfig.json
deleted file mode 100644
index f537001c..00000000
--- a/week1/tsconfig.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "compilerOptions": {
- "target": "es2016", // ECMAScript 2016으로 컴파일
- "module": "ES2015", // ES2015 모듈 시스템 사용
- "rootDir": "./src", // 소스 파일의 루트 디렉토리
- "outDir": "./dist", // 컴파일된 파일이 저장될 디렉토리
- "esModuleInterop": true, // ES 모듈 호환성 설정
- "forceConsistentCasingInFileNames": true, // 파일 이름의 대소문자 일관성 강제
- "strict": true, // 엄격한 타입 검사
- "skipLibCheck": true, // 라이브러리 파일 검사 건너뜀
- "removeComments": true, // 컴파일된 코드에서 주석 제거
- "noEmitOnError": false, // 컴파일 에러 발생 시 파일 생성 안 함
- "noUnusedLocals": true, // 사용하지 않는 지역 변수에 대해 에러 발생
- "noUnusedParameters": true, // 사용하지 않는 매개변수에 대해 에러 발생
- "noImplicitReturns": true, // 함수에서 명시적으로 값을 반환하지 않는 경우 에러 발생
- "noFallthroughCasesInSwitch": true, // switch 문에서 fallthrough 방지
- "noUncheckedIndexedAccess": true // 인덱스 접근 시 체크되지 않은 경우 에러 발생
- }
-}
\ No newline at end of file