diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..88bc97bb --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,39 @@ +module.exports = { + root: true, + env: { + browser: true, + es2021: true, + node: true, + }, + parser: "@typescript-eslint/parser", + parserOptions: { + ecmaVersion: 12, + sourceType: "module", + ecmaFeatures: { jsx: true }, + }, + plugins: [ + "react", + "react-hooks", + "@typescript-eslint", + "jsx-a11y", + "prettier", + ], + extends: [ + "eslint:recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended", + "plugin:jsx-a11y/recommended", + "plugin:@typescript-eslint/recommended", + "prettier", + ], + settings: { + react: { version: "detect" }, + }, + rules: { + // Prettier 문제를 ESLint 에러로 표시 + "prettier/prettier": "error", + // 필요에 따라 아래에 커스텀 룰 추가 + // 'react/prop-types': 'off', + // '@typescript-eslint/explicit-module-boundary-types': 'off', + }, +}; diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..754105b4 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,12 @@ +{ + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": true, + "trailingComma": "es5", + "bracketSpacing": true, + "arrowParens": "always", + "htmlWhitespaceSensitivity": "css", + "endOfLine": "lf" +} diff --git a/.stylelintrc.js b/.stylelintrc.js new file mode 100644 index 00000000..472a9483 --- /dev/null +++ b/.stylelintrc.js @@ -0,0 +1,20 @@ +module.exports = { + extends: ['stylelint-config-standard-scss', 'stylelint-prettier/recommended'], + plugins: ['stylelint-scss'], + rules: { + // Prettier 포맷팅 충돌 방지 + 'prettier/prettier': true, + + // 미디어쿼리 표기법 (e.g. @media (max-width: 600px)) + 'media-feature-range-notation': 'prefix', + + // BEM + kebab-case 강제 + 'selector-class-pattern': [ + '^[a-z][a-z0-9-]*(?:__[a-z0-9-]+)*(?:--[a-z0-9-]+)*$', + { + message: + '클래스 패턴에는 BEM(block__element--modifier) 또는 kebab-case(user-profile)만을 사용해야 합니다.', + }, + ], + }, +}; diff --git a/README.md b/README.md index 58beeacc..7c4a397d 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,150 @@ -# Getting Started with Create React App +## Sprint Misson 5 -This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). +### 요구사항 -## Available Scripts +- [x] 중고마켓 페이지 주소는 “/items” 입니다. +- [x] 페이지 주소가 “/items” 일때 상단네비게이션바의 “중고마켓" 버튼의 색상은 “3692FF”입니다. +- [x] 상단 네비게이션 바는 이전 미션에서 구현한 랜딩 페이지와 동일한 스타일로 만들어 주세요. +- [x] 전체 상품에서 드롭 다운으로 “최신 순” 또는 “좋아요 순”을 선택해서 정렬을 할 수 있습니다. +- [x] 베스트 상품의 정렬 기준은 `favorit`, **favorit이 가장 높은 상품 4가지**를 표시합니다. +- [x] ‘상품 등록하기’ 버튼을 누르면 “/additem” 로 이동합니다. ( 빈 페이지 ) +- [x] 카드 데이터는 제공된 백엔드 API 페이지의 GET 메소드인 “/products”를 사용해주세요. +- [x] 미디어 쿼리를 사용하여 반응형 view 마다 물품 개수를 다르게 보여줍니다 (서버로 요청하는 값은 동일) +- [x] 페이지 네이션 기능을 구현합니다. +- [x] 반응형으로 보여지는 물품들의 개수를 다르게 설정할때 서버에 보내는 pageSize값을 적절하게 설정합니다. -In the project directory, you can run: + > > #### 베스트 상품 + > + > - Desktop : 4개 보이기 + > - Tablet : 2개 보이기 + > - Mobile : 1개 보이기 + > + > > #### 전체 상품 + > + > - Desktop : 10개 보이기 + > - Tablet : 6개 보이기 + > - Mobile : 4개 보이기 -### `npm start` +### 추가 구현사항 -Runs the app in the development mode.\ -Open [http://localhost:3000](http://localhost:3000) to view it in your browser. +- [x] ESLint, Stylelint, Prettier, Husky 사용 +- [x] Vite 번들러 기반으로 변경 +- [x] ts 기반으로 제작 +- [ ] 테스트 코드 제작 +- [x] 재사용 가능한 부분들을 커스텀 훅 사용 +- [x] 스켈레톤 디자인 로딩 화면 제작 -The page will reload when you make changes.\ -You may also see any lint errors in the console. +## 구현 -### `npm test` +### 1. 프로젝트 환경 세팅 -Launches the test runner in the interactive watch mode.\ -See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. +- Vite + TypeScript로 초기화 -### `npm run build` +- ESLint, Stylelint, Prettier, Husky 연동 -Builds the app for production to the `build` folder.\ -It correctly bundles React in production mode and optimizes the build for the best performance. +### 2. 라우팅 구조 잡기 -The build is minified and the filenames include the hashes.\ -Your app is ready to be deployed! +- / (랜딩 페이지) -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. +- /board (자유게시판) -### `npm run eject` +- /items (중고마켓) -**Note: this is a one-way operation. Once you `eject`, you can't go back!** +- /additem (상품등록 빈 페이지) -If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. +### 3. 글로벌 인증 컨텍스트 -Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. +- AuthProvider 생성: user, isLoggedIn 상태 관리 -You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. +- useAuth 훅으로 상태 접근 및 setUser 제공 -## Learn More +- useAuthService 훅으로 로그인·로그아웃 비즈니스 로직 분리 -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). +### 4. 헤더 컴포넌트 구현 -To learn React, check out the [React documentation](https://reactjs.org/). +- 로고 / 내비게이션 버튼 -### Code Splitting +- 로그인 상태에 따라 UserProfile ↔️ 로그인 | 회원가입 버튼 표시 -This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) +- useAuthService.login으로 모의 로그인 처리 -### Analyzing the Bundle Size +- useAuthService.logout 수행 -This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) +- [todo]: 기존 회원가입 로그인 페이지 마이그레이션 및 인증 수행 -### Making a Progressive Web App +### 5. 미디어 쿼리용 훅 제작 -This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) +- useMediaQuery 로 현재 브레이크포인트(mobile/tablet/desktop) 반환 -### Advanced Configuration +- getMediaCount 로 각 뷰포트별 bestProductsCount·allProductsCount 제공 -This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) +### 6. API 연동 -### Deployment +- fetchProducts(page, pageSize, sort, keyword) 함수 작성 -This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) +- axios 기반 에러 핸들링 로직 구현 -### `npm run build` fails to minify +### 7. API 호출 / 로딩 / 에러 훅 -This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) +- useApi(apiFn, deps) 훅: loading·data·error 상태 자동 관리 + +- useCallback 으로 apiFn 메모이제이션 + +### 8. 베스트 상품 컴포넌트 + +- bestProductsCount 따라 1/2/4개 요청 + +- useApi(() => fetchProducts(1, count, 'favorite', ''), [count]) + +- ProductCard + 로딩 스켈레톤 SkeletonCard 렌더링 + +### 9. 전체 상품 컴포넌트 + +- page, sort, keyword 상태 선언 + +- 헤더(AllProductsHeader) 분리: 검색·정렬·등록 + +- useDebounce 커스텀 훅으로 검색어 300ms 디바운스 + +- useApi(() => fetchProducts(page, pageSize, sort, debouncedKeyword), [...]) + +- ProductCard + 로딩 스켈레톤 그리드 표시 + +### 10. 페이지네이션 컴포넌트 + +- totalPages = ceil(totalCount / pageSize) 계산 + +- 최대 5개 버튼: 현재 페이지 중심으로 앞뒤 2개씩 + +- “‹”, “›” 이전·다음 버튼 + +- 클릭 시 setPage 호출 → useApi 자동 재호출 + +### 11. 반응형 스타일링 + +- Mobile / Tablet / Desktop 에 따라 + +- 베스트 상품: 1/2/4 컬럼 + +- 전체 상품: 4/6/10 개 요청, 그리드 컬럼 수 조절 + +- 검색·정렬 UI 배치 변경 + +- select 아이콘을 모바일에서는 원형 버튼, 태블릿 이상에서 텍스트+화살표로 + +### todo + +- 상태 관리 최적화 필요 +- 가독성 향상 및 관심사 분리 재확인 +- 페이지네이션에서 현재 페이지를 볼 수 있도록 유저 경험 향상 +- 컴포넌트 메모이제이션 +- 기존 페이지들 마이그레이션 +- 테스트 코드 작성(API 유틸, 훅, 주요 컴포넌트 단위 테스트) +- notFound페이지 제작 +- 오류 상황시 UI로 보여줄 수 있도록 함 + +### issue + +- 아직 `srcset` 적용이 잘 안된다. +- `AllProductHeader`에서 반응형 css가 미흡한거같다. +- 타입 선언에서 혼동이 온다. diff --git a/dist/_redirects b/dist/_redirects new file mode 100644 index 00000000..3f3fa69f --- /dev/null +++ b/dist/_redirects @@ -0,0 +1,3 @@ +# public/_redirects + +/* /index.html 200 \ No newline at end of file diff --git a/dist/assets/Pretendard-Light-knQmDAda.woff2 b/dist/assets/Pretendard-Light-knQmDAda.woff2 new file mode 100644 index 00000000..7f82fe84 Binary files /dev/null and b/dist/assets/Pretendard-Light-knQmDAda.woff2 differ diff --git a/dist/assets/Pretendard-Medium-Dw2vNklR.woff2 b/dist/assets/Pretendard-Medium-Dw2vNklR.woff2 new file mode 100644 index 00000000..f8c743d6 Binary files /dev/null and b/dist/assets/Pretendard-Medium-Dw2vNklR.woff2 differ diff --git a/dist/assets/Pretendard-Regular-BhrLQoBv.woff2 b/dist/assets/Pretendard-Regular-BhrLQoBv.woff2 new file mode 100644 index 00000000..a9f62319 Binary files /dev/null and b/dist/assets/Pretendard-Regular-BhrLQoBv.woff2 differ diff --git a/dist/assets/Pretendard-SemiBold-ClEDdoZU.woff2 b/dist/assets/Pretendard-SemiBold-ClEDdoZU.woff2 new file mode 100644 index 00000000..4c6a32de Binary files /dev/null and b/dist/assets/Pretendard-SemiBold-ClEDdoZU.woff2 differ diff --git a/dist/assets/Pretendard-Thin-DWJVAZ2K.woff2 b/dist/assets/Pretendard-Thin-DWJVAZ2K.woff2 new file mode 100644 index 00000000..6c9bc960 Binary files /dev/null and b/dist/assets/Pretendard-Thin-DWJVAZ2K.woff2 differ diff --git a/dist/assets/heart-fill-BP4_qiU3.png b/dist/assets/heart-fill-BP4_qiU3.png new file mode 100644 index 00000000..e459771c Binary files /dev/null and b/dist/assets/heart-fill-BP4_qiU3.png differ diff --git a/dist/assets/heart-orwlBO01.png b/dist/assets/heart-orwlBO01.png new file mode 100644 index 00000000..bbf0d9fb Binary files /dev/null and b/dist/assets/heart-orwlBO01.png differ diff --git a/dist/assets/index-B2dI_jp_.css b/dist/assets/index-B2dI_jp_.css new file mode 100644 index 00000000..e02ba232 --- /dev/null +++ b/dist/assets/index-B2dI_jp_.css @@ -0,0 +1 @@ +@charset "UTF-8";*,*:before,*:after{box-sizing:border-box}ol,ul{list-style:none}a{text-decoration:none;color:inherit}button,input,select,textarea{font:inherit;background:none;border:none;outline:none}img,video,canvas,svg{display:block;max-width:100%}h1,h2,h3,h4,h5,h6,p{margin:0}@font-face{font-family:Pretendard;src:url(/assets/Pretendard-Light-knQmDAda.woff2) format("woff2");font-weight:300;font-style:normal;font-display:swap}@font-face{font-family:Pretendard;src:url(/assets/Pretendard-Regular-BhrLQoBv.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap}@font-face{font-family:Pretendard;src:url(/assets/Pretendard-Medium-Dw2vNklR.woff2) format("woff2");font-weight:500;font-style:normal;font-display:swap}@font-face{font-family:Pretendard;src:url(/assets/Pretendard-SemiBold-ClEDdoZU.woff2) format("woff2");font-weight:600;font-style:normal;font-display:swap}@font-face{font-family:Pretendard;src:url(/assets/Pretendard-Thin-DWJVAZ2K.woff2) format("woff2");font-weight:100;font-style:normal;font-display:swap}*{box-sizing:border-box}html{font-family:var(--font-family-base);font-size:16px}body{margin:0}.pointer{cursor:pointer}._app_w7qyt_61{display:flex;flex-direction:column;min-height:100vh}._main_w7qyt_67{flex:1;margin-top:70px}._market-page_1vbk8_61{display:flex;flex-direction:column;align-items:center;width:100%;max-width:var(--market-container-max-width);margin:0 auto;padding:var(--spacing-xs);gap:var(--spacing-md)}@media (min-width: 768px) and (max-width: 1199px){._market-page_1vbk8_61{padding:var(--spacing-md);gap:var(--spacing-lg)}}._best-products_edrbh_61{width:100%;max-width:1200px;display:flex;flex-direction:column;gap:20px}._best-products__title_edrbh_68{width:100%;font-size:var(--font-title-md);font-weight:700;margin-bottom:20px}._best-products__list_edrbh_74{display:grid;gap:var(--spacing-xs);grid-template-columns:1fr;grid-template-rows:1fr}@media (min-width: 768px) and (max-width: 1199px){._best-products__list_edrbh_74{grid-template-columns:repeat(2,1fr);grid-template-rows:1fr}}@media (min-width: 1200px){._best-products__list_edrbh_74{grid-template-columns:repeat(4,1fr);grid-template-rows:1fr}}._product-card_jd2w9_61{display:flex;flex:1 1 0;flex-direction:column;background-color:var(--color-background);border-radius:20px;transition:box-shadow .2s ease;gap:6px}._product-card_jd2w9_61:hover{transform:translateY(-4px);box-shadow:0 8px 20px #0000001a}._product-card__image_jd2w9_74{width:100%;aspect-ratio:1/1;border-radius:20px;object-fit:cover}._product-card__info_jd2w9_80{display:flex;flex-direction:column;gap:6px;padding:6px}._product-card__title_jd2w9_86{font-size:var(--font-content-sm);font-weight:100;color:var(--color-neutral-800)}._product-card__price_jd2w9_91{font-size:var(--font-content-md);font-weight:700;color:var(--color-neutral-800)}._product-card__like_jd2w9_96{display:flex;align-items:center;gap:4px;font-size:var(--font-content-xs);color:var(--color-neutral-500)}._product-card__like-icon_jd2w9_103{width:var(--font-label-xs);fill:var(--color-neutral-500)}@keyframes _pulse_arffm_1{0%,to{opacity:1}50%{opacity:.4}}._skeleton-card_arffm_70{display:flex;flex:1 1 0;flex-direction:column;background-color:#f0f0f0;border-radius:20px;overflow:hidden;gap:6px;animation:_pulse_arffm_1 1.5s ease-in-out infinite}._skeleton-card__image_arffm_80{width:100%;aspect-ratio:1/1;background-color:#e0e0e0}._skeleton-card__info_arffm_85{display:flex;flex-direction:column;gap:6px;padding:6px}._skeleton-card__title_arffm_91{width:60%;height:16px;background-color:#e0e0e0;border-radius:4px}._skeleton-card__price_arffm_97{width:40%;height:16px;background-color:#e0e0e0;border-radius:4px}._skeleton-card__like_arffm_103{width:30%;height:14px;background-color:#e0e0e0;border-radius:4px}._all-products-header_17gbo_61{display:flex;justify-content:space-between;align-items:flex-start;flex-direction:column}@media (min-width: 768px) and (max-width: 1199px){._all-products-header_17gbo_61{flex-direction:row;align-items:center}}@media (min-width: 1200px){._all-products-header_17gbo_61{flex-direction:row;align-items:center}}._all-products-header__title_17gbo_79{font-size:var(--font-title-md);font-weight:700;margin-bottom:20px;width:100%;max-width:100px}._all-products-header__filter-wrap_17gbo_86{width:100%;display:flex;align-items:center;justify-content:end;gap:10px;position:relative}._all-products-header__search_17gbo_94{flex:1;min-width:200px;width:100%;padding:10px 20px;border:1px solid var(--color-neutral-300);border-radius:12px;font-size:var(--font-content-sm);color:var(--color-neutral-800);background-color:var(--color-neutral-100);outline:none;transition:border-color .2s ease}@media (min-width: 768px) and (max-width: 1199px){._all-products-header__search_17gbo_94{max-width:325px}}@media (min-width: 1200px){._all-products-header__search_17gbo_94{max-width:400px}}._all-products-header__search_17gbo_94:focus{border-color:var(--color-primary-500)}._all-products-header__add_17gbo_120{padding:12px 24px;font-size:var(--font-content-md);font-weight:700;color:#fff;background-color:var(--color-primary-100);border-radius:8px;cursor:pointer;position:absolute;bottom:50px;right:10px}@media (min-width: 768px) and (max-width: 1199px){._all-products-header__add_17gbo_120{position:relative;bottom:0;right:0}}@media (min-width: 1200px){._all-products-header__add_17gbo_120{position:relative;bottom:0;right:0}}._all-products-header__filter_17gbo_86{border:2px solid var(--color-neutral-200);border-radius:13px;padding:9px;width:40px;background-repeat:no-repeat;background-position:center;background-size:24px;color:transparent;text-indent:9999px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAE7SURBVHgB7VOxSsRAEH1zCcp1aWx1LQRFi1iIh1X8hPsCvS/QP9E/8D7BT0gldqYRBAsXbASbNGqhyTi7R4zcHosXc82RB4Gdt7PvbWZmgQ5LjwANofYGSbS2HuWvzy++vHDWQTCUm9rL9P1NVkVc8gW4iGS5iXkMJgcRO5n0ZcT360RE+AMcA/oMRlgpXYOCNBrAMdCPtgwZWkI4i1TbAyXtT36IknJ8rKZapznaMADxOZc4qwkG9d+HsrhGKwZMlxRMlemtn2KRULsH8cbO4Z2U78TEsn4yn90Tzu6ZEZ9C6BWt3oTpQVkYKmbisQgKzajEDWcD7jk9Ip+B3IrrRB6KQCRiV79SjKB9D8Q00g+3Y8zzB3LoWKZJ2UB6YKbI3r428YpPLtYAYnJamfjE/wW1dRSLUYIOHb4B1ylwvCUl1SoAAAAASUVORK5CYII=)}@media (min-width: 768px) and (max-width: 1199px){._all-products-header__filter_17gbo_86{background-image:none;width:auto;color:var(--color-neutral-800);text-indent:0;padding:12px 20px}}@media (min-width: 1200px){._all-products-header__filter_17gbo_86{width:auto;background-image:none;color:var(--color-neutral-800);text-indent:0;padding:12px 20px}}._all-products_tkmgf_61{width:100%;max-width:1200px;display:flex;flex-direction:column;gap:20px}._all-products__list_tkmgf_68{display:grid;gap:var(--spacing-xs);grid-template-columns:repeat(2,1fr);grid-template-rows:repeat(2,1fr)}@media (min-width: 768px) and (max-width: 1199px){._all-products__list_tkmgf_68{grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(2,1fr)}}@media (min-width: 1200px){._all-products__list_tkmgf_68{grid-template-columns:repeat(5,1fr);grid-template-rows:repeat(2,1fr)}}._pagination_1opqe_61{display:flex;justify-content:center;align-items:center;gap:8px;margin:24px 0}._pageBtn_1opqe_69{width:40px;height:40px;border:1px solid var(--color-neutral-200);border-radius:50%;background-color:#fff;color:var(--color-neutral-800);font-size:var(--font-content-md);cursor:pointer;transition:background-color .2s,color .2s}._pageBtn_1opqe_69:disabled{opacity:.6;cursor:not-allowed}._pageBtn_1opqe_69._active_1opqe_84{background-color:var(--color-primary-100);color:#fff}._pageBtn_1opqe_69:hover:not(:disabled){background-color:var(--color-neutral-100)}._header_1vwqq_61{position:fixed;top:0;left:0;right:0;height:70px;background:#fff;border-bottom:1px solid var(--color-neutral-200);z-index:1000}._header__container_1vwqq_74{max-width:var(--container-max-width);height:100%;margin:0 auto;padding:9px var(--spacing-xs);display:flex;align-items:center;justify-content:space-between}@media (min-width: 768px) and (max-width: 1199px){._header__container_1vwqq_74{padding:9px var(--spacing-md)}}@media (min-width: 1200px){._header__container_1vwqq_74{padding:9px var(--container-padding)}}._header__leftwrap_1vwqq_93{display:flex;align-items:center;gap:var(--spacing-md)}@media (min-width: 768px) and (max-width: 1199px){._header__leftwrap_1vwqq_93{gap:var(--spacing-lg)}}._header__logo_1vwqq_103{display:block}._header__logo_1vwqq_103 img{display:block;height:2.5rem}._header__nav_1vwqq_110{display:flex;gap:var(--spacing-sm);font-size:var(--font-content-xs);font-weight:700}@media (min-width: 768px) and (max-width: 1199px){._header__nav_1vwqq_110{gap:var(--spacing-md)}}@media (min-width: 1200px){._header__nav_1vwqq_110{gap:var(--spacing-lg)}}._header__nav-item_1vwqq_126{font-size:var(--font-content-sm);color:var(--color-neutral-700);text-decoration:none;transition:color .2s,font-size .2s}._header__nav-item_1vwqq_126:hover,._header__nav-item_1vwqq_126:active{color:var(--color-primary-100);transform:scale(1.05)}._header__login_1vwqq_136{background:none;border:none;cursor:pointer;padding:var(--spacing-xs)}._header__login_1vwqq_136 svg{width:1.5rem;height:1.5rem;fill:var(--color-neutral-700);transition:fill .2s}._header__login_1vwqq_136:hover svg{fill:var(--color-primary-100)}:root{--font-family-base: "Pretendard", sans-serif;--font-title-lx: 2.5rem;--font-title-lg: 2rem;--font-title-md: 1.5rem;--font-title-sm: 1.25rem;--font-title-xs: 1.125rem;--font-content-xl: 1.5rem;--font-content-lg: 1.25rem;--font-content-md: 1rem;--font-content-sm: .875rem;--font-content-xs: .75rem;--font-label-xl: 1.25rem;--font-label-lg: 1.125rem;--font-label-md: 1rem;--font-label-sm: .875rem;--font-label-xs: .75rem;--color-primary-100: #3692ff;--color-secondary-50: #fcfcfc;--color-secondary-100: #e6f2ff;--color-secondary-200: #cfe5ff;--color-neutral-50: #f9fafb;--color-neutral-100: #f3f4f6;--color-neutral-200: #e5e7eb;--color-neutral-400: #9ca3af;--color-neutral-500: #6b7280;--color-neutral-600: #4b5563;--color-neutral-700: #374151;--color-neutral-800: #1f2937;--color-neutral-900: #111827;--color-error: red;--spacing-xs: 1rem;--spacing-sm: 1.125rem;--spacing-md: 1.5rem;--spacing-lg: 2.5rem;--spacing-xl: 8rem;--container-max-width: 1920px;--container-padding: 200px;--container-padding-tablet: 104px;--container-top-margin: 231px;--container-top-margin-sm: 80px;--auth-container-max-width: 640px;--auth-container-max-width-sm: 400px;--market-container-max-width: 1200px;--tablet-max-width: 1199px;--mobile-max-width: 767px;--radius-button: 40px}user-profile{display:flex;align-items:center;gap:.5rem;padding:.5rem;background-color:var(--color-background);border-radius:.25rem}user-profile__avatar{width:2rem;height:2rem;border-radius:50%;overflow:hidden} diff --git a/dist/assets/index-ZpV3HMJG.js b/dist/assets/index-ZpV3HMJG.js new file mode 100644 index 00000000..3c5ede07 --- /dev/null +++ b/dist/assets/index-ZpV3HMJG.js @@ -0,0 +1,47 @@ +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const l of document.querySelectorAll('link[rel="modulepreload"]'))r(l);new MutationObserver(l=>{for(const o of l)if(o.type==="childList")for(const i of o.addedNodes)i.tagName==="LINK"&&i.rel==="modulepreload"&&r(i)}).observe(document,{childList:!0,subtree:!0});function n(l){const o={};return l.integrity&&(o.integrity=l.integrity),l.referrerPolicy&&(o.referrerPolicy=l.referrerPolicy),l.crossOrigin==="use-credentials"?o.credentials="include":l.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function r(l){if(l.ep)return;l.ep=!0;const o=n(l);fetch(l.href,o)}})();function bd(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var Wa={exports:{}},Yl={},$a={exports:{}},I={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Pr=Symbol.for("react.element"),ep=Symbol.for("react.portal"),tp=Symbol.for("react.fragment"),np=Symbol.for("react.strict_mode"),rp=Symbol.for("react.profiler"),lp=Symbol.for("react.provider"),op=Symbol.for("react.context"),ip=Symbol.for("react.forward_ref"),up=Symbol.for("react.suspense"),sp=Symbol.for("react.memo"),ap=Symbol.for("react.lazy"),as=Symbol.iterator;function cp(e){return e===null||typeof e!="object"?null:(e=as&&e[as]||e["@@iterator"],typeof e=="function"?e:null)}var Qa={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Ka=Object.assign,qa={};function Pn(e,t,n){this.props=e,this.context=t,this.refs=qa,this.updater=n||Qa}Pn.prototype.isReactComponent={};Pn.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Pn.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function Ya(){}Ya.prototype=Pn.prototype;function ru(e,t,n){this.props=e,this.context=t,this.refs=qa,this.updater=n||Qa}var lu=ru.prototype=new Ya;lu.constructor=ru;Ka(lu,Pn.prototype);lu.isPureReactComponent=!0;var cs=Array.isArray,Ja=Object.prototype.hasOwnProperty,ou={current:null},Xa={key:!0,ref:!0,__self:!0,__source:!0};function Ga(e,t,n){var r,l={},o=null,i=null;if(t!=null)for(r in t.ref!==void 0&&(i=t.ref),t.key!==void 0&&(o=""+t.key),t)Ja.call(t,r)&&!Xa.hasOwnProperty(r)&&(l[r]=t[r]);var u=arguments.length-2;if(u===1)l.children=n;else if(1>>1,ee=A[J];if(0>>1;Jl(ko,z))ztl(Dr,ko)?(A[J]=Dr,A[zt]=z,J=zt):(A[J]=ko,A[jt]=z,J=jt);else if(ztl(Dr,z))A[J]=Dr,A[zt]=z,J=zt;else break e}}return j}function l(A,j){var z=A.sortIndex-j.sortIndex;return z!==0?z:A.id-j.id}if(typeof performance=="object"&&typeof performance.now=="function"){var o=performance;e.unstable_now=function(){return o.now()}}else{var i=Date,u=i.now();e.unstable_now=function(){return i.now()-u}}var s=[],a=[],c=1,h=null,m=3,g=!1,y=!1,v=!1,E=typeof setTimeout=="function"?setTimeout:null,d=typeof clearTimeout=="function"?clearTimeout:null,f=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function p(A){for(var j=n(a);j!==null;){if(j.callback===null)r(a);else if(j.startTime<=A)r(a),j.sortIndex=j.expirationTime,t(s,j);else break;j=n(a)}}function k(A){if(v=!1,p(A),!y)if(n(s)!==null)y=!0,So(C);else{var j=n(a);j!==null&&Eo(k,j.startTime-A)}}function C(A,j){y=!1,v&&(v=!1,d(T),T=-1),g=!0;var z=m;try{for(p(j),h=n(s);h!==null&&(!(h.expirationTime>j)||A&&!me());){var J=h.callback;if(typeof J=="function"){h.callback=null,m=h.priorityLevel;var ee=J(h.expirationTime<=j);j=e.unstable_now(),typeof ee=="function"?h.callback=ee:h===n(s)&&r(s),p(j)}else r(s);h=n(s)}if(h!==null)var Ir=!0;else{var jt=n(a);jt!==null&&Eo(k,jt.startTime-j),Ir=!1}return Ir}finally{h=null,m=z,g=!1}}var R=!1,P=null,T=-1,F=5,L=-1;function me(){return!(e.unstable_now()-LA||125J?(A.sortIndex=z,t(a,A),n(s)===null&&A===n(a)&&(v?(d(T),T=-1):v=!0,Eo(k,z-J))):(A.sortIndex=ee,t(s,A),y||g||(y=!0,So(C))),A},e.unstable_shouldYield=me,e.unstable_wrapCallback=function(A){var j=m;return function(){var z=m;m=j;try{return A.apply(this,arguments)}finally{m=z}}}})(tc);ec.exports=tc;var kp=ec.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var nc=S,Re=kp;function x(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),ri=Object.prototype.hasOwnProperty,xp=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,ds={},ps={};function Cp(e){return ri.call(ps,e)?!0:ri.call(ds,e)?!1:xp.test(e)?ps[e]=!0:(ds[e]=!0,!1)}function _p(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function Rp(e,t,n,r){if(t===null||typeof t>"u"||_p(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function he(e,t,n,r,l,o,i){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=l,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=o,this.removeEmptyString=i}var oe={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){oe[e]=new he(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];oe[t]=new he(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){oe[e]=new he(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){oe[e]=new he(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){oe[e]=new he(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){oe[e]=new he(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){oe[e]=new he(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){oe[e]=new he(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){oe[e]=new he(e,5,!1,e.toLowerCase(),null,!1,!1)});var uu=/[\-:]([a-z])/g;function su(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(uu,su);oe[t]=new he(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(uu,su);oe[t]=new he(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(uu,su);oe[t]=new he(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){oe[e]=new he(e,1,!1,e.toLowerCase(),null,!1,!1)});oe.xlinkHref=new he("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){oe[e]=new he(e,1,!1,e.toLowerCase(),null,!0,!0)});function au(e,t,n,r){var l=oe.hasOwnProperty(t)?oe[t]:null;(l!==null?l.type!==0:r||!(2u||l[i]!==o[u]){var s=` +`+l[i].replace(" at new "," at ");return e.displayName&&s.includes("")&&(s=s.replace("",e.displayName)),s}while(1<=i&&0<=u);break}}}finally{_o=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?Yn(e):""}function Pp(e){switch(e.tag){case 5:return Yn(e.type);case 16:return Yn("Lazy");case 13:return Yn("Suspense");case 19:return Yn("SuspenseList");case 0:case 2:case 15:return e=Ro(e.type,!1),e;case 11:return e=Ro(e.type.render,!1),e;case 1:return e=Ro(e.type,!0),e;default:return""}}function ui(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case nn:return"Fragment";case tn:return"Portal";case li:return"Profiler";case cu:return"StrictMode";case oi:return"Suspense";case ii:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case oc:return(e.displayName||"Context")+".Consumer";case lc:return(e._context.displayName||"Context")+".Provider";case fu:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case du:return t=e.displayName||null,t!==null?t:ui(e.type)||"Memo";case pt:t=e._payload,e=e._init;try{return ui(e(t))}catch{}}return null}function Np(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return ui(t);case 8:return t===cu?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Pt(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function uc(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function Ap(e){var t=uc(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var l=n.get,o=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(i){r=""+i,o.call(this,i)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(i){r=""+i},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Br(e){e._valueTracker||(e._valueTracker=Ap(e))}function sc(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=uc(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Sl(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function si(e,t){var n=t.checked;return K({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function ms(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=Pt(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function ac(e,t){t=t.checked,t!=null&&au(e,"checked",t,!1)}function ai(e,t){ac(e,t);var n=Pt(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?ci(e,t.type,n):t.hasOwnProperty("defaultValue")&&ci(e,t.type,Pt(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function ys(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function ci(e,t,n){(t!=="number"||Sl(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Jn=Array.isArray;function hn(e,t,n,r){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=Hr.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function ar(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var bn={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Tp=["Webkit","ms","Moz","O"];Object.keys(bn).forEach(function(e){Tp.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),bn[t]=bn[e]})});function pc(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||bn.hasOwnProperty(e)&&bn[e]?(""+t).trim():t+"px"}function hc(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,l=pc(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,l):e[n]=l}}var Lp=K({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function pi(e,t){if(t){if(Lp[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(x(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(x(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(x(61))}if(t.style!=null&&typeof t.style!="object")throw Error(x(62))}}function hi(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var mi=null;function pu(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var yi=null,mn=null,yn=null;function ws(e){if(e=Tr(e)){if(typeof yi!="function")throw Error(x(280));var t=e.stateNode;t&&(t=bl(t),yi(e.stateNode,e.type,t))}}function mc(e){mn?yn?yn.push(e):yn=[e]:mn=e}function yc(){if(mn){var e=mn,t=yn;if(yn=mn=null,ws(e),t)for(e=0;e>>=0,e===0?32:31-(Vp(e)/Wp|0)|0}var Vr=64,Wr=4194304;function Xn(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Cl(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,l=e.suspendedLanes,o=e.pingedLanes,i=n&268435455;if(i!==0){var u=i&~l;u!==0?r=Xn(u):(o&=i,o!==0&&(r=Xn(o)))}else i=n&~l,i!==0?r=Xn(i):o!==0&&(r=Xn(o));if(r===0)return 0;if(t!==0&&t!==r&&!(t&l)&&(l=r&-r,o=t&-t,l>=o||l===16&&(o&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function Nr(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-Ue(t),e[t]=n}function qp(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=tr),Ns=" ",As=!1;function Ic(e,t){switch(e){case"keyup":return Eh.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Dc(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var rn=!1;function xh(e,t){switch(e){case"compositionend":return Dc(t);case"keypress":return t.which!==32?null:(As=!0,Ns);case"textInput":return e=t.data,e===Ns&&As?null:e;default:return null}}function Ch(e,t){if(rn)return e==="compositionend"||!Eu&&Ic(e,t)?(e=zc(),ol=gu=vt=null,rn=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=js(n)}}function Hc(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Hc(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Vc(){for(var e=window,t=Sl();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Sl(e.document)}return t}function ku(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function jh(e){var t=Vc(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&Hc(n.ownerDocument.documentElement,n)){if(r!==null&&ku(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=n.textContent.length,o=Math.min(r.start,l);r=r.end===void 0?o:Math.min(r.end,l),!e.extend&&o>r&&(l=r,r=o,o=l),l=zs(n,o);var i=zs(n,r);l&&i&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==i.node||e.focusOffset!==i.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),o>r?(e.addRange(t),e.extend(i.node,i.offset)):(t.setEnd(i.node,i.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,ln=null,ki=null,rr=null,xi=!1;function Fs(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;xi||ln==null||ln!==Sl(r)||(r=ln,"selectionStart"in r&&ku(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),rr&&mr(rr,r)||(rr=r,r=Pl(ki,"onSelect"),0sn||(e.current=Ai[sn],Ai[sn]=null,sn--)}function U(e,t){sn++,Ai[sn]=e.current,e.current=t}var Nt={},ce=Tt(Nt),ge=Tt(!1),$t=Nt;function En(e,t){var n=e.type.contextTypes;if(!n)return Nt;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var l={},o;for(o in n)l[o]=t[o];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function we(e){return e=e.childContextTypes,e!=null}function Al(){H(ge),H(ce)}function Vs(e,t,n){if(ce.current!==Nt)throw Error(x(168));U(ce,t),U(ge,n)}function Gc(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var l in r)if(!(l in t))throw Error(x(108,Np(e)||"Unknown",l));return K({},n,r)}function Tl(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Nt,$t=ce.current,U(ce,e),U(ge,ge.current),!0}function Ws(e,t,n){var r=e.stateNode;if(!r)throw Error(x(169));n?(e=Gc(e,t,$t),r.__reactInternalMemoizedMergedChildContext=e,H(ge),H(ce),U(ce,e)):H(ge),U(ge,n)}var et=null,eo=!1,Bo=!1;function Zc(e){et===null?et=[e]:et.push(e)}function Qh(e){eo=!0,Zc(e)}function Lt(){if(!Bo&&et!==null){Bo=!0;var e=0,t=M;try{var n=et;for(M=1;e>=i,l-=i,tt=1<<32-Ue(t)+l|n<T?(F=P,P=null):F=P.sibling;var L=m(d,P,p[T],k);if(L===null){P===null&&(P=F);break}e&&P&&L.alternate===null&&t(d,P),f=o(L,f,T),R===null?C=L:R.sibling=L,R=L,P=F}if(T===p.length)return n(d,P),V&&Ft(d,T),C;if(P===null){for(;TT?(F=P,P=null):F=P.sibling;var me=m(d,P,L.value,k);if(me===null){P===null&&(P=F);break}e&&P&&me.alternate===null&&t(d,P),f=o(me,f,T),R===null?C=me:R.sibling=me,R=me,P=F}if(L.done)return n(d,P),V&&Ft(d,T),C;if(P===null){for(;!L.done;T++,L=p.next())L=h(d,L.value,k),L!==null&&(f=o(L,f,T),R===null?C=L:R.sibling=L,R=L);return V&&Ft(d,T),C}for(P=r(d,P);!L.done;T++,L=p.next())L=g(P,d,T,L.value,k),L!==null&&(e&&L.alternate!==null&&P.delete(L.key===null?T:L.key),f=o(L,f,T),R===null?C=L:R.sibling=L,R=L);return e&&P.forEach(function(Fn){return t(d,Fn)}),V&&Ft(d,T),C}function E(d,f,p,k){if(typeof p=="object"&&p!==null&&p.type===nn&&p.key===null&&(p=p.props.children),typeof p=="object"&&p!==null){switch(p.$$typeof){case Ur:e:{for(var C=p.key,R=f;R!==null;){if(R.key===C){if(C=p.type,C===nn){if(R.tag===7){n(d,R.sibling),f=l(R,p.props.children),f.return=d,d=f;break e}}else if(R.elementType===C||typeof C=="object"&&C!==null&&C.$$typeof===pt&&Xs(C)===R.type){n(d,R.sibling),f=l(R,p.props),f.ref=Vn(d,R,p),f.return=d,d=f;break e}n(d,R);break}else t(d,R);R=R.sibling}p.type===nn?(f=Vt(p.props.children,d.mode,k,p.key),f.return=d,d=f):(k=pl(p.type,p.key,p.props,null,d.mode,k),k.ref=Vn(d,f,p),k.return=d,d=k)}return i(d);case tn:e:{for(R=p.key;f!==null;){if(f.key===R)if(f.tag===4&&f.stateNode.containerInfo===p.containerInfo&&f.stateNode.implementation===p.implementation){n(d,f.sibling),f=l(f,p.children||[]),f.return=d,d=f;break e}else{n(d,f);break}else t(d,f);f=f.sibling}f=Yo(p,d.mode,k),f.return=d,d=f}return i(d);case pt:return R=p._init,E(d,f,R(p._payload),k)}if(Jn(p))return y(d,f,p,k);if(Dn(p))return v(d,f,p,k);Xr(d,p)}return typeof p=="string"&&p!==""||typeof p=="number"?(p=""+p,f!==null&&f.tag===6?(n(d,f.sibling),f=l(f,p),f.return=d,d=f):(n(d,f),f=qo(p,d.mode,k),f.return=d,d=f),i(d)):n(d,f)}return E}var xn=uf(!0),sf=uf(!1),Lr={},Ge=Tt(Lr),wr=Tt(Lr),Sr=Tt(Lr);function Ut(e){if(e===Lr)throw Error(x(174));return e}function Lu(e,t){switch(U(Sr,t),U(wr,e),U(Ge,Lr),e=t.nodeType,e){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:di(null,"");break;default:e=e===8?t.parentNode:t,t=e.namespaceURI||null,e=e.tagName,t=di(t,e)}H(Ge),U(Ge,t)}function Cn(){H(Ge),H(wr),H(Sr)}function af(e){Ut(Sr.current);var t=Ut(Ge.current),n=di(t,e.type);t!==n&&(U(wr,e),U(Ge,n))}function Ou(e){wr.current===e&&(H(Ge),H(wr))}var $=Tt(0);function Il(e){for(var t=e;t!==null;){if(t.tag===13){var n=t.memoizedState;if(n!==null&&(n=n.dehydrated,n===null||n.data==="$?"||n.data==="$!"))return t}else if(t.tag===19&&t.memoizedProps.revealOrder!==void 0){if(t.flags&128)return t}else if(t.child!==null){t.child.return=t,t=t.child;continue}if(t===e)break;for(;t.sibling===null;){if(t.return===null||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var Ho=[];function ju(){for(var e=0;en?n:4,e(!0);var r=Vo.transition;Vo.transition={};try{e(!1),t()}finally{M=n,Vo.transition=r}}function _f(){return ze().memoizedState}function Jh(e,t,n){var r=_t(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Rf(e))Pf(t,n);else if(n=nf(e,t,n,r),n!==null){var l=de();Be(n,e,r,l),Nf(n,t,r)}}function Xh(e,t,n){var r=_t(e),l={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Rf(e))Pf(t,l);else{var o=e.alternate;if(e.lanes===0&&(o===null||o.lanes===0)&&(o=t.lastRenderedReducer,o!==null))try{var i=t.lastRenderedState,u=o(i,n);if(l.hasEagerState=!0,l.eagerState=u,He(u,i)){var s=t.interleaved;s===null?(l.next=l,Au(t)):(l.next=s.next,s.next=l),t.interleaved=l;return}}catch{}finally{}n=nf(e,t,l,r),n!==null&&(l=de(),Be(n,e,r,l),Nf(n,t,r))}}function Rf(e){var t=e.alternate;return e===Q||t!==null&&t===Q}function Pf(e,t){lr=Dl=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Nf(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,mu(e,n)}}var Ml={readContext:je,useCallback:ie,useContext:ie,useEffect:ie,useImperativeHandle:ie,useInsertionEffect:ie,useLayoutEffect:ie,useMemo:ie,useReducer:ie,useRef:ie,useState:ie,useDebugValue:ie,useDeferredValue:ie,useTransition:ie,useMutableSource:ie,useSyncExternalStore:ie,useId:ie,unstable_isNewReconciler:!1},Gh={readContext:je,useCallback:function(e,t){return Ye().memoizedState=[e,t===void 0?null:t],e},useContext:je,useEffect:Zs,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,al(4194308,4,Sf.bind(null,t,e),n)},useLayoutEffect:function(e,t){return al(4194308,4,e,t)},useInsertionEffect:function(e,t){return al(4,2,e,t)},useMemo:function(e,t){var n=Ye();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=Ye();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=Jh.bind(null,Q,e),[r.memoizedState,e]},useRef:function(e){var t=Ye();return e={current:e},t.memoizedState=e},useState:Gs,useDebugValue:Mu,useDeferredValue:function(e){return Ye().memoizedState=e},useTransition:function(){var e=Gs(!1),t=e[0];return e=Yh.bind(null,e[1]),Ye().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=Q,l=Ye();if(V){if(n===void 0)throw Error(x(407));n=n()}else{if(n=t(),ne===null)throw Error(x(349));Kt&30||df(r,t,n)}l.memoizedState=n;var o={value:n,getSnapshot:t};return l.queue=o,Zs(hf.bind(null,r,o,e),[e]),r.flags|=2048,xr(9,pf.bind(null,r,o,n,t),void 0,null),n},useId:function(){var e=Ye(),t=ne.identifierPrefix;if(V){var n=nt,r=tt;n=(r&~(1<<32-Ue(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Er++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=i.createElement(n,{is:r.is}):(e=i.createElement(n),n==="select"&&(i=e,r.multiple?i.multiple=!0:r.size&&(i.size=r.size))):e=i.createElementNS(e,n),e[Je]=t,e[gr]=r,Df(e,t,!1,!1),t.stateNode=e;e:{switch(i=hi(n,r),n){case"dialog":B("cancel",e),B("close",e),l=r;break;case"iframe":case"object":case"embed":B("load",e),l=r;break;case"video":case"audio":for(l=0;lRn&&(t.flags|=128,r=!0,Wn(o,!1),t.lanes=4194304)}else{if(!r)if(e=Il(i),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),Wn(o,!0),o.tail===null&&o.tailMode==="hidden"&&!i.alternate&&!V)return ue(t),null}else 2*X()-o.renderingStartTime>Rn&&n!==1073741824&&(t.flags|=128,r=!0,Wn(o,!1),t.lanes=4194304);o.isBackwards?(i.sibling=t.child,t.child=i):(n=o.last,n!==null?n.sibling=i:t.child=i,o.last=i)}return o.tail!==null?(t=o.tail,o.rendering=t,o.tail=t.sibling,o.renderingStartTime=X(),t.sibling=null,n=$.current,U($,r?n&1|2:n&1),t):(ue(t),null);case 22:case 23:return $u(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?xe&1073741824&&(ue(t),t.subtreeFlags&6&&(t.flags|=8192)):ue(t),null;case 24:return null;case 25:return null}throw Error(x(156,t.tag))}function om(e,t){switch(Cu(t),t.tag){case 1:return we(t.type)&&Al(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Cn(),H(ge),H(ce),ju(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return Ou(t),null;case 13:if(H($),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(x(340));kn()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return H($),null;case 4:return Cn(),null;case 10:return Nu(t.type._context),null;case 22:case 23:return $u(),null;case 24:return null;default:return null}}var Zr=!1,se=!1,im=typeof WeakSet=="function"?WeakSet:Set,N=null;function dn(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){q(e,t,r)}else n.current=null}function Hi(e,t,n){try{n()}catch(r){q(e,t,r)}}var ua=!1;function um(e,t){if(Ci=_l,e=Vc(),ku(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var l=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break e}var i=0,u=-1,s=-1,a=0,c=0,h=e,m=null;t:for(;;){for(var g;h!==n||l!==0&&h.nodeType!==3||(u=i+l),h!==o||r!==0&&h.nodeType!==3||(s=i+r),h.nodeType===3&&(i+=h.nodeValue.length),(g=h.firstChild)!==null;)m=h,h=g;for(;;){if(h===e)break t;if(m===n&&++a===l&&(u=i),m===o&&++c===r&&(s=i),(g=h.nextSibling)!==null)break;h=m,m=h.parentNode}h=g}n=u===-1||s===-1?null:{start:u,end:s}}else n=null}n=n||{start:0,end:0}}else n=null;for(_i={focusedElem:e,selectionRange:n},_l=!1,N=t;N!==null;)if(t=N,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,N=e;else for(;N!==null;){t=N;try{var y=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(y!==null){var v=y.memoizedProps,E=y.memoizedState,d=t.stateNode,f=d.getSnapshotBeforeUpdate(t.elementType===t.type?v:Ie(t.type,v),E);d.__reactInternalSnapshotBeforeUpdate=f}break;case 3:var p=t.stateNode.containerInfo;p.nodeType===1?p.textContent="":p.nodeType===9&&p.documentElement&&p.removeChild(p.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(x(163))}}catch(k){q(t,t.return,k)}if(e=t.sibling,e!==null){e.return=t.return,N=e;break}N=t.return}return y=ua,ua=!1,y}function or(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var o=l.destroy;l.destroy=void 0,o!==void 0&&Hi(t,n,o)}l=l.next}while(l!==r)}}function ro(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function Vi(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Bf(e){var t=e.alternate;t!==null&&(e.alternate=null,Bf(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Je],delete t[gr],delete t[Ni],delete t[Wh],delete t[$h])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Hf(e){return e.tag===5||e.tag===3||e.tag===4}function sa(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Hf(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Wi(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Nl));else if(r!==4&&(e=e.child,e!==null))for(Wi(e,t,n),e=e.sibling;e!==null;)Wi(e,t,n),e=e.sibling}function $i(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for($i(e,t,n),e=e.sibling;e!==null;)$i(e,t,n),e=e.sibling}var re=null,De=!1;function ft(e,t,n){for(n=n.child;n!==null;)Vf(e,t,n),n=n.sibling}function Vf(e,t,n){if(Xe&&typeof Xe.onCommitFiberUnmount=="function")try{Xe.onCommitFiberUnmount(Jl,n)}catch{}switch(n.tag){case 5:se||dn(n,t);case 6:var r=re,l=De;re=null,ft(e,t,n),re=r,De=l,re!==null&&(De?(e=re,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):re.removeChild(n.stateNode));break;case 18:re!==null&&(De?(e=re,n=n.stateNode,e.nodeType===8?Uo(e.parentNode,n):e.nodeType===1&&Uo(e,n),pr(e)):Uo(re,n.stateNode));break;case 4:r=re,l=De,re=n.stateNode.containerInfo,De=!0,ft(e,t,n),re=r,De=l;break;case 0:case 11:case 14:case 15:if(!se&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var o=l,i=o.destroy;o=o.tag,i!==void 0&&(o&2||o&4)&&Hi(n,t,i),l=l.next}while(l!==r)}ft(e,t,n);break;case 1:if(!se&&(dn(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(u){q(n,t,u)}ft(e,t,n);break;case 21:ft(e,t,n);break;case 22:n.mode&1?(se=(r=se)||n.memoizedState!==null,ft(e,t,n),se=r):ft(e,t,n);break;default:ft(e,t,n)}}function aa(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new im),t.forEach(function(r){var l=ym.bind(null,e,r);n.has(r)||(n.add(r),r.then(l,l))})}}function Fe(e,t){var n=t.deletions;if(n!==null)for(var r=0;rl&&(l=i),r&=~o}if(r=l,r=X()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*am(r/1960))-r,10e?16:e,gt===null)var r=!1;else{if(e=gt,gt=null,Hl=0,D&6)throw Error(x(331));var l=D;for(D|=4,N=e.current;N!==null;){var o=N,i=o.child;if(N.flags&16){var u=o.deletions;if(u!==null){for(var s=0;sX()-Vu?Ht(e,0):Hu|=n),Se(e,t)}function Xf(e,t){t===0&&(e.mode&1?(t=Wr,Wr<<=1,!(Wr&130023424)&&(Wr=4194304)):t=1);var n=de();e=ut(e,t),e!==null&&(Nr(e,t,n),Se(e,n))}function mm(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Xf(e,n)}function ym(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(x(314))}r!==null&&r.delete(t),Xf(e,n)}var Gf;Gf=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||ge.current)ve=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return ve=!1,rm(e,t,n);ve=!!(e.flags&131072)}else ve=!1,V&&t.flags&1048576&&bc(t,Ol,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;cl(e,t),e=t.pendingProps;var l=En(t,ce.current);gn(t,n),l=Fu(null,t,r,e,l,n);var o=Iu();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,we(r)?(o=!0,Tl(t)):o=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,Tu(t),l.updater=to,t.stateNode=l,l._reactInternals=t,zi(t,r,e,n),t=Di(null,t,r,!0,o,n)):(t.tag=0,V&&o&&xu(t),fe(null,t,l,n),t=t.child),t;case 16:r=t.elementType;e:{switch(cl(e,t),e=t.pendingProps,l=r._init,r=l(r._payload),t.type=r,l=t.tag=gm(r),e=Ie(r,e),l){case 0:t=Ii(null,t,r,e,n);break e;case 1:t=la(null,t,r,e,n);break e;case 11:t=na(null,t,r,e,n);break e;case 14:t=ra(null,t,r,Ie(r.type,e),n);break e}throw Error(x(306,r,""))}return t;case 0:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Ie(r,l),Ii(e,t,r,l,n);case 1:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Ie(r,l),la(e,t,r,l,n);case 3:e:{if(zf(t),e===null)throw Error(x(387));r=t.pendingProps,o=t.memoizedState,l=o.element,rf(e,t),Fl(t,r,null,n);var i=t.memoizedState;if(r=i.element,o.isDehydrated)if(o={element:r,isDehydrated:!1,cache:i.cache,pendingSuspenseBoundaries:i.pendingSuspenseBoundaries,transitions:i.transitions},t.updateQueue.baseState=o,t.memoizedState=o,t.flags&256){l=_n(Error(x(423)),t),t=oa(e,t,r,n,l);break e}else if(r!==l){l=_n(Error(x(424)),t),t=oa(e,t,r,n,l);break e}else for(Ce=kt(t.stateNode.containerInfo.firstChild),_e=t,V=!0,Me=null,n=sf(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(kn(),r===l){t=st(e,t,n);break e}fe(e,t,r,n)}t=t.child}return t;case 5:return af(t),e===null&&Li(t),r=t.type,l=t.pendingProps,o=e!==null?e.memoizedProps:null,i=l.children,Ri(r,l)?i=null:o!==null&&Ri(r,o)&&(t.flags|=32),jf(e,t),fe(e,t,i,n),t.child;case 6:return e===null&&Li(t),null;case 13:return Ff(e,t,n);case 4:return Lu(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=xn(t,null,r,n):fe(e,t,r,n),t.child;case 11:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Ie(r,l),na(e,t,r,l,n);case 7:return fe(e,t,t.pendingProps,n),t.child;case 8:return fe(e,t,t.pendingProps.children,n),t.child;case 12:return fe(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,l=t.pendingProps,o=t.memoizedProps,i=l.value,U(jl,r._currentValue),r._currentValue=i,o!==null)if(He(o.value,i)){if(o.children===l.children&&!ge.current){t=st(e,t,n);break e}}else for(o=t.child,o!==null&&(o.return=t);o!==null;){var u=o.dependencies;if(u!==null){i=o.child;for(var s=u.firstContext;s!==null;){if(s.context===r){if(o.tag===1){s=rt(-1,n&-n),s.tag=2;var a=o.updateQueue;if(a!==null){a=a.shared;var c=a.pending;c===null?s.next=s:(s.next=c.next,c.next=s),a.pending=s}}o.lanes|=n,s=o.alternate,s!==null&&(s.lanes|=n),Oi(o.return,n,t),u.lanes|=n;break}s=s.next}}else if(o.tag===10)i=o.type===t.type?null:o.child;else if(o.tag===18){if(i=o.return,i===null)throw Error(x(341));i.lanes|=n,u=i.alternate,u!==null&&(u.lanes|=n),Oi(i,n,t),i=o.sibling}else i=o.child;if(i!==null)i.return=o;else for(i=o;i!==null;){if(i===t){i=null;break}if(o=i.sibling,o!==null){o.return=i.return,i=o;break}i=i.return}o=i}fe(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,r=t.pendingProps.children,gn(t,n),l=je(l),r=r(l),t.flags|=1,fe(e,t,r,n),t.child;case 14:return r=t.type,l=Ie(r,t.pendingProps),l=Ie(r.type,l),ra(e,t,r,l,n);case 15:return Lf(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Ie(r,l),cl(e,t),t.tag=1,we(r)?(e=!0,Tl(t)):e=!1,gn(t,n),of(t,r,l),zi(t,r,l,n),Di(null,t,r,!0,e,n);case 19:return If(e,t,n);case 22:return Of(e,t,n)}throw Error(x(156,t.tag))};function Zf(e,t){return xc(e,t)}function vm(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Le(e,t,n,r){return new vm(e,t,n,r)}function Ku(e){return e=e.prototype,!(!e||!e.isReactComponent)}function gm(e){if(typeof e=="function")return Ku(e)?1:0;if(e!=null){if(e=e.$$typeof,e===fu)return 11;if(e===du)return 14}return 2}function Rt(e,t){var n=e.alternate;return n===null?(n=Le(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function pl(e,t,n,r,l,o){var i=2;if(r=e,typeof e=="function")Ku(e)&&(i=1);else if(typeof e=="string")i=5;else e:switch(e){case nn:return Vt(n.children,l,o,t);case cu:i=8,l|=8;break;case li:return e=Le(12,n,t,l|2),e.elementType=li,e.lanes=o,e;case oi:return e=Le(13,n,t,l),e.elementType=oi,e.lanes=o,e;case ii:return e=Le(19,n,t,l),e.elementType=ii,e.lanes=o,e;case ic:return oo(n,l,o,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case lc:i=10;break e;case oc:i=9;break e;case fu:i=11;break e;case du:i=14;break e;case pt:i=16,r=null;break e}throw Error(x(130,e==null?e:typeof e,""))}return t=Le(i,n,t,l),t.elementType=e,t.type=r,t.lanes=o,t}function Vt(e,t,n,r){return e=Le(7,e,r,t),e.lanes=n,e}function oo(e,t,n,r){return e=Le(22,e,r,t),e.elementType=ic,e.lanes=n,e.stateNode={isHidden:!1},e}function qo(e,t,n){return e=Le(6,e,null,t),e.lanes=n,e}function Yo(e,t,n){return t=Le(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function wm(e,t,n,r,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=No(0),this.expirationTimes=No(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=No(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function qu(e,t,n,r,l,o,i,u,s){return e=new wm(e,t,n,u,s),t===1?(t=1,o===!0&&(t|=8)):t=0,o=Le(3,null,null,t),e.current=o,o.stateNode=e,o.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Tu(o),e}function Sm(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(nd)}catch(e){console.error(e)}}nd(),ba.exports=Pe;var _m=ba.exports,va=_m;ni.createRoot=va.createRoot,ni.hydrateRoot=va.hydrateRoot;const Rm="_app_w7qyt_61",Pm="_main_w7qyt_67",ga={app:Rm,main:Pm};var Gu={};Object.defineProperty(Gu,"__esModule",{value:!0});Gu.parse=zm;Gu.serialize=Fm;const Nm=/^[\u0021-\u003A\u003C\u003E-\u007E]+$/,Am=/^[\u0021-\u003A\u003C-\u007E]*$/,Tm=/^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i,Lm=/^[\u0020-\u003A\u003D-\u007E]*$/,Om=Object.prototype.toString,jm=(()=>{const e=function(){};return e.prototype=Object.create(null),e})();function zm(e,t){const n=new jm,r=e.length;if(r<2)return n;const l=(t==null?void 0:t.decode)||Im;let o=0;do{const i=e.indexOf("=",o);if(i===-1)break;const u=e.indexOf(";",o),s=u===-1?r:u;if(i>s){o=e.lastIndexOf(";",i-1)+1;continue}const a=wa(e,o,i),c=Sa(e,i,a),h=e.slice(a,c);if(n[h]===void 0){let m=wa(e,i+1,s),g=Sa(e,s,m);const y=l(e.slice(m,g));n[h]=y}o=s+1}while(on;){const r=e.charCodeAt(--t);if(r!==32&&r!==9)return t+1}return n}function Fm(e,t,n){const r=(n==null?void 0:n.encode)||encodeURIComponent;if(!Nm.test(e))throw new TypeError(`argument name is invalid: ${e}`);const l=r(t);if(!Am.test(l))throw new TypeError(`argument val is invalid: ${t}`);let o=e+"="+l;if(!n)return o;if(n.maxAge!==void 0){if(!Number.isInteger(n.maxAge))throw new TypeError(`option maxAge is invalid: ${n.maxAge}`);o+="; Max-Age="+n.maxAge}if(n.domain){if(!Tm.test(n.domain))throw new TypeError(`option domain is invalid: ${n.domain}`);o+="; Domain="+n.domain}if(n.path){if(!Lm.test(n.path))throw new TypeError(`option path is invalid: ${n.path}`);o+="; Path="+n.path}if(n.expires){if(!Dm(n.expires)||!Number.isFinite(n.expires.valueOf()))throw new TypeError(`option expires is invalid: ${n.expires}`);o+="; Expires="+n.expires.toUTCString()}if(n.httpOnly&&(o+="; HttpOnly"),n.secure&&(o+="; Secure"),n.partitioned&&(o+="; Partitioned"),n.priority)switch(typeof n.priority=="string"?n.priority.toLowerCase():void 0){case"low":o+="; Priority=Low";break;case"medium":o+="; Priority=Medium";break;case"high":o+="; Priority=High";break;default:throw new TypeError(`option priority is invalid: ${n.priority}`)}if(n.sameSite)switch(typeof n.sameSite=="string"?n.sameSite.toLowerCase():n.sameSite){case!0:case"strict":o+="; SameSite=Strict";break;case"lax":o+="; SameSite=Lax";break;case"none":o+="; SameSite=None";break;default:throw new TypeError(`option sameSite is invalid: ${n.sameSite}`)}return o}function Im(e){if(e.indexOf("%")===-1)return e;try{return decodeURIComponent(e)}catch{return e}}function Dm(e){return Om.call(e)==="[object Date]"}var Ea="popstate";function Mm(e={}){function t(r,l){let{pathname:o,search:i,hash:u}=r.location;return Ji("",{pathname:o,search:i,hash:u},l.state&&l.state.usr||null,l.state&&l.state.key||"default")}function n(r,l){return typeof l=="string"?l:_r(l)}return Bm(t,n,null,e)}function W(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function Ve(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function Um(){return Math.random().toString(36).substring(2,10)}function ka(e,t){return{usr:e.state,key:e.key,idx:t}}function Ji(e,t,n=null,r){return{pathname:typeof e=="string"?e:e.pathname,search:"",hash:"",...typeof t=="string"?Tn(t):t,state:n,key:t&&t.key||r||Um()}}function _r({pathname:e="/",search:t="",hash:n=""}){return t&&t!=="?"&&(e+=t.charAt(0)==="?"?t:"?"+t),n&&n!=="#"&&(e+=n.charAt(0)==="#"?n:"#"+n),e}function Tn(e){let t={};if(e){let n=e.indexOf("#");n>=0&&(t.hash=e.substring(n),e=e.substring(0,n));let r=e.indexOf("?");r>=0&&(t.search=e.substring(r),e=e.substring(0,r)),e&&(t.pathname=e)}return t}function Bm(e,t,n,r={}){let{window:l=document.defaultView,v5Compat:o=!1}=r,i=l.history,u="POP",s=null,a=c();a==null&&(a=0,i.replaceState({...i.state,idx:a},""));function c(){return(i.state||{idx:null}).idx}function h(){u="POP";let E=c(),d=E==null?null:E-a;a=E,s&&s({action:u,location:v.location,delta:d})}function m(E,d){u="PUSH";let f=Ji(v.location,E,d);a=c()+1;let p=ka(f,a),k=v.createHref(f);try{i.pushState(p,"",k)}catch(C){if(C instanceof DOMException&&C.name==="DataCloneError")throw C;l.location.assign(k)}o&&s&&s({action:u,location:v.location,delta:1})}function g(E,d){u="REPLACE";let f=Ji(v.location,E,d);a=c();let p=ka(f,a),k=v.createHref(f);i.replaceState(p,"",k),o&&s&&s({action:u,location:v.location,delta:0})}function y(E){return Hm(E)}let v={get action(){return u},get location(){return e(l,i)},listen(E){if(s)throw new Error("A history only accepts one active listener");return l.addEventListener(Ea,h),s=E,()=>{l.removeEventListener(Ea,h),s=null}},createHref(E){return t(l,E)},createURL:y,encodeLocation(E){let d=y(E);return{pathname:d.pathname,search:d.search,hash:d.hash}},push:m,replace:g,go(E){return i.go(E)}};return v}function Hm(e,t=!1){let n="http://localhost";typeof window<"u"&&(n=window.location.origin!=="null"?window.location.origin:window.location.href),W(n,"No window.location.(origin|href) available to create URL");let r=typeof e=="string"?e:_r(e);return r=r.replace(/ $/,"%20"),!t&&r.startsWith("//")&&(r=n+r),new URL(r,n)}function rd(e,t,n="/"){return Vm(e,t,n,!1)}function Vm(e,t,n,r){let l=typeof t=="string"?Tn(t):t,o=at(l.pathname||"/",n);if(o==null)return null;let i=ld(e);Wm(i);let u=null;for(let s=0;u==null&&s{let s={relativePath:u===void 0?o.path||"":u,caseSensitive:o.caseSensitive===!0,childrenIndex:i,route:o};s.relativePath.startsWith("/")&&(W(s.relativePath.startsWith(r),`Absolute route path "${s.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),s.relativePath=s.relativePath.slice(r.length));let a=lt([r,s.relativePath]),c=n.concat(s);o.children&&o.children.length>0&&(W(o.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${a}".`),ld(o.children,t,c,a)),!(o.path==null&&!o.index)&&t.push({path:a,score:Xm(a,o.index),routesMeta:c})};return e.forEach((o,i)=>{var u;if(o.path===""||!((u=o.path)!=null&&u.includes("?")))l(o,i);else for(let s of od(o.path))l(o,i,s)}),t}function od(e){let t=e.split("/");if(t.length===0)return[];let[n,...r]=t,l=n.endsWith("?"),o=n.replace(/\?$/,"");if(r.length===0)return l?[o,""]:[o];let i=od(r.join("/")),u=[];return u.push(...i.map(s=>s===""?o:[o,s].join("/"))),l&&u.push(...i),u.map(s=>e.startsWith("/")&&s===""?"/":s)}function Wm(e){e.sort((t,n)=>t.score!==n.score?n.score-t.score:Gm(t.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}var $m=/^:[\w-]+$/,Qm=3,Km=2,qm=1,Ym=10,Jm=-2,xa=e=>e==="*";function Xm(e,t){let n=e.split("/"),r=n.length;return n.some(xa)&&(r+=Jm),t&&(r+=Km),n.filter(l=>!xa(l)).reduce((l,o)=>l+($m.test(o)?Qm:o===""?qm:Ym),r)}function Gm(e,t){return e.length===t.length&&e.slice(0,-1).every((r,l)=>r===t[l])?e[e.length-1]-t[t.length-1]:0}function Zm(e,t,n=!1){let{routesMeta:r}=e,l={},o="/",i=[];for(let u=0;u{if(c==="*"){let y=u[m]||"";i=o.slice(0,o.length-y.length).replace(/(.)\/+$/,"$1")}const g=u[m];return h&&!g?a[c]=void 0:a[c]=(g||"").replace(/%2F/g,"/"),a},{}),pathname:o,pathnameBase:i,pattern:e}}function bm(e,t=!1,n=!0){Ve(e==="*"||!e.endsWith("*")||e.endsWith("/*"),`Route path "${e}" will be treated as if it were "${e.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${e.replace(/\*$/,"/*")}".`);let r=[],l="^"+e.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(i,u,s)=>(r.push({paramName:u,isOptional:s!=null}),s?"/?([^\\/]+)?":"/([^\\/]+)"));return e.endsWith("*")?(r.push({paramName:"*"}),l+=e==="*"||e==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?l+="\\/*$":e!==""&&e!=="/"&&(l+="(?:(?=\\/|$))"),[new RegExp(l,t?void 0:"i"),r]}function ey(e){try{return e.split("/").map(t=>decodeURIComponent(t).replace(/\//g,"%2F")).join("/")}catch(t){return Ve(!1,`The URL path "${e}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${t}).`),e}}function at(e,t){if(t==="/")return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith("/")?t.length-1:t.length,r=e.charAt(n);return r&&r!=="/"?null:e.slice(n)||"/"}function ty(e,t="/"){let{pathname:n,search:r="",hash:l=""}=typeof e=="string"?Tn(e):e;return{pathname:n?n.startsWith("/")?n:ny(n,t):t,search:oy(r),hash:iy(l)}}function ny(e,t){let n=t.replace(/\/+$/,"").split("/");return e.split("/").forEach(l=>{l===".."?n.length>1&&n.pop():l!=="."&&n.push(l)}),n.length>1?n.join("/"):"/"}function Jo(e,t,n,r){return`Cannot include a '${e}' character in a manually specified \`to.${t}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${n}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function ry(e){return e.filter((t,n)=>n===0||t.route.path&&t.route.path.length>0)}function Zu(e){let t=ry(e);return t.map((n,r)=>r===t.length-1?n.pathname:n.pathnameBase)}function bu(e,t,n,r=!1){let l;typeof e=="string"?l=Tn(e):(l={...e},W(!l.pathname||!l.pathname.includes("?"),Jo("?","pathname","search",l)),W(!l.pathname||!l.pathname.includes("#"),Jo("#","pathname","hash",l)),W(!l.search||!l.search.includes("#"),Jo("#","search","hash",l)));let o=e===""||l.pathname==="",i=o?"/":l.pathname,u;if(i==null)u=n;else{let h=t.length-1;if(!r&&i.startsWith("..")){let m=i.split("/");for(;m[0]==="..";)m.shift(),h-=1;l.pathname=m.join("/")}u=h>=0?t[h]:"/"}let s=ty(l,u),a=i&&i!=="/"&&i.endsWith("/"),c=(o||i===".")&&n.endsWith("/");return!s.pathname.endsWith("/")&&(a||c)&&(s.pathname+="/"),s}var lt=e=>e.join("/").replace(/\/\/+/g,"/"),ly=e=>e.replace(/\/+$/,"").replace(/^\/*/,"/"),oy=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,iy=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e;function uy(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}var id=["POST","PUT","PATCH","DELETE"];new Set(id);var sy=["GET",...id];new Set(sy);var Ln=S.createContext(null);Ln.displayName="DataRouter";var co=S.createContext(null);co.displayName="DataRouterState";var ud=S.createContext({isTransitioning:!1});ud.displayName="ViewTransition";var ay=S.createContext(new Map);ay.displayName="Fetchers";var cy=S.createContext(null);cy.displayName="Await";var We=S.createContext(null);We.displayName="Navigation";var Or=S.createContext(null);Or.displayName="Location";var Ze=S.createContext({outlet:null,matches:[],isDataRoute:!1});Ze.displayName="Route";var es=S.createContext(null);es.displayName="RouteError";function fy(e,{relative:t}={}){W(On(),"useHref() may be used only in the context of a component.");let{basename:n,navigator:r}=S.useContext(We),{hash:l,pathname:o,search:i}=jr(e,{relative:t}),u=o;return n!=="/"&&(u=o==="/"?n:lt([n,o])),r.createHref({pathname:u,search:i,hash:l})}function On(){return S.useContext(Or)!=null}function Ot(){return W(On(),"useLocation() may be used only in the context of a component."),S.useContext(Or).location}var sd="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function ad(e){S.useContext(We).static||S.useLayoutEffect(e)}function cd(){let{isDataRoute:e}=S.useContext(Ze);return e?Cy():dy()}function dy(){W(On(),"useNavigate() may be used only in the context of a component.");let e=S.useContext(Ln),{basename:t,navigator:n}=S.useContext(We),{matches:r}=S.useContext(Ze),{pathname:l}=Ot(),o=JSON.stringify(Zu(r)),i=S.useRef(!1);return ad(()=>{i.current=!0}),S.useCallback((s,a={})=>{if(Ve(i.current,sd),!i.current)return;if(typeof s=="number"){n.go(s);return}let c=bu(s,JSON.parse(o),l,a.relative==="path");e==null&&t!=="/"&&(c.pathname=c.pathname==="/"?t:lt([t,c.pathname])),(a.replace?n.replace:n.push)(c,a.state,a)},[t,n,o,l,e])}S.createContext(null);function jr(e,{relative:t}={}){let{matches:n}=S.useContext(Ze),{pathname:r}=Ot(),l=JSON.stringify(Zu(n));return S.useMemo(()=>bu(e,JSON.parse(l),r,t==="path"),[e,l,r,t])}function py(e,t){return fd(e,t)}function fd(e,t,n,r){var f;W(On(),"useRoutes() may be used only in the context of a component.");let{navigator:l,static:o}=S.useContext(We),{matches:i}=S.useContext(Ze),u=i[i.length-1],s=u?u.params:{},a=u?u.pathname:"/",c=u?u.pathnameBase:"/",h=u&&u.route;{let p=h&&h.path||"";dd(a,!h||p.endsWith("*")||p.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${a}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. + +Please change the parent to .`)}let m=Ot(),g;if(t){let p=typeof t=="string"?Tn(t):t;W(c==="/"||((f=p.pathname)==null?void 0:f.startsWith(c)),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${c}" but pathname "${p.pathname}" was given in the \`location\` prop.`),g=p}else g=m;let y=g.pathname||"/",v=y;if(c!=="/"){let p=c.replace(/^\//,"").split("/");v="/"+y.replace(/^\//,"").split("/").slice(p.length).join("/")}let E=!o&&n&&n.matches&&n.matches.length>0?n.matches:rd(e,{pathname:v});Ve(h||E!=null,`No routes matched location "${g.pathname}${g.search}${g.hash}" `),Ve(E==null||E[E.length-1].route.element!==void 0||E[E.length-1].route.Component!==void 0||E[E.length-1].route.lazy!==void 0,`Matched leaf route at location "${g.pathname}${g.search}${g.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let d=gy(E&&E.map(p=>Object.assign({},p,{params:Object.assign({},s,p.params),pathname:lt([c,l.encodeLocation?l.encodeLocation(p.pathname).pathname:p.pathname]),pathnameBase:p.pathnameBase==="/"?c:lt([c,l.encodeLocation?l.encodeLocation(p.pathnameBase).pathname:p.pathnameBase])})),i,n,r);return t&&d?S.createElement(Or.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",...g},navigationType:"POP"}},d):d}function hy(){let e=xy(),t=uy(e)?`${e.status} ${e.statusText}`:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,r="rgba(200,200,200, 0.5)",l={padding:"0.5rem",backgroundColor:r},o={padding:"2px 4px",backgroundColor:r},i=null;return console.error("Error handled by React Router default ErrorBoundary:",e),i=S.createElement(S.Fragment,null,S.createElement("p",null,"💿 Hey developer 👋"),S.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",S.createElement("code",{style:o},"ErrorBoundary")," or"," ",S.createElement("code",{style:o},"errorElement")," prop on your route.")),S.createElement(S.Fragment,null,S.createElement("h2",null,"Unexpected Application Error!"),S.createElement("h3",{style:{fontStyle:"italic"}},t),n?S.createElement("pre",{style:l},n):null,i)}var my=S.createElement(hy,null),yy=class extends S.Component{constructor(e){super(e),this.state={location:e.location,revalidation:e.revalidation,error:e.error}}static getDerivedStateFromError(e){return{error:e}}static getDerivedStateFromProps(e,t){return t.location!==e.location||t.revalidation!=="idle"&&e.revalidation==="idle"?{error:e.error,location:e.location,revalidation:e.revalidation}:{error:e.error!==void 0?e.error:t.error,location:t.location,revalidation:e.revalidation||t.revalidation}}componentDidCatch(e,t){console.error("React Router caught the following error during render",e,t)}render(){return this.state.error!==void 0?S.createElement(Ze.Provider,{value:this.props.routeContext},S.createElement(es.Provider,{value:this.state.error,children:this.props.component})):this.props.children}};function vy({routeContext:e,match:t,children:n}){let r=S.useContext(Ln);return r&&r.static&&r.staticContext&&(t.route.errorElement||t.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=t.route.id),S.createElement(Ze.Provider,{value:e},n)}function gy(e,t=[],n=null,r=null){if(e==null){if(!n)return null;if(n.errors)e=n.matches;else if(t.length===0&&!n.initialized&&n.matches.length>0)e=n.matches;else return null}let l=e,o=n==null?void 0:n.errors;if(o!=null){let s=l.findIndex(a=>a.route.id&&(o==null?void 0:o[a.route.id])!==void 0);W(s>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(o).join(",")}`),l=l.slice(0,Math.min(l.length,s+1))}let i=!1,u=-1;if(n)for(let s=0;s=0?l=l.slice(0,u+1):l=[l[0]];break}}}return l.reduceRight((s,a,c)=>{let h,m=!1,g=null,y=null;n&&(h=o&&a.route.id?o[a.route.id]:void 0,g=a.route.errorElement||my,i&&(u<0&&c===0?(dd("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),m=!0,y=null):u===c&&(m=!0,y=a.route.hydrateFallbackElement||null)));let v=t.concat(l.slice(0,c+1)),E=()=>{let d;return h?d=g:m?d=y:a.route.Component?d=S.createElement(a.route.Component,null):a.route.element?d=a.route.element:d=s,S.createElement(vy,{match:a,routeContext:{outlet:s,matches:v,isDataRoute:n!=null},children:d})};return n&&(a.route.ErrorBoundary||a.route.errorElement||c===0)?S.createElement(yy,{location:n.location,revalidation:n.revalidation,component:g,error:h,children:E(),routeContext:{outlet:null,matches:v,isDataRoute:!0}}):E()},null)}function ts(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function wy(e){let t=S.useContext(Ln);return W(t,ts(e)),t}function Sy(e){let t=S.useContext(co);return W(t,ts(e)),t}function Ey(e){let t=S.useContext(Ze);return W(t,ts(e)),t}function ns(e){let t=Ey(e),n=t.matches[t.matches.length-1];return W(n.route.id,`${e} can only be used on routes that contain a unique "id"`),n.route.id}function ky(){return ns("useRouteId")}function xy(){var r;let e=S.useContext(es),t=Sy("useRouteError"),n=ns("useRouteError");return e!==void 0?e:(r=t.errors)==null?void 0:r[n]}function Cy(){let{router:e}=wy("useNavigate"),t=ns("useNavigate"),n=S.useRef(!1);return ad(()=>{n.current=!0}),S.useCallback(async(l,o={})=>{Ve(n.current,sd),n.current&&(typeof l=="number"?e.navigate(l):await e.navigate(l,{fromRouteId:t,...o}))},[e,t])}var Ca={};function dd(e,t,n){!t&&!Ca[e]&&(Ca[e]=!0,Ve(!1,n))}S.memo(_y);function _y({routes:e,future:t,state:n}){return fd(e,void 0,n,t)}function _a({to:e,replace:t,state:n,relative:r}){W(On()," may be used only in the context of a component.");let{static:l}=S.useContext(We);Ve(!l," must not be used on the initial render in a . This is a no-op, but you should modify your code so the is only ever rendered in response to some user interaction or state change.");let{matches:o}=S.useContext(Ze),{pathname:i}=Ot(),u=cd(),s=bu(e,Zu(o),i,r==="path"),a=JSON.stringify(s);return S.useEffect(()=>{u(JSON.parse(a),{replace:t,state:n,relative:r})},[u,a,r,t,n]),null}function hl(e){W(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function Ry({basename:e="/",children:t=null,location:n,navigationType:r="POP",navigator:l,static:o=!1}){W(!On(),"You cannot render a inside another . You should never have more than one in your app.");let i=e.replace(/^\/*/,"/"),u=S.useMemo(()=>({basename:i,navigator:l,static:o,future:{}}),[i,l,o]);typeof n=="string"&&(n=Tn(n));let{pathname:s="/",search:a="",hash:c="",state:h=null,key:m="default"}=n,g=S.useMemo(()=>{let y=at(s,i);return y==null?null:{location:{pathname:y,search:a,hash:c,state:h,key:m},navigationType:r}},[i,s,a,c,h,m,r]);return Ve(g!=null,` is not able to match the URL "${s}${a}${c}" because it does not start with the basename, so the won't render anything.`),g==null?null:S.createElement(We.Provider,{value:u},S.createElement(Or.Provider,{children:t,value:g}))}function Py({children:e,location:t}){return py(Xi(e),t)}function Xi(e,t=[]){let n=[];return S.Children.forEach(e,(r,l)=>{if(!S.isValidElement(r))return;let o=[...t,l];if(r.type===S.Fragment){n.push.apply(n,Xi(r.props.children,o));return}W(r.type===hl,`[${typeof r.type=="string"?r.type:r.type.name}] is not a component. All component children of must be a or `),W(!r.props.index||!r.props.children,"An index route cannot have child routes.");let i={id:r.props.id||o.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,loader:r.props.loader,action:r.props.action,hydrateFallbackElement:r.props.hydrateFallbackElement,HydrateFallback:r.props.HydrateFallback,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.hasErrorBoundary===!0||r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(i.children=Xi(r.props.children,o)),n.push(i)}),n}var ml="get",yl="application/x-www-form-urlencoded";function fo(e){return e!=null&&typeof e.tagName=="string"}function Ny(e){return fo(e)&&e.tagName.toLowerCase()==="button"}function Ay(e){return fo(e)&&e.tagName.toLowerCase()==="form"}function Ty(e){return fo(e)&&e.tagName.toLowerCase()==="input"}function Ly(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function Oy(e,t){return e.button===0&&(!t||t==="_self")&&!Ly(e)}var tl=null;function jy(){if(tl===null)try{new FormData(document.createElement("form"),0),tl=!1}catch{tl=!0}return tl}var zy=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function Xo(e){return e!=null&&!zy.has(e)?(Ve(!1,`"${e}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${yl}"`),null):e}function Fy(e,t){let n,r,l,o,i;if(Ay(e)){let u=e.getAttribute("action");r=u?at(u,t):null,n=e.getAttribute("method")||ml,l=Xo(e.getAttribute("enctype"))||yl,o=new FormData(e)}else if(Ny(e)||Ty(e)&&(e.type==="submit"||e.type==="image")){let u=e.form;if(u==null)throw new Error('Cannot submit a + + + + + ); +} + +export default AllProductsHeader; diff --git a/src/pages/MarketPage/BestProduct.tsx b/src/pages/MarketPage/BestProduct.tsx new file mode 100644 index 00000000..7bb73732 --- /dev/null +++ b/src/pages/MarketPage/BestProduct.tsx @@ -0,0 +1,39 @@ +import React, { use, useEffect } from 'react'; +import style from './BestProducts.module.scss'; +import getMediaCount from '@/utils/getMediaCount'; +import useApi from '@/hooks/useApi'; +import { fetchProducts, Product } from '@/api/products'; +import ProductCard from '@/components/Cards/ProductCard'; +import SkeletonCard from '@/components/Cards/SkeletonCard'; +// 베스트 상품 컴포넌트 +function BestProducts() { + // 미디어 쿼리에서 베스트 상품의 개수를 가져옵니다. + const { bestProductsCount } = getMediaCount(); + // API를 호출하여 베스트 상품을 가져옵니다. + const { data, loading, error } = useApi( + () => fetchProducts(1, bestProductsCount, 'favorite', ''), + [bestProductsCount] + ); + + if (error) { + console.error('베스트 상품을 불러오는 중 오류 발생:', error); + } + const products: Product[] = data?.list ?? []; + console.log('베스트 상품:', products); + return ( +
+

베스트 상품

+
+ {loading + ? Array.from({ length: bestProductsCount }).map((_, idx) => ( + + )) + : products.map((product) => ( + + ))} +
+
+ ); +} + +export default BestProducts; diff --git a/src/pages/MarketPage/BestProducts.module.scss b/src/pages/MarketPage/BestProducts.module.scss new file mode 100644 index 00000000..15fbeeac --- /dev/null +++ b/src/pages/MarketPage/BestProducts.module.scss @@ -0,0 +1,32 @@ +.best-products { + width: 100%; + max-width: 1200px; + display: flex; + flex-direction: column; + gap: 20px; + + &__title { + width: 100%; + font-size: var(--font-title-md); + font-weight: bold; + margin-bottom: 20px; + } + &__list { + display: grid; + gap: var(--spacing-xs); + /* 모바일: 1열 */ + grid-template-columns: 1fr; + grid-template-rows: 1fr; + /* 태블릿: 2열 */ + + @include tablet { + grid-template-columns: repeat(2, 1fr); + grid-template-rows: 1fr; + } + /* 랩톱: 4열 */ + @include laptop { + grid-template-columns: repeat(4, 1fr); + grid-template-rows: 1fr; + } + } +} diff --git a/src/pages/MarketPage/MarketPage.module.scss b/src/pages/MarketPage/MarketPage.module.scss new file mode 100644 index 00000000..22128be2 --- /dev/null +++ b/src/pages/MarketPage/MarketPage.module.scss @@ -0,0 +1,15 @@ +.market-page { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + max-width: var(--market-container-max-width); + margin: 0 auto; + padding: var(--spacing-xs); + gap: var(--spacing-md); + + @include tablet { + padding: var(--spacing-md); + gap: var(--spacing-lg); + } +} diff --git a/src/pages/MarketPage/MarketPage.tsx b/src/pages/MarketPage/MarketPage.tsx new file mode 100644 index 00000000..8eed79d6 --- /dev/null +++ b/src/pages/MarketPage/MarketPage.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import style from './MarketPage.module.scss'; +import BestProducts from './BestProduct'; +import AllProducts from './AllProducts'; +function MarketPage() { + return ( +
+ + +
+ ); +} +export default MarketPage; diff --git a/src/pages/MarketPage/PageNations.module.scss b/src/pages/MarketPage/PageNations.module.scss new file mode 100644 index 00000000..88c8a86c --- /dev/null +++ b/src/pages/MarketPage/PageNations.module.scss @@ -0,0 +1,36 @@ +// src/pages/MarketPage/PageNations.module.scss +.pagination { + display: flex; + justify-content: center; + align-items: center; + gap: 8px; + margin: 24px 0; +} + +.pageBtn { + width: 40px; + height: 40px; + border: 1px solid var(--color-neutral-200); + border-radius: 50%; + background-color: white; + color: var(--color-neutral-800); + font-size: var(--font-content-md); + cursor: pointer; + transition: + background-color 0.2s, + color 0.2s; + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } + + &.active { + background-color: var(--color-primary-100); + color: white; + } + + &:hover:not(:disabled) { + background-color: var(--color-neutral-100); + } +} diff --git a/src/pages/MarketPage/PageNations.tsx b/src/pages/MarketPage/PageNations.tsx new file mode 100644 index 00000000..39effaae --- /dev/null +++ b/src/pages/MarketPage/PageNations.tsx @@ -0,0 +1,62 @@ +// src/pages/MarketPage/PageNations.tsx +import React from 'react'; +import style from './PageNations.module.scss'; + +interface Props { + currentPage: number; + pageSize: number; + totalCount: number; + onPageChange: (page: number) => void; +} + +export default function PageNations({ + currentPage, + pageSize, + totalCount, + onPageChange, +}: Props) { + const totalPages = Math.ceil(totalCount / pageSize); + if (totalPages <= 1) return null; + + // 5개 번호 범위 계산 + const maxButtons = 5; + let start = Math.max(1, currentPage - 2); + let end = Math.min(totalPages, start + maxButtons - 1); + if (end - start + 1 < maxButtons) { + start = Math.max(1, end - maxButtons + 1); + } + + const pages = Array.from({ length: end - start + 1 }, (_, i) => start + i); + + return ( + + ); +} diff --git a/src/reportWebVitals.js b/src/reportWebVitals.js deleted file mode 100644 index 5253d3ad..00000000 --- a/src/reportWebVitals.js +++ /dev/null @@ -1,13 +0,0 @@ -const reportWebVitals = onPerfEntry => { - if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }); - } -}; - -export default reportWebVitals; diff --git a/src/routes/index.tsx b/src/routes/index.tsx new file mode 100644 index 00000000..49eec7c6 --- /dev/null +++ b/src/routes/index.tsx @@ -0,0 +1,23 @@ +// src/router/index.tsx +// 라우터를 조합해서 렌더링하는 컴포넌트 + +import React from 'react'; +import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; +import { routes } from './routes'; + +export default function AppRouter() { + return ( + + {/*기본 경로 "/" 로 들어오면 /items 로 리다이렉트 */} + } /> + {/* {라우터 배열에서 경로를 탐색함} */} + {routes.map(({ path, element: Component }) => ( + } /> + ))} + + {/* 매칭되는 경로 없으면 루트로 리다이렉트 */} + {/* todo: 매칭되는 경로가 없다면 notFound 페이지로 이동 */} + } /> + + ); +} diff --git a/src/routes/routes.ts b/src/routes/routes.ts new file mode 100644 index 00000000..e62ae660 --- /dev/null +++ b/src/routes/routes.ts @@ -0,0 +1,14 @@ +// src/router/routes.ts +//라우터 경로 정의 +import MarketPage from '@/pages/MarketPage/MarketPage'; + +//라우터 인터페이스 설정 +export interface AppRoute { + path: string; + element: React.ComponentType; +} +export const routes: AppRoute[] = [ + { path: '/items', element: MarketPage }, + + // …추가 라우트 +]; diff --git a/src/styles/App.module.scss b/src/styles/App.module.scss new file mode 100644 index 00000000..2ca3913e --- /dev/null +++ b/src/styles/App.module.scss @@ -0,0 +1,9 @@ +.app { + display: flex; + flex-direction: column; + min-height: 100vh; +} +.main { + flex: 1; + margin-top: 70px; /* Header height */ +} diff --git a/src/styles/font.scss b/src/styles/font.scss new file mode 100644 index 00000000..52b05aa3 --- /dev/null +++ b/src/styles/font.scss @@ -0,0 +1,40 @@ +/* font-face */ +@font-face { + font-family: Pretendard; + src: url('../assets/fonts/Pretendard-Light.woff2') format('woff2'); + font-weight: 300; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: Pretendard; + src: url('../assets/fonts/Pretendard-Regular.woff2') format('woff2'); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: Pretendard; + src: url('../assets/fonts/Pretendard-Medium.woff2') format('woff2'); + font-weight: 500; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: Pretendard; + src: url('../assets/fonts/Pretendard-SemiBold.woff2') format('woff2'); + font-weight: 600; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: Pretendard; + src: url('../assets/fonts/Pretendard-Thin.woff2') format('woff2'); + font-weight: 100; + font-style: normal; + font-display: swap; +} diff --git a/src/styles/index.scss b/src/styles/index.scss new file mode 100644 index 00000000..ad893772 --- /dev/null +++ b/src/styles/index.scss @@ -0,0 +1,23 @@ +//index.scss +//main.tsx에서 불러옴 +@use './reset'; +@use './font.scss'; +/* 글로벌 기본 스타일 */ +* { + box-sizing: border-box; +} + +html { + font-family: var(--font-family-base); + font-size: 16px; +} + +body { + margin: 0; +} + +/* 공통 유틸리티 클래스 */ + +.pointer { + cursor: pointer; +} diff --git a/src/styles/mixins.scss b/src/styles/mixins.scss new file mode 100644 index 00000000..2b4f7b3b --- /dev/null +++ b/src/styles/mixins.scss @@ -0,0 +1,25 @@ +@use 'variables' as *; +//믹스인 정의 + +/// 모바일 이하일 때 +@mixin mobile { + @media (max-width: $mobile-max-width) { + @content; + } +} + +/// tablet 이하일 때 + +@mixin tablet { + @media (min-width: $tablet-min-width) and (max-width: $tablet-max-width) { + @content; + } +} + +/// laptop 이하일 때 + +@mixin laptop { + @media (min-width: $desktop-min-width) { + @content; + } +} diff --git a/src/styles/reset.scss b/src/styles/reset.scss new file mode 100644 index 00000000..24605a4c --- /dev/null +++ b/src/styles/reset.scss @@ -0,0 +1,45 @@ +/* reset.css */ + +/* 브라우저의 전역 스타일을 초기화합니다. */ +*, +*::before, +*::after { + box-sizing: border-box; +} + +ol, +ul { + list-style: none; +} + +a { + text-decoration: none; + color: inherit; +} + +button, +input, +select, +textarea { + font: inherit; + background: none; + border: none; + outline: none; +} + +img, +video, +canvas, +svg { + display: block; + max-width: 100%; +} +h1, +h2, +h3, +h4, +h5, +h6, +p { + margin: 0; +} diff --git a/src/styles/variables.scss b/src/styles/variables.scss new file mode 100644 index 00000000..5d168cd3 --- /dev/null +++ b/src/styles/variables.scss @@ -0,0 +1,73 @@ +/* 디자인 변수를 정의합니다. */ +:root { + /* Font */ + --font-family-base: 'Pretendard', sans-serif; + --font-title-lx: 2.5rem; // 40px + --font-title-lg: 2rem; // 32px + --font-title-md: 1.5rem; // 24px + --font-title-sm: 1.25rem; // 20px + --font-title-xs: 1.125rem; // 18px + + --font-content-xl: 1.5rem; // 24px + --font-content-lg: 1.25rem; // 20px + --font-content-md: 1rem; // 16px + --font-content-sm: 0.875rem; // 14px + --font-content-xs: 0.75rem; // 12px + + --font-label-xl: 1.25rem; // 20px + --font-label-lg: 1.125rem; // 18px + --font-label-md: 1rem; // 16px + --font-label-sm: 0.875rem; // 14px + --font-label-xs: 0.75rem; // 12px + + /* Color - Primary */ + --color-primary-100: #3692ff; + + /* Color -Secondary */ + + --color-secondary-50: #fcfcfc; + --color-secondary-100: #e6f2ff; + --color-secondary-200: #cfe5ff; + + /* Color -Neutral */ + --color-neutral-50: #f9fafb; + --color-neutral-100: #f3f4f6; + --color-neutral-200: #e5e7eb; + --color-neutral-400: #9ca3af; + --color-neutral-500: #6b7280; + --color-neutral-600: #4b5563; + --color-neutral-700: #374151; + --color-neutral-800: #1f2937; + --color-neutral-900: #111827; + + /* Color- Error */ + --color-error: red; + + /* Spacing */ + --spacing-xs: 1rem; // 16px + --spacing-sm: 1.125rem; // 18px + --spacing-md: 1.5rem; // 24px + --spacing-lg: 2.5rem; // 40px + --spacing-xl: 8rem; // 128px + + /* Layout */ + --container-max-width: 1920px; + --container-padding: 200px; + --container-padding-tablet: 104px; + --container-top-margin: 231px; + --container-top-margin-sm: 80px; + --auth-container-max-width: 640px; + --auth-container-max-width-sm: 400px; + --market-container-max-width: 1200px; + --tablet-max-width: 1199px; + --mobile-max-width: 767px; + + /* Border-radious */ + --radius-button: 40px; +} + +/* 미디어 쿼리 : scss */ +$mobile-max-width: 767px; +$tablet-min-width: 768px; +$tablet-max-width: 1199px; +$desktop-min-width: 1200px; diff --git a/src/App.test.js b/src/tests/App.test.ts similarity index 89% rename from src/App.test.js rename to src/tests/App.test.ts index 1f03afee..7b89c8b2 100644 --- a/src/App.test.js +++ b/src/tests/App.test.ts @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react'; -import App from './App'; +import App from '../App'; test('renders learn react link', () => { render(); diff --git a/src/setupTests.js b/src/tests/setupTests.ts similarity index 100% rename from src/setupTests.js rename to src/tests/setupTests.ts diff --git a/src/utils/getMediaCount.ts b/src/utils/getMediaCount.ts new file mode 100644 index 00000000..8fd090fb --- /dev/null +++ b/src/utils/getMediaCount.ts @@ -0,0 +1,24 @@ +//미디어쿼리 변화에 따라 콘텐츠의 개수를 조정하기 위한 유틸리티 함수입니다. + +import useMediaQuery from '../hooks/useMediaQuery'; + +const BestProductsCounts = { + mobile: 1, + tablet: 2, + desktop: 4, +}; +const AllProductsCounts = { + mobile: 4, + tablet: 6, + desktop: 10, +}; + +// useMediaQuery 훅을 사용하여 현재 화면 크기에 따라 베스트 상품과 전체 상품의 개수를 반환합니다. +export default function getMediaCount() { + const breakpoint = useMediaQuery(); + + return { + bestProductsCount: BestProductsCounts[breakpoint], + allProductsCount: AllProductsCounts[breakpoint], + }; +} diff --git a/src/utils/reportWebVitals.ts b/src/utils/reportWebVitals.ts new file mode 100644 index 00000000..5cd00ded --- /dev/null +++ b/src/utils/reportWebVitals.ts @@ -0,0 +1,32 @@ +// src/reportWebVitals.ts +/* Web Vitals”라는 핵심 퍼포먼스 지표(CLS, FID, LCP 등)를 측정해서, 원하는 콜백 함수로 넘겨주는 유틸 함수 + - CLS(Cumulative Layout Shift): 레이아웃이 얼마나 흔들리는지 + - FID(First Input Delay): 첫 사용자 입력 반응 속도 + - LCP(Largest Contentful Paint): 화면 주요 콘텐츠가 렌더링되는 시간 + + 동적 임포트 + - web-vitals 모듈을 필요할 때만(import('web-vitals')) 불러와 번들 크기를 줄여 줍니다. + + 콜백 전달 + - 측정된 값을 매개변수로 넘겨주는 콜백 함수(onPerfEntry)를 통해 “로그 찍기”나 “분석 서버에 보내기” 같은 처리를 할 수 있어요. +*/ + +// ① 웹 바이탈 리포트 핸들러 타입 가져오기 +import type { ReportHandler } from 'web-vitals'; + +const reportWebVitals = (onPerfEntry?: ReportHandler): void => { + // ② typeof 검사로 “함수” 여부를 확인 + if (onPerfEntry && typeof onPerfEntry === 'function') { + // ③ 동적 import + import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + // ④ 각 측정 함수에 onPerfEntry 콜백 전달 + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..05fd7b9e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + /* JavaScript 출력물 타겟팅 */ + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + + /* 모듈 해석 및 번들러와의 호환 */ + "module": "ESNext", + "moduleResolution": "Node", + "jsx": "react-jsx", + + /* 경로 별칭 설정 */ + "baseUrl": "./src", + "paths": { + "@/*": ["*"] + }, + + /* 엄격 모드 및 호환성 */ + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src", "vite-env.d.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/vite-env.d.ts b/vite-env.d.ts new file mode 100644 index 00000000..8a950f4a --- /dev/null +++ b/vite-env.d.ts @@ -0,0 +1,16 @@ +// /vite-env.d.ts +// scss/css 모듈을 import 할 수 있도록 선언 +declare module '*.module.scss' { + const classes: { [key: string]: string }; + export default classes; +} + +//이미지 파일 +declare module '*.png' { + const src: string; + export default src; +} +declare module '*.jpg' { + const src: string; + export default src; +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 00000000..c08068b0 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,37 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import path from 'path'; +import sass from 'sass'; + +export default defineConfig({ + base: '/', // 빌드 결과물의 기본 경로 설정 + plugins: [ + react({ + // fast-refresh, SWC 옵션 등 필요시 추가 설정 + }), + ], + resolve: { + alias: { + '@': path.resolve(__dirname, 'src'), + }, + }, + css: { + preprocessorOptions: { + scss: { + implementation: sass, + //issue : includePath 를 불러오지 못함 + + // 자동 주입 + additionalData: ` + @use "@/styles/variables" as *; + @use "@/styles/mixins" as *; + `, + }, + }, + }, + server: { + port: 3000, + open: true, + }, + // 빌드 결과물 경로나 최적화 옵션은 필요에 따라… +}); diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 00000000..58d63911 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vitest/config'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + test: { + globals: true, + environment: 'jsdom', + setupFiles: 'src/tests/setupTests.ts', + coverage: { + provider: 'istanbul', + reporter: ['text', 'lcov'], + all: true, + include: ['src/**/*.{ts,tsx}'], + exclude: ['node_modules/', 'src/tests/'], + }, + }, +});