From 1dfa9395fc9d451e639af8fe8e0a012ae5546d38 Mon Sep 17 00:00:00 2001 From: Changuk Woo <43228743+wukdddang@users.noreply.github.com> Date: Tue, 31 Oct 2023 18:45:39 +0900 Subject: [PATCH] =?UTF-8?q?deploy:=201=EC=B0=A8=20=EC=8A=A4=ED=94=84?= =?UTF-8?q?=EB=A6=B0=ED=8A=B8=20=EB=B0=B0=ED=8F=AC=20(#58)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * style : 전역 디자인 시스템 세팅 * style : 전역 디자인 시스템 세팅 * chore : 이슈 템플릿 수정 * refactor: build-test.yml 파일 수정 (#14) - node_modules 캐싱 기능 추가 - main, dev 브랜치 push, PR 시 빌드 테스트 돌아가도록 수정 Co-authored-by: wukddang <43228743+funkyblues@users.noreply.github.com> * feature: deploy.yml 파일 추가 (#15) * feature: deploy.yml 파일 추가 - main 브랜치에 push할 때 S3로 파일 업로드 * fix: pre-push 코드 수정 * fix: deploy.yml 파일 수정 - build폴더가 아닌 dist 폴더로 수정 --------- Co-authored-by: wukddang <43228743+funkyblues@users.noreply.github.com> * [Style] 모바일 레이아웃 작업 (#19) * style : 모바일 레이아웃 작업 * chore : 이슈, pr 템플릿 docs 수정 * style: HeroImage, AlertText 공통 컴포넌트 제작 (#24) * style: HeroImage 추가 * style: AlertText * style: Input 공통 컴포넌트 (#26) * style: HeroImage 추가 * style: AlertText * style: Input * feature: Button 공통 컴포넌트 제작 (#20) * feature: 네이버, 카카오 아이콘 컴포넌트 추가 * feature: NormalButton 컴포넌트 추가 * feature: palette, typo 스타일 수정 * feature: Divider, Text 공통 컴포넌트 추가 * feature: IconButtons 추가 - 관심사, 네이버, 카카오, 특정 주제, 랜덤 매칭 버튼 * feature: Button 컴포넌트 사용법 + timeStamp 유틸 함수 추가 * feature: RandomMatchingJoin 버튼 추가 --------- Co-authored-by: wukddang <43228743+funkyblues@users.noreply.github.com> * style : flexbox 컴포넌트 제작 (#32) * style : spacing 컴포넌트 생성 (#33) * [Feature] mock service worker settings (#29) * deploy: 초기 배포 (#23) * style : 전역 디자인 시스템 세팅 * style : 전역 디자인 시스템 세팅 * chore : 이슈 템플릿 수정 * refactor: build-test.yml 파일 수정 (#14) - node_modules 캐싱 기능 추가 - main, dev 브랜치 push, PR 시 빌드 테스트 돌아가도록 수정 Co-authored-by: wukddang <43228743+funkyblues@users.noreply.github.com> * feature: deploy.yml 파일 추가 (#15) * feature: deploy.yml 파일 추가 - main 브랜치에 push할 때 S3로 파일 업로드 * fix: pre-push 코드 수정 * fix: deploy.yml 파일 수정 - build폴더가 아닌 dist 폴더로 수정 --------- Co-authored-by: wukddang <43228743+funkyblues@users.noreply.github.com> * [Style] 모바일 레이아웃 작업 (#19) * style : 모바일 레이아웃 작업 * chore : 이슈, pr 템플릿 docs 수정 --------- Co-authored-by: judahhh Co-authored-by: wukddang <43228743+funkyblues@users.noreply.github.com> * chore : mock service worker 설치 및 세팅 * chore : mock service worder setting --------- Co-authored-by: Changuk Woo <43228743+wukdddang@users.noreply.github.com> Co-authored-by: wukddang <43228743+funkyblues@users.noreply.github.com> * style: BottomSheet 컴포넌트 제작 (#34) * feature: Timer 컴포넌트 추가 + d3.js 라이브러리 설치 * feature: BottomSheet 컴포넌트 추가 * feature: RandomMatchingJoinButton props 수정 * feature: framer-motion 설치 + 애니메이션 효과 추가 * refactor: BottomSheet 폴더 변경 * refactor: isDarkMode 필수 타입으로 수정 * refactor: AlertText, HeroImage 폴더 구조 변경 * refactor: BottomSheet 컴포넌트 분리 * feature: Avatar 컴포넌트 제작 * refactor: RandomMatchingSheet 컴포넌트 이벤트 props 추가 * fix: package-lock.json 파일 오류 수정 --------- Co-authored-by: wukddang <43228743+funkyblues@users.noreply.github.com> * [Style/] navigation bar 컴포넌트 제작 (#37) * style : 네비게이션 바 디자인 * style : 네비게이션 바 디자인 및 라우팅 처리 * fix : 프로필 이미지를 Avatar 컴포넌트를 이용하도록 수정 * chore : 타입 에러 해결 * chore : 홈 페이지에 네비게이션 바 예시 제거 * style: CountNumber 공통 컴포넌트 제작 (#38) * style: CountNumber * feat: Input Wrapper 추가. * chore : CountNumber 폴더 구조 변경 * style: InputTimer 공통 컴포넌트 제작 (#41) * style: CountNumber * feat: Input Wrapper 추가. * style: InputTimer 제작 * style : 로딩 컴포넌트 제작 (#47) * style: WhiteSelectorButton, DarkSelectorButton 공통 컴포넌트 (#46) * style: whiteselectorButton * refactor: 불필요 주석 삭제 * style: darkselectorbutton * Update src/components/common/DarkSelectorButton/index.tsx * Update src/components/common/WhiteSelectorButton/index.tsx * fix: font-weight 오타 수정 --------- Co-authored-by: Changuk Woo <43228743+wukdddang@users.noreply.github.com> Co-authored-by: wukddang <43228743+funkyblues@users.noreply.github.com> * style: ListRow 컴포넌트 제작 (#43) * refactor: Style prefix 붙이도록 수정 * refactor: Divider 컴포넌트 수정 + 웹 폰트 수정 - Divider 컴포넌트가 확장성 있도록 수정 - 웹 폰트 오타 수정 * feature: AdminListRow 컴포넌트 추가 - 관리자 페이지에 사용되는 ListRow 컴포넌트 * feature: ProfileListRow 컴포넌트 추가 - 프로필 페이지에 사용되는 ListRow --------- Co-authored-by: wukddang <43228743+funkyblues@users.noreply.github.com> * style: useToast 커스텀 훅 제작 (#48) * feature: useToast 커스텀 훅 추가 * refactor: RandomMatchingJoinButton으로 이름 변경 * feature: Layout 컴포넌트에 ToastContainer 설정 * refactor: NormalButton 컴포넌트 수정 - isDarkMode props 받도록 수정 * fix: RandomMatchingJoin.tsx 파일 오류 수정 * fix: 파일명 오류 수정 --------- Co-authored-by: wukddang <43228743+funkyblues@users.noreply.github.com> * [Style] Modal 컴포넌트 제작 (#52) * chore : zustand 설치 및 store 폴더 생성 * feat : 모달창 전역 상태 추가 * style : 모달창 컴포넌트 제작 * fix: package.json 쉼표 오류 * fix: package-lock.json 쉼표 오류 * fix : 모달창 type 받아 분기 처리 * fix : type 에러 수정 * chore : 주석 제거 * fix: isDarkMode 옵셔널로 수정 --------- Co-authored-by: Changuk Woo <43228743+wukdddang@users.noreply.github.com> Co-authored-by: wukddang <43228743+funkyblues@users.noreply.github.com> --------- Co-authored-by: judahhh Co-authored-by: wukddang <43228743+funkyblues@users.noreply.github.com> Co-authored-by: from1to2 <124763142+from1to2@users.noreply.github.com> --- package-lock.json | 1909 ++++++++++++++++- package.json | 12 +- public/mockServiceWorker.js | 289 +++ src/assets/LoginImage.svg | 21 + src/assets/icons/Exclamation.svg | 5 + src/assets/icons/KakaoIcon.tsx | 40 + src/assets/icons/NaverIcon.tsx | 34 + src/assets/icons/Warning.svg | 3 + src/assets/images/defaultProfileImage.png | Bin 0 -> 35794 bytes src/components/CountNumber.tsx | 32 + src/components/Input.tsx | 72 + src/components/common/AlertText/index.tsx | 24 + src/components/common/Avatar/index.tsx | 29 + .../common/BottomSheet/ProfileSheet.tsx | 152 ++ .../BottomSheet/RandomMatchingSheet.tsx | 163 ++ src/components/common/BottomSheet/Timer.tsx | 91 + .../Buttons/IconButton/IconButtonStyles.ts | 104 + .../Buttons/IconButton/InterestButton.tsx | 75 + .../common/Buttons/IconButton/KakaoButton.tsx | 42 + .../common/Buttons/IconButton/NaverButton.tsx | 34 + .../IconButton/ParticularTopicButton.tsx | 84 + .../IconButton/RandomMatchingButton.tsx | 83 + .../Buttons/IconButton/RandomMatchingJoin.tsx | 0 .../IconButton/RandomMatchingJoinButton.tsx | 61 + .../common/Buttons/IconButton/index.tsx | 46 + .../Buttons/NormalButton/NormalButton.tsx | 36 + .../NormalButton/NormalButtonStyles.ts | 176 ++ src/components/common/CountNumber/index.tsx | 32 + .../common/DarkSelectorButton/index.tsx | 77 + src/components/common/Divider/index.tsx | 17 + src/components/common/Flexbox/index.tsx | 52 + src/components/common/HeroImage/index.tsx | 19 + src/components/common/InputTimer/index.tsx | 42 + .../common/ListRow/AdminListRow.tsx | 90 + .../common/ListRow/ProfileListRow.tsx | 94 + src/components/common/Loading/index.tsx | 20 + src/components/common/Modal/index.tsx | 124 ++ src/components/common/NavigationBar/index.tsx | 68 + src/components/common/Spacing/index.tsx | 18 + src/components/common/Text/index.tsx | 25 + .../common/WhiteSelectorButton/index.tsx | 63 + src/components/layouts/Layout.tsx | 6 + src/hooks/useModal.tsx | 22 + src/hooks/useToast.tsx | 25 + src/main.tsx | 6 + src/mocks/handlers.ts | 8 + src/mocks/worker.ts | 5 + src/store/ModalStore.tsx | 28 + src/styles/global.ts | 11 +- src/styles/palette.ts | 4 +- src/styles/typo.ts | 42 +- src/utils/getTimeStamp.ts | 40 + tsconfig.json | 4 +- 53 files changed, 4506 insertions(+), 53 deletions(-) create mode 100644 public/mockServiceWorker.js create mode 100644 src/assets/LoginImage.svg create mode 100644 src/assets/icons/Exclamation.svg create mode 100644 src/assets/icons/KakaoIcon.tsx create mode 100644 src/assets/icons/NaverIcon.tsx create mode 100644 src/assets/icons/Warning.svg create mode 100644 src/assets/images/defaultProfileImage.png create mode 100644 src/components/CountNumber.tsx create mode 100644 src/components/Input.tsx create mode 100644 src/components/common/AlertText/index.tsx create mode 100644 src/components/common/Avatar/index.tsx create mode 100644 src/components/common/BottomSheet/ProfileSheet.tsx create mode 100644 src/components/common/BottomSheet/RandomMatchingSheet.tsx create mode 100644 src/components/common/BottomSheet/Timer.tsx create mode 100644 src/components/common/Buttons/IconButton/IconButtonStyles.ts create mode 100644 src/components/common/Buttons/IconButton/InterestButton.tsx create mode 100644 src/components/common/Buttons/IconButton/KakaoButton.tsx create mode 100644 src/components/common/Buttons/IconButton/NaverButton.tsx create mode 100644 src/components/common/Buttons/IconButton/ParticularTopicButton.tsx create mode 100644 src/components/common/Buttons/IconButton/RandomMatchingButton.tsx create mode 100644 src/components/common/Buttons/IconButton/RandomMatchingJoin.tsx create mode 100644 src/components/common/Buttons/IconButton/RandomMatchingJoinButton.tsx create mode 100644 src/components/common/Buttons/IconButton/index.tsx create mode 100644 src/components/common/Buttons/NormalButton/NormalButton.tsx create mode 100644 src/components/common/Buttons/NormalButton/NormalButtonStyles.ts create mode 100644 src/components/common/CountNumber/index.tsx create mode 100644 src/components/common/DarkSelectorButton/index.tsx create mode 100644 src/components/common/Divider/index.tsx create mode 100644 src/components/common/Flexbox/index.tsx create mode 100644 src/components/common/HeroImage/index.tsx create mode 100644 src/components/common/InputTimer/index.tsx create mode 100644 src/components/common/ListRow/AdminListRow.tsx create mode 100644 src/components/common/ListRow/ProfileListRow.tsx create mode 100644 src/components/common/Loading/index.tsx create mode 100644 src/components/common/Modal/index.tsx create mode 100644 src/components/common/NavigationBar/index.tsx create mode 100644 src/components/common/Spacing/index.tsx create mode 100644 src/components/common/Text/index.tsx create mode 100644 src/components/common/WhiteSelectorButton/index.tsx create mode 100644 src/hooks/useModal.tsx create mode 100644 src/hooks/useToast.tsx create mode 100644 src/mocks/handlers.ts create mode 100644 src/mocks/worker.ts create mode 100644 src/store/ModalStore.tsx create mode 100644 src/utils/getTimeStamp.ts diff --git a/package-lock.json b/package-lock.json index ed92fac0..60875e21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,17 +12,23 @@ "@emotion/styled": "^11.11.0", "@tanstack/react-query": "^4.36.1", "axios": "^1.5.1", + "d3": "^7.8.5", "emotion-reset": "^3.0.1", + "framer-motion": "^10.16.4", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.47.0", "react-icons": "^4.11.0", "react-router-dom": "^6.16.0", - "react-toastify": "^9.1.3" + "react-spinners": "^0.13.8", + "react-toastify": "^9.1.3", + "zustand": "^4.4.4", + "zustand-persist": "^0.4.0" }, "devDependencies": { "@rushstack/eslint-config": "^3.4.1", "@tanstack/react-query-devtools": "^4.36.1", + "@types/d3": "^7.4.2", "@types/node": "^20.8.6", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", @@ -39,6 +45,7 @@ "eslint-plugin-simple-import-sort": "^10.0.0", "husky": "^8.0.0", "lint-staged": "^15.0.1", + "msw": "^2.0.0", "prettier": "^3.0.3", "typescript": "^5.0.2", "vite": "^4.4.5", @@ -549,6 +556,33 @@ "node": ">=6.9.0" } }, + "node_modules/@bundled-es-modules/cookie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz", + "integrity": "sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==", + "dev": true, + "dependencies": { + "cookie": "^0.5.0" + } + }, + "node_modules/@bundled-es-modules/js-levenshtein": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/js-levenshtein/-/js-levenshtein-2.0.1.tgz", + "integrity": "sha512-DERMS3yfbAljKsQc0U2wcqGKUWpdFjwqWuoMugEJlqBnKO180/n+4SR/J8MRDt1AN48X1ovgoD9KrdVXcaa3Rg==", + "dev": true, + "dependencies": { + "js-levenshtein": "^1.1.6" + } + }, + "node_modules/@bundled-es-modules/statuses": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz", + "integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==", + "dev": true, + "dependencies": { + "statuses": "^2.0.1" + } + }, "node_modules/@emotion/babel-plugin": { "version": "11.11.0", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", @@ -1202,6 +1236,32 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/@mswjs/cookies": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-1.0.0.tgz", + "integrity": "sha512-TdXoBdI+h/EDTsVLCX/34s4+9U0sWi92qFnIGUEikpMCSKLhBeujovyYVSoORNbYgsBH5ga7/tfxyWcEZAxiYA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@mswjs/interceptors": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.25.7.tgz", + "integrity": "sha512-U7iFYs/qU/5jfz1VDpoYz3xqX9nzhsBXw7q923dv6GiGTy+m2ZLhD33L80R/shHOW/YWjeH6k16GbIHGw+bAng==", + "dev": true, + "dependencies": { + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.2.1", + "strict-event-emitter": "^0.5.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1237,6 +1297,28 @@ "node": ">= 8" } }, + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", + "dev": true + }, + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", + "dev": true, + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" + } + }, + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", + "dev": true + }, "node_modules/@pkgr/utils": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", @@ -2130,12 +2212,283 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "node_modules/@types/d3": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.2.tgz", + "integrity": "sha512-Y4g2Yb30ZJmmtqAJTqMRaqXwRawfvpdpVmyEYEcyGNhrQI/Zvkq3k7yE1tdN07aFSmNBfvmegMQ9Fe2qy9ZMhw==", + "dev": true, + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.9.tgz", + "integrity": "sha512-mZowFN3p64ajCJJ4riVYlOjNlBJv3hctgAY01pjw3qTnJePD8s9DZmYDzhHKvzfCYvdjwylkU38+Vdt7Cu2FDA==", + "dev": true + }, + "node_modules/@types/d3-axis": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.5.tgz", + "integrity": "sha512-ufDAV3SQzju+uB3Jlty7SUb/jMigjpIlvDDcSGvGmmO6OT/sNO93UE0dRzwWOZeBLzrLSA0CQM4bf3iq1std3A==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.5.tgz", + "integrity": "sha512-JROQXZNq1X6QdWstESDUv1VilwZ2hBCQnWB91yal+5yZvYwGQvYsGCjrkHGfKK/8/AcX1JnERmpQzdDDuLRUsA==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.5.tgz", + "integrity": "sha512-rs26AIhJjtc+XLR4YQU8IjPTLOlDVO4PR1y+pVFYEHzKh2tE5tYz3MF4QV6iz7HboXQEaYpJQt8dH9uUkne8yA==", + "dev": true + }, + "node_modules/@types/d3-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.2.tgz", + "integrity": "sha512-At+Ski7dL8Bs58E8g8vPcFJc8tGcaC12Z4m07+p41+DRqnZQcAlp3NfYjLrhNYv+zEyQitU1CUxXNjqUyf+c0g==", + "dev": true + }, + "node_modules/@types/d3-contour": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.5.tgz", + "integrity": "sha512-wLvjwdOQVd1NL1IcW90CCt1VtpeZ3V20p/OTXlkT8uAiprrJnq2PNNnRNe1QCez4U9aMU29Z14zpJQVLW1+Lcg==", + "dev": true, + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.3.tgz", + "integrity": "sha512-+Lf5NPKZ4JBC9tbudVkKceQXRxU3jJs0el9aKQvinMtdnFSOG84eVXyhCNgIFuXNQO3iIcYs7sgzN359FEOZnQ==", + "dev": true + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.5.tgz", + "integrity": "sha512-hxvq2kc+9hydVppo21JCGfcM0tLTh1DXnG3MLN0KlxsNZJH4bsdl1iXDuWtXFpWWlBrCMwSqlnoLPDxNAZU3Bg==", + "dev": true + }, + "node_modules/@types/d3-drag": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.5.tgz", + "integrity": "sha512-arHyAGvO0NEGGPCU2jTb31TlXeSxwty1bIxr5wOFOCVqVjgriXloLWXoRp39Oa0Y/qXxcAVMIonAWLrtLxUZAQ==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.5.tgz", + "integrity": "sha512-73WZR3QFOaSRVz9iOrebTbTnbo7xjcgS/i0Cq5zy0jMXPO3v/JbkTD3Zqii1eYE6v4EJ78g5VP407rm+p8fdlA==", + "dev": true + }, + "node_modules/@types/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-VZofjpEt8HWv3nxUAosj5o/+4JflnJ7Bbv07k17VO3T2WRuzGdZeookfaF60iVh5RdhVG49LE5w6LIshVUC6rg==", + "dev": true + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.5.tgz", + "integrity": "sha512-Rc8pb6H0RRLpAV2hEXduykUgcDUOhjSLTLmCIeo6ejzgs4SaITh/EteMb3p5Env3Hqjsqw0fCksyqopHHzMkMg==", + "dev": true, + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.7.tgz", + "integrity": "sha512-rsok4CEvPLyVWRPsFiBhanJc3up03H/EARVz4d8soPh8drv82YMuAckYy4yv8g4/81JwCng5U5/o9aj9d0T6bQ==", + "dev": true + }, + "node_modules/@types/d3-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.3.tgz", + "integrity": "sha512-kxuLXSAEJykTeL/EI3tUiEfGqru7PRdqEy099YBnqFl+fF167UVSB4+wntlZv86ZdoYf0DHjsRHnTIm8kcH7qw==", + "dev": true + }, + "node_modules/@types/d3-geo": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.0.6.tgz", + "integrity": "sha512-wblAES3b+C3hvp4VakwECEKtHquT/xc6K4HOna95LM1j1fd7s7WmU4V+JMQZfKhNCMkV2vWD+ZUgY2Uj6gqfuA==", + "dev": true, + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.5.tgz", + "integrity": "sha512-DEcBUj1IL3WyPLDlh4m2nsNXnMLITXM5Vwcu4G85yJHtf2cVGPBjgky3L11WBnT+ayHKf06Tchk5mY1eGmd4WQ==", + "dev": true + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.3.tgz", + "integrity": "sha512-6OZ2EIB4lLj+8cUY7I/Cgn9Q+hLdA4DjJHYOQDiHL0SzqS1K9DL5xIOVBSIHgF+tiuO9MU1D36qvdIvRDRPh+Q==", + "dev": true, + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.1.tgz", + "integrity": "sha512-blRhp7ki7pVznM8k6lk5iUU9paDbVRVq+/xpf0RRgSJn5gr6SE7RcFtxooYGMBOc1RZiGyqRpVdu5AD0z0ooMA==", + "dev": true + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-nrcWPk7B9qs6xnpq60Cls44zm9eDmFAv65qi/N/emh/oftnG6uYz49aIS0mdFaGeJxVN8H3pHneMuZMV8EwFdw==", + "dev": true + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.4.tgz", + "integrity": "sha512-B725MopFDIOQ6njFbeOxIEf42HVO2Xv+FmcxQISdOKErvLbFqWz3Riu+OWujUYoogreqqyHBHcGGL/JzzXQYsw==", + "dev": true + }, + "node_modules/@types/d3-random": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.2.tgz", + "integrity": "sha512-8QhsqkKs6mymAZMrg3ZFXPxKA34rdgp3ZrtB8o6mhFsKAd1gOvR1gocWnca+kmXypQdwgnzKm9gZE2Uw8NjjKw==", + "dev": true + }, + "node_modules/@types/d3-scale": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.6.tgz", + "integrity": "sha512-lo3oMLSiqsQUovv8j15X4BNEDOsnHuGjeVg7GRbAuB2PUa1prK5BNSOu6xixgNf3nqxPl4I1BqJWrPvFGlQoGQ==", + "dev": true, + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.1.tgz", + "integrity": "sha512-Ob7OrwiTeQXY/WBBbRHGZBOn6rH1h7y3jjpTSKYqDEeqFjktql6k2XSgNwLrLDmAsXhEn8P9NHDY4VTuo0ZY1w==", + "dev": true + }, + "node_modules/@types/d3-selection": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.8.tgz", + "integrity": "sha512-pxCZUfQyedq/DIlPXIR5wE1mIH37omOdx1yxRudL3KZ4AC+156jMjOv1z5RVlGq62f8WX2kyO0hTVgEx627QFg==", + "dev": true + }, + "node_modules/@types/d3-shape": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.4.tgz", + "integrity": "sha512-M2/xsWPsjaZc5ifMKp1EBp0gqJG0eO/zlldJNOC85Y/5DGsBQ49gDkRJ2h5GY7ZVD6KUumvZWsylSbvTaJTqKg==", + "dev": true, + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.2.tgz", + "integrity": "sha512-kbdRXTmUgNfw5OTE3KZnFQn6XdIc4QGroN5UixgdrXATmYsdlPQS6pEut9tVlIojtzuFD4txs/L+Rq41AHtLpg==", + "dev": true + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.2.tgz", + "integrity": "sha512-wr08C1Gh77qaN8JIkrn5Rz/bdt5M9bdEqFmEOcYhUSq2t2sHvLTBfb4XAtGB3D4hm0ubj50NXWWXoXyp5tPXDg==", + "dev": true + }, + "node_modules/@types/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-GGTvzKccVEhxmRfJEB6zhY9ieT4UhGVUIQaBzFpUO9OXy2ycAlnPCSJLzmGGgqt3KVjqN3QCQB4g1rsZnHsWhg==", + "dev": true + }, + "node_modules/@types/d3-transition": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.6.tgz", + "integrity": "sha512-K0To23B5UxNwFtKORnS5JoNYvw/DnknU5MzhHIS9czJ/lTqFFDeU6w9lArOdoTl0cZFNdNrMJSFCbRCEHccH2w==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.6.tgz", + "integrity": "sha512-dGZQaXEu7aNcCL71LPpjB58IjoQNM9oDPfQuMUJ7N/fbkcIWGX2PnmUWO1jPJ+RLbZBpRUggJUX8twKRvo2hKQ==", + "dev": true, + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.3.tgz", "integrity": "sha512-CS2rOaoQ/eAgAfcTfq6amKG7bsN+EMcgGY4FAFQdvSj2y1ixvOZTUA9mOtCai7E1SYu283XNw7urKK30nP3wkQ==", "dev": true }, + "node_modules/@types/geojson": { + "version": "7946.0.12", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.12.tgz", + "integrity": "sha512-uK2z1ZHJyC0nQRbuovXFt4mzXDwf27vQeUWNhfKGwRcWW429GOhP8HxUHlM6TLH4bzmlv/HlEjpvJh3JfmGsAA==", + "dev": true + }, + "node_modules/@types/js-levenshtein": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.2.tgz", + "integrity": "sha512-/NCbMABw2uacuyE16Iwka1EzREDD50/W2ggRBad0y1WHBvAkvR9OEINxModVY7D428gXBe0igeVX7bUc9GaslQ==", + "dev": true + }, "node_modules/@types/json-schema": { "version": "7.0.14", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", @@ -2167,13 +2520,13 @@ "version": "15.7.9", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.9.tgz", "integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==", - "dev": true + "devOptional": true }, "node_modules/@types/react": { "version": "18.2.30", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.30.tgz", "integrity": "sha512-OfqdJnDsSo4UNw0bqAjFCuBpLYQM7wvZidz0hVxHRjrEkzRlvZL1pJVyOSY55HMiKvRNEo9DUBRuEl7FNlJ/Vg==", - "dev": true, + "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2193,7 +2546,7 @@ "version": "0.16.5", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.5.tgz", "integrity": "sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==", - "dev": true + "devOptional": true }, "node_modules/@types/semver": { "version": "7.5.4", @@ -2201,6 +2554,12 @@ "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", "dev": true }, + "node_modules/@types/statuses": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.3.tgz", + "integrity": "sha512-NwCYScf83RIwCyi5/9cXocrJB//xrqMh5PMw3mYTSFGaI3DuVjBLfO/PCk7QVAC3Da8b9NjxNmTO9Aj9T3rl/Q==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz", @@ -2715,6 +3074,19 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2908,6 +3280,26 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/big-integer": { "version": "1.6.51", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", @@ -2917,6 +3309,26 @@ "node": ">=0.6" } }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/bplist-parser": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", @@ -2983,6 +3395,30 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/bundle-name": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", @@ -3068,6 +3504,51 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/cli-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", @@ -3083,6 +3564,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-spinners": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz", + "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-truncate": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", @@ -3099,21 +3592,99 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, "engines": { - "node": ">=6" + "node": ">= 10" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" }, "engines": { "node": ">=7.0.0" @@ -3162,6 +3733,15 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/copy-anything": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", @@ -3211,6 +3791,384 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "node_modules/d3": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.5.tgz", + "integrity": "sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -3318,6 +4276,18 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-data-property": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", @@ -3361,6 +4331,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "dependencies": { + "robust-predicates": "^3.0.0" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -4105,8 +5083,34 @@ "engines": { "node": ">=16.17" }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/external-editor/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/fast-deep-equal": { @@ -4170,6 +5174,30 @@ "reusify": "^1.0.4" } }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4276,6 +5304,57 @@ "node": ">= 6" } }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dev": true, + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/framer-motion": { + "version": "10.16.4", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.16.4.tgz", + "integrity": "sha512-p9V9nGomS3m6/CALXqv6nFGMuFOxbWsmaOrdmhyQimMIlLl3LC7h7l86wge/Js/8cRu5ktutS/zlzgR7eBOtFA==", + "dependencies": { + "tslib": "^2.4.0" + }, + "optionalDependencies": { + "@emotion/is-prop-valid": "^0.8.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/framer-motion/node_modules/@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "optional": true, + "dependencies": { + "@emotion/memoize": "0.7.4" + } + }, + "node_modules/framer-motion/node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "optional": true + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -4341,6 +5420,15 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", @@ -4514,6 +5602,15 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/graphql": { + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", + "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, "node_modules/has": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", @@ -4591,6 +5688,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/headers-polyfill": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.2.tgz", + "integrity": "sha512-EWGTfnTqAO2L/j5HZgoM/3z82L7necsJ0pO9Tp0X1wil3PDLrkypTBRgVO2ExehEEvUycejZD3FuRaXpZZc3kw==", + "dev": true + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -4623,6 +5726,37 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -4672,6 +5806,157 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inquirer/node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/inquirer/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/inquirer/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inquirer/node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/inquirer/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inquirer/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/internal-slot": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", @@ -4686,6 +5971,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/is-array-buffer": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", @@ -4732,6 +6025,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -4879,6 +6184,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", @@ -4900,6 +6214,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", + "dev": true + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5027,6 +6347,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", @@ -5131,6 +6463,15 @@ "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", "dev": true }, + "node_modules/js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5327,12 +6668,34 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/log-update": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", @@ -5489,13 +6852,81 @@ "dev": true, "peer": true, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/msw": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.0.0.tgz", + "integrity": "sha512-lw9UHuzNCWoODHaThGeLLIIuzEBUQkj3fJXQnChHifMKbB2UmF2msHd4d/lnyqjAyD0XWoibdviW9wlstFPpkA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@bundled-es-modules/cookie": "^2.0.0", + "@bundled-es-modules/js-levenshtein": "^2.0.1", + "@bundled-es-modules/statuses": "^1.0.1", + "@mswjs/cookies": "^1.0.0", + "@mswjs/interceptors": "^0.25.1", + "@open-draft/until": "^2.1.0", + "@types/cookie": "^0.4.1", + "@types/js-levenshtein": "^1.1.1", + "@types/statuses": "^2.0.1", + "chalk": "^4.1.2", + "chokidar": "^3.4.2", + "formdata-node": "4.4.1", + "graphql": "^16.8.1", + "headers-polyfill": "^4.0.1", + "inquirer": "^8.2.0", + "is-node-process": "^1.2.0", + "js-levenshtein": "^1.1.6", + "node-fetch": "^2.6.7", + "outvariant": "^1.4.0", + "path-to-regexp": "^6.2.0", + "strict-event-emitter": "^0.5.0", + "type-fest": "^2.19.0", + "yargs": "^17.3.1" + }, + "bin": { + "msw": "cli/index.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mswjs" + }, + "peerDependencies": { + "typescript": ">= 4.7.x <= 5.2.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/msw/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, "node_modules/nanoid": { @@ -5538,12 +6969,60 @@ "tslib": "^2.0.3" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.13", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-run-path": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", @@ -5749,6 +7228,99 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ora/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/outvariant": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.0.tgz", + "integrity": "sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==", + "dev": true + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -5839,6 +7411,12 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "dev": true + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -6067,6 +7645,15 @@ "react-dom": ">=16.8" } }, + "node_modules/react-spinners": { + "version": "0.13.8", + "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.13.8.tgz", + "integrity": "sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==", + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-toastify": { "version": "9.1.3", "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz", @@ -6079,6 +7666,32 @@ "react-dom": ">=16" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", @@ -6127,6 +7740,15 @@ "integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==", "dev": true }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -6237,6 +7859,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, "node_modules/rollup": { "version": "3.29.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", @@ -6375,6 +8002,15 @@ "node": ">=6" } }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6398,6 +8034,20 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-array-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", @@ -6416,6 +8066,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/safe-regex-test": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", @@ -6430,6 +8100,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -6593,6 +8268,30 @@ "node": ">=0.10.0" } }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/strict-event-emitter": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", + "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", + "dev": true + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-argv": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", @@ -6834,6 +8533,12 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, "node_modules/titleize": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", @@ -6846,6 +8551,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -6866,6 +8583,12 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, "node_modules/ts-api-utils": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", @@ -6914,8 +8637,7 @@ "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -7117,6 +8839,12 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, "node_modules/vite": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", @@ -7205,6 +8933,40 @@ } } }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7358,6 +9120,15 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -7372,6 +9143,62 @@ "node": ">= 6" } }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -7383,6 +9210,42 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.4.tgz", + "integrity": "sha512-5UTUIAiHMNf5+mFp7/AnzJXS7+XxktULFN0+D1sCiZWyX7ZG+AQpqs2qpYrynRij4QvoDdCD+U+bmg/cG3Ucxw==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/zustand-persist": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/zustand-persist/-/zustand-persist-0.4.0.tgz", + "integrity": "sha512-u6bBIc4yZRpSKBKuTNhoqvoIb09gGHk2NkiPg4K7MPIWTYZg70PlpBn48QEDnKZwfNurnf58TaW5BuMGIMf5hw==", + "peerDependencies": { + "react": ">=16.8.0", + "zustand": ">=3.6.3" + } } } } diff --git a/package.json b/package.json index 6a0b0a8d..5c48947f 100644 --- a/package.json +++ b/package.json @@ -15,17 +15,23 @@ "@emotion/styled": "^11.11.0", "@tanstack/react-query": "^4.36.1", "axios": "^1.5.1", + "d3": "^7.8.5", "emotion-reset": "^3.0.1", + "framer-motion": "^10.16.4", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.47.0", "react-icons": "^4.11.0", "react-router-dom": "^6.16.0", - "react-toastify": "^9.1.3" + "react-toastify": "^9.1.3", + "zustand": "^4.4.4", + "zustand-persist": "^0.4.0", + "react-spinners": "^0.13.8" }, "devDependencies": { "@rushstack/eslint-config": "^3.4.1", "@tanstack/react-query-devtools": "^4.36.1", + "@types/d3": "^7.4.2", "@types/node": "^20.8.6", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", @@ -42,6 +48,7 @@ "eslint-plugin-simple-import-sort": "^10.0.0", "husky": "^8.0.0", "lint-staged": "^15.0.1", + "msw": "^2.0.0", "prettier": "^3.0.3", "typescript": "^5.0.2", "vite": "^4.4.5", @@ -53,5 +60,8 @@ "eslint --fix", "prettier --write" ] + }, + "msw": { + "workerDirectory": "public" } } diff --git a/public/mockServiceWorker.js b/public/mockServiceWorker.js new file mode 100644 index 00000000..29c33774 --- /dev/null +++ b/public/mockServiceWorker.js @@ -0,0 +1,289 @@ +/* eslint-disable */ +/* tslint:disable */ + +/** + * Mock Service Worker (2.0.0). + * @see https://github.com/mswjs/msw + * - Please do NOT modify this file. + * - Please do NOT serve this file on production. + */ + +const INTEGRITY_CHECKSUM = '0877fcdc026242810f5bfde0d7178db4' +const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') +const activeClientIds = new Set() + +self.addEventListener('install', function () { + self.skipWaiting() +}) + +self.addEventListener('activate', function (event) { + event.waitUntil(self.clients.claim()) +}) + +self.addEventListener('message', async function (event) { + const clientId = event.source.id + + if (!clientId || !self.clients) { + return + } + + const client = await self.clients.get(clientId) + + if (!client) { + return + } + + const allClients = await self.clients.matchAll({ + type: 'window', + }) + + switch (event.data) { + case 'KEEPALIVE_REQUEST': { + sendToClient(client, { + type: 'KEEPALIVE_RESPONSE', + }) + break + } + + case 'INTEGRITY_CHECK_REQUEST': { + sendToClient(client, { + type: 'INTEGRITY_CHECK_RESPONSE', + payload: INTEGRITY_CHECKSUM, + }) + break + } + + case 'MOCK_ACTIVATE': { + activeClientIds.add(clientId) + + sendToClient(client, { + type: 'MOCKING_ENABLED', + payload: true, + }) + break + } + + case 'MOCK_DEACTIVATE': { + activeClientIds.delete(clientId) + break + } + + case 'CLIENT_CLOSED': { + activeClientIds.delete(clientId) + + const remainingClients = allClients.filter((client) => { + return client.id !== clientId + }) + + // Unregister itself when there are no more clients + if (remainingClients.length === 0) { + self.registration.unregister() + } + + break + } + } +}) + +self.addEventListener('fetch', function (event) { + const { request } = event + + // Bypass navigation requests. + if (request.mode === 'navigate') { + return + } + + // Opening the DevTools triggers the "only-if-cached" request + // that cannot be handled by the worker. Bypass such requests. + if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') { + return + } + + // Bypass all requests when there are no active clients. + // Prevents the self-unregistered worked from handling requests + // after it's been deleted (still remains active until the next reload). + if (activeClientIds.size === 0) { + return + } + + // Generate unique request ID. + const requestId = crypto.randomUUID() + event.respondWith(handleRequest(event, requestId)) +}) + +async function handleRequest(event, requestId) { + const client = await resolveMainClient(event) + const response = await getResponse(event, client, requestId) + + // Send back the response clone for the "response:*" life-cycle events. + // Ensure MSW is active and ready to handle the message, otherwise + // this message will pend indefinitely. + if (client && activeClientIds.has(client.id)) { + ;(async function () { + const responseClone = response.clone() + // When performing original requests, response body will + // always be a ReadableStream, even for 204 responses. + // But when creating a new Response instance on the client, + // the body for a 204 response must be null. + const responseBody = response.status === 204 ? null : responseClone.body + + sendToClient( + client, + { + type: 'RESPONSE', + payload: { + requestId, + isMockedResponse: IS_MOCKED_RESPONSE in response, + type: responseClone.type, + status: responseClone.status, + statusText: responseClone.statusText, + body: responseBody, + headers: Object.fromEntries(responseClone.headers.entries()), + }, + }, + [responseBody], + ) + })() + } + + return response +} + +// Resolve the main client for the given event. +// Client that issues a request doesn't necessarily equal the client +// that registered the worker. It's with the latter the worker should +// communicate with during the response resolving phase. +async function resolveMainClient(event) { + const client = await self.clients.get(event.clientId) + + if (client?.frameType === 'top-level') { + return client + } + + const allClients = await self.clients.matchAll({ + type: 'window', + }) + + return allClients + .filter((client) => { + // Get only those clients that are currently visible. + return client.visibilityState === 'visible' + }) + .find((client) => { + // Find the client ID that's recorded in the + // set of clients that have registered the worker. + return activeClientIds.has(client.id) + }) +} + +async function getResponse(event, client, requestId) { + const { request } = event + + // Clone the request because it might've been already used + // (i.e. its body has been read and sent to the client). + const requestClone = request.clone() + + function passthrough() { + const headers = Object.fromEntries(requestClone.headers.entries()) + + // Remove internal MSW request header so the passthrough request + // complies with any potential CORS preflight checks on the server. + // Some servers forbid unknown request headers. + delete headers['x-msw-intention'] + + return fetch(requestClone, { headers }) + } + + // Bypass mocking when the client is not active. + if (!client) { + return passthrough() + } + + // Bypass initial page load requests (i.e. static assets). + // The absence of the immediate/parent client in the map of the active clients + // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet + // and is not ready to handle requests. + if (!activeClientIds.has(client.id)) { + return passthrough() + } + + // Bypass requests with the explicit bypass header. + // Such requests can be issued by "ctx.fetch()". + const mswIntention = request.headers.get('x-msw-intention') + if (['bypass', 'passthrough'].includes(mswIntention)) { + return passthrough() + } + + // Notify the client that a request has been intercepted. + const requestBuffer = await request.arrayBuffer() + const clientMessage = await sendToClient( + client, + { + type: 'REQUEST', + payload: { + id: requestId, + url: request.url, + mode: request.mode, + method: request.method, + headers: Object.fromEntries(request.headers.entries()), + cache: request.cache, + credentials: request.credentials, + destination: request.destination, + integrity: request.integrity, + redirect: request.redirect, + referrer: request.referrer, + referrerPolicy: request.referrerPolicy, + body: requestBuffer, + keepalive: request.keepalive, + }, + }, + [requestBuffer], + ) + + switch (clientMessage.type) { + case 'MOCK_RESPONSE': { + return respondWithMock(clientMessage.data) + } + + case 'MOCK_NOT_FOUND': { + return passthrough() + } + } + + return passthrough() +} + +function sendToClient(client, message, transferrables = []) { + return new Promise((resolve, reject) => { + const channel = new MessageChannel() + + channel.port1.onmessage = (event) => { + if (event.data && event.data.error) { + return reject(event.data.error) + } + + resolve(event.data) + } + + client.postMessage(message, [channel.port2].concat(transferrables.filter(Boolean))) + }) +} + +async function respondWithMock(response) { + // Setting response status code to 0 is a no-op. + // However, when responding with a "Response.error()", the produced Response + // instance will have status code set to 0. Since it's not possible to create + // a Response instance with status code 0, handle that use-case separately. + if (response.status === 0) { + return Response.error() + } + + const mockedResponse = new Response(response.body, response) + + Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, { + value: true, + enumerable: true, + }) + + return mockedResponse +} diff --git a/src/assets/LoginImage.svg b/src/assets/LoginImage.svg new file mode 100644 index 00000000..3de58a8b --- /dev/null +++ b/src/assets/LoginImage.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/Exclamation.svg b/src/assets/icons/Exclamation.svg new file mode 100644 index 00000000..c6348371 --- /dev/null +++ b/src/assets/icons/Exclamation.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/KakaoIcon.tsx b/src/assets/icons/KakaoIcon.tsx new file mode 100644 index 00000000..bea9b248 --- /dev/null +++ b/src/assets/icons/KakaoIcon.tsx @@ -0,0 +1,40 @@ +import { palette } from '@/styles/palette' + +export type IconProps = { + width: number + height: number + iconWidth?: number + iconHeight?: number + borderRadius: number +} + +const KakaoIcon = ({ width, height, iconWidth, iconHeight, borderRadius }: IconProps) => ( + + + + + +) + +export default KakaoIcon diff --git a/src/assets/icons/NaverIcon.tsx b/src/assets/icons/NaverIcon.tsx new file mode 100644 index 00000000..a3db7a9d --- /dev/null +++ b/src/assets/icons/NaverIcon.tsx @@ -0,0 +1,34 @@ +import { palette } from '@/styles/palette' + +import { IconProps } from './KakaoIcon' + +const NaverIcon = ({ width, height, iconWidth, iconHeight, borderRadius }: IconProps) => ( + + + + + +) + +export default NaverIcon diff --git a/src/assets/icons/Warning.svg b/src/assets/icons/Warning.svg new file mode 100644 index 00000000..8a1b6177 --- /dev/null +++ b/src/assets/icons/Warning.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/defaultProfileImage.png b/src/assets/images/defaultProfileImage.png new file mode 100644 index 0000000000000000000000000000000000000000..4c4675674452b1dc87b02a1a76d1ce06b009eeb8 GIT binary patch literal 35794 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 literal 0 HcmV?d00001 diff --git a/src/components/CountNumber.tsx b/src/components/CountNumber.tsx new file mode 100644 index 00000000..018aaf35 --- /dev/null +++ b/src/components/CountNumber.tsx @@ -0,0 +1,32 @@ +import styled from '@emotion/styled' + +type CountNumberProps = { + currentLength: number + maxLength: number + color: string + right: number +} + +type StyleCountNumberProps = { + color: string + right: number +} + +const CountNumber = ({ right, currentLength, maxLength, color }: CountNumberProps): JSX.Element => { + return ( + {`${currentLength}/${maxLength}`} + ) +} + +const StyleCountNumber = styled.span` + position: relative; + right: ${(props) => props.right}px; + bottom: 3px; + font-size: 12px; + color: ${(props) => props.color}; +` + +export default CountNumber diff --git a/src/components/Input.tsx b/src/components/Input.tsx new file mode 100644 index 00000000..28e71169 --- /dev/null +++ b/src/components/Input.tsx @@ -0,0 +1,72 @@ +import styled from '@emotion/styled' + +type InputProps = { + placeholder?: string + placeholderSize?: string + placeholderColor?: string + width?: string + height?: string + borderColor?: string + borderWidth?: string + inputTextColor?: string + inputTextSize?: string + inputBackgroundColor?: string + borderRadius?: string +} + +const Input = ({ + placeholder, + placeholderSize, + placeholderColor, + width, + height, + borderColor, + borderWidth, + borderRadius, + inputTextColor, + inputTextSize, + inputBackgroundColor, +}: InputProps) => { + return ( + <> + + + + + ) +} + +const InputWrapper = styled.div` + position: relative; +` + +const StyleInput = styled.input` + ::placeholder { + font-size: ${(props) => props.placeholderSize}; + color: ${(props) => props.placeholderColor}; + } + position: relative; + placeholder: ${(props) => props.placeholder}; + width: ${(props) => props.width}; + height: ${(props) => props.height}; + border-color: ${(props) => props.borderColor}; + border-width: ${(props) => props.borderWidth}; + color: ${(props) => props.inputTextColor}; + background-color: ${(props) => props.inputBackgroundColor}; + border-radius: ${(props) => props.borderRadius}; + font-size: ${(props) => props.inputTextSize}; +` + +export default Input diff --git a/src/components/common/AlertText/index.tsx b/src/components/common/AlertText/index.tsx new file mode 100644 index 00000000..f3d3003b --- /dev/null +++ b/src/components/common/AlertText/index.tsx @@ -0,0 +1,24 @@ +import styled from '@emotion/styled' + +type AlertTextProps = { + fontSize: string + fontColor: string + children?: React.ReactNode +} + +const AlertText = ({ fontSize, fontColor, children }: AlertTextProps) => { + return ( + <> + + {children} + + + ) +} + +const StyleAlertText = styled.div` + font-size: ${(props) => props.fontSize}; + color: ${(props) => props.fontColor}; +` + +export default AlertText diff --git a/src/components/common/Avatar/index.tsx b/src/components/common/Avatar/index.tsx new file mode 100644 index 00000000..43b56e00 --- /dev/null +++ b/src/components/common/Avatar/index.tsx @@ -0,0 +1,29 @@ +import styled from '@emotion/styled' + +type AvatarProps = { + width: number + height: number + imgUrl: string + margin: string + shadow?: boolean +} + +const StyledAvatar = styled.div` + width: ${(props) => (typeof props.width === 'number' ? `${props.width}px` : props.width)}; + height: ${(props) => (typeof props.height === 'number' ? `${props.height}px` : props.height)}; + background-image: url(${(props) => props.imgUrl}); + background-size: cover; + background-repeat: no-repeat; + background-position: center center; + border-radius: 50%; // 원 형태로 만들기 위함 + margin: ${(props) => `${props.margin}px`}; + box-shadow: ${(props) => (props.shadow ? '0px 0px 10px rgba(0, 0, 0, 0.25)' : 'none')}; +` + +const Avatar: React.FC = ({ width, height, imgUrl, margin = '0', shadow = false }) => { + return ( + + ) +} + +export default Avatar diff --git a/src/components/common/BottomSheet/ProfileSheet.tsx b/src/components/common/BottomSheet/ProfileSheet.tsx new file mode 100644 index 00000000..54adefca --- /dev/null +++ b/src/components/common/BottomSheet/ProfileSheet.tsx @@ -0,0 +1,152 @@ +import styled from '@emotion/styled' +import { AnimatePresence, motion } from 'framer-motion' +import { MouseEvent, useState } from 'react' +import { AiOutlineClose } from 'react-icons/ai' + +import Avatar from '@/components/common/Avatar' +import { Text } from '@/components/common/Text' +import { palette } from '@/styles/palette' + +import { InterestButton } from '../Buttons/IconButton' + +const Background = styled(motion.div)` + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: flex-end; + overflow-y: hidden; +` + +const BottomContentWrapper = styled(motion.div)<{ + isDarkMode: boolean +}>` + width: 100%; + display: flex; + flex-direction: column; + height: 378px; + border-top-left-radius: 20px; + border-top-right-radius: 20px; + background-color: ${({ isDarkMode }) => (isDarkMode ? palette.GRAY700 : palette.WHITE)}; +` + +const BottomContentHeader = styled.div<{ + isDarkMode: boolean +}>` + width: 100%; + position: relative; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid ${({ isDarkMode }) => (isDarkMode ? palette.GRAY500 : palette.GRAY200)}; + background-color: ${({ isDarkMode }) => (isDarkMode ? palette.GRAY700 : palette.WHITE)}; + border-top-left-radius: 20px; + border-top-right-radius: 20px; + padding: 24px 0; +` + +const BottomContent = styled.div<{ + isDarkMode: boolean +}>` + display: flex; + flex-direction: column; + align-items: center; + border-top-left-radius: 20px; + border-top-right-radius: 20px; + background-color: ${({ isDarkMode }) => (isDarkMode ? palette.GRAY700 : palette.WHITE)}; +` + +type ProfileSheetProps = { + title: string + isDarkMode: boolean +} + +const ProfileSheet = ({ title, isDarkMode }: ProfileSheetProps) => { + const [isOpen, setIsOpen] = useState(true) // ProfileSheet의 상태 + + const handleWrapperClick = (e: MouseEvent) => { + e.stopPropagation() + } + + const toggleProfileSheet = () => { + setIsOpen(false) + } + + const slideUp = { + hidden: { y: '100%', opacity: 0 }, + visible: { y: '0%', opacity: 1, transition: { type: 'spring', damping: 15, stiffness: 100 } }, + exit: { y: '100%', opacity: 0, transition: { type: 'spring', damping: 15, stiffness: 100 } }, + } + + const backgroundFade = { + hidden: { opacity: 0 }, + visible: { opacity: 1 }, + exit: { opacity: 0 }, + } + + return ( + + {isOpen && ( + + + + + + {title} + + + + + + + + + )} + + ) +} + +export default ProfileSheet diff --git a/src/components/common/BottomSheet/RandomMatchingSheet.tsx b/src/components/common/BottomSheet/RandomMatchingSheet.tsx new file mode 100644 index 00000000..8b6a68be --- /dev/null +++ b/src/components/common/BottomSheet/RandomMatchingSheet.tsx @@ -0,0 +1,163 @@ +import styled from '@emotion/styled' +import { AnimatePresence, motion } from 'framer-motion' +import { MouseEvent, useState } from 'react' +import { AiOutlineClose } from 'react-icons/ai' + +import RandomMatchingJoinButton from '@/components/common/Buttons/IconButton/RandomMatchingJoinButton' +import { Text } from '@/components/common/Text' +import { palette } from '@/styles/palette' + +import Timer from './Timer' + +const Background = styled.div` + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: flex-end; + overflow-y: hidden; +` + +const BottomContentWrapper = styled(motion.div)<{ + isDarkMode: boolean +}>` + width: 100%; + display: flex; + flex-direction: column; + height: 378px; + border-top-left-radius: 20px; + border-top-right-radius: 20px; + background-color: ${({ isDarkMode }) => (isDarkMode ? palette.GRAY700 : palette.WHITE)}; +` + +const BottomContentHeader = styled.div<{ + isDarkMode: boolean +}>` + width: 100%; + position: relative; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid ${({ isDarkMode }) => (isDarkMode ? palette.GRAY500 : palette.GRAY200)}; + background-color: ${({ isDarkMode }) => (isDarkMode ? palette.GRAY700 : palette.WHITE)}; + border-top-left-radius: 20px; + border-top-right-radius: 20px; + padding: 24px 0; +` + +const BottomContent = styled.div<{ + isDarkMode: boolean +}>` + display: flex; + flex-direction: column; + align-items: center; + border-top-left-radius: 20px; + border-top-right-radius: 20px; + background-color: ${({ isDarkMode }) => (isDarkMode ? palette.GRAY700 : palette.WHITE)}; +` + +type RandomMatchingSheetProps = { + title: string + isDarkMode: boolean + moveToRandomMatching: () => void + cancelRandomMatching: () => void +} + +const RandomMatchingSheet = ({ + title, + isDarkMode, + moveToRandomMatching, + cancelRandomMatching, +}: RandomMatchingSheetProps) => { + const [isOpen, setIsOpen] = useState(true) // RandomMatchingSheet의 상태 + + const handleWrapperClick = (e: MouseEvent) => { + e.stopPropagation() + } + + const toggleRandomMatchingSheet = () => { + // isOpen이 true일 때만 상태를 토글 + if (isOpen) { + cancelRandomMatching() + setIsOpen(!isOpen) + } + } + + const slideUp = { + hidden: { y: '100%', opacity: 0 }, + visible: { y: '0%', opacity: 1, transition: { type: 'spring', damping: 15, stiffness: 100 } }, + partiallyVisible: { + y: '85%', + opacity: 1, + transition: { type: 'spring', damping: 15, stiffness: 100 }, + }, + exit: { y: '100%', opacity: 0, transition: { type: 'spring', damping: 20, stiffness: 100 } }, + } + return ( + + + + + + + {title} + + + + { + console.log('타이머 종료!') + }} + /> + + + {'현재 매칭에 참가하지 않으면 다음 매칭에 불이익이 있습니다.'} + + + + + + ) +} + +export default RandomMatchingSheet diff --git a/src/components/common/BottomSheet/Timer.tsx b/src/components/common/BottomSheet/Timer.tsx new file mode 100644 index 00000000..f5254005 --- /dev/null +++ b/src/components/common/BottomSheet/Timer.tsx @@ -0,0 +1,91 @@ +import { arc, select, timer } from 'd3' +import { useEffect, useRef } from 'react' + +import { palette } from '@/styles/palette' + +type TimerProps = { + totalTime: number + isDarkMode: boolean + timeOver: () => void +} + +const Timer = ({ totalTime, isDarkMode, timeOver }: TimerProps) => { + const svgRef = useRef(null) + const currentTimer = totalTime + + useEffect(() => { + if (svgRef.current && currentTimer) { + const fontColor = isDarkMode ? palette.DARK_WHITE : palette.BLACK + const svg = select(svgRef.current).attr('width', 141).attr('height', 141) + const group = svg.append('g').attr('transform', 'translate(70, 70)') + + const arcSvg = arc().innerRadius(64).outerRadius(70).startAngle(0) + + const path = group.append('path').attr('fill', palette.TERTIARY) + + const text = group + .append('text') + .attr('text-anchor', 'middle') + .attr('dy', '0.35em') + .attr('style', 'font-family: Pretendard') + .style('fill', fontColor) + .style('font-weight', '600') + .style('font-size', '32px') + + const update = (elapsed: number) => { + if (elapsed >= currentTimer) { + timerObj.stop() + path.attr('visibility', 'hidden') + text.text('00:00') + timeOver() + return + } + + const remainingTime = currentTimer - elapsed + const minutes = Math.floor(remainingTime / 60000) // milliseconds to minutes + const seconds = Math.floor((remainingTime % 60000) / 1000) // remainder to seconds + + // 시간 형식을 00:00 으로 변환 + const displayTime = `${minutes.toString().padStart(2, '0')}:${seconds + .toString() + .padStart(2, '0')}` + text.text(displayTime) + + const angle = (elapsed / totalTime) * 2 * Math.PI + arcSvg.startAngle(angle).endAngle(2 * Math.PI) + path.attr( + 'd', + arcSvg({ + startAngle: angle, + endAngle: 2 * Math.PI, + innerRadius: 0, + outerRadius: 100, + }), + ) + } + + const timerObj = timer(update) + + return () => { + timerObj.stop() + select(svgRef.current).selectAll('*').remove() // SVG 내부의 모든 요소 제거 + } + } + }, []) + + return ( +
+ +
+ ) +} + +export default Timer diff --git a/src/components/common/Buttons/IconButton/IconButtonStyles.ts b/src/components/common/Buttons/IconButton/IconButtonStyles.ts new file mode 100644 index 00000000..d2421919 --- /dev/null +++ b/src/components/common/Buttons/IconButton/IconButtonStyles.ts @@ -0,0 +1,104 @@ +import { palette } from '@/styles/palette' + +import { NormalButtonStyle } from '../NormalButton/NormalButtonStyles' + +export type IconButtonType = + | 'interest' + | 'interest-dark' + | 'particular-topic' + | 'particular-topic-dark' + | 'random-matching' + | 'random-matching-dark' + | 'random-matching-join' + | 'random-matching-join-dark' + +export const iconButtonStyles: Record = { + interest: { + width: 339, + height: 70, + fontColor: palette.WHITE, + font: 'Body_18', + fontWeight: 500, + letterSpacing: -2, + borderRadius: 20, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + backgroundColor: `linear-gradient(96deg, #7382F8 49.74%, #A6BCFC 93.87%);`, + }, + 'interest-dark': { + width: 339, + height: 70, + fontColor: palette.DARK_WHITE, + font: 'Body_18', + fontWeight: 500, + letterSpacing: -2, + borderRadius: 20, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + backgroundColor: `linear-gradient(89deg, ${palette.DARK_SECONDARY} 49.41%, ${palette.DARK_TERTIARY} 92.91%)`, + }, + 'particular-topic': { + width: 344, + height: 70, + fontColor: palette.GRAY600, + font: 'Body_18', + fontWeight: 500, + letterSpacing: -2, + borderRadius: 20, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + backgroundColor: palette.WHITE, + }, + 'particular-topic-dark': { + width: 344, + height: 70, + fontColor: palette.DARK_WHITE, + font: 'Body_18', + fontWeight: 500, + letterSpacing: -2, + borderRadius: 20, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + backgroundColor: palette.GRAY700, + }, + 'random-matching': { + width: 230, + height: 70, + fontColor: palette.WHITE, + font: 'Body_18', + fontWeight: 500, + letterSpacing: -2, + borderRadius: 20, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + backgroundColor: `linear-gradient(96deg, ${palette.SECONDARY} 49.74%, #A6BCFC 93.87%);`, + }, + 'random-matching-dark': { + width: 230, + height: 70, + fontColor: palette.DARK_WHITE, + font: 'Body_18', + fontWeight: 500, + letterSpacing: -2, + borderRadius: 20, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + backgroundColor: `linear-gradient(86deg, #494F80 8.54%, #5A77B3 94.19%);`, + }, + 'random-matching-join': { + width: 230, + height: 50, + fontColor: palette.WHITE, + font: 'Body_16', + fontWeight: 500, + letterSpacing: -2, + borderRadius: 10, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + backgroundColor: `linear-gradient(96deg, #7382F8 49.74%, #A6BCFC 93.87%);`, + }, + 'random-matching-join-dark': { + width: 230, + height: 50, + fontColor: palette.WHITE, + font: 'Body_16', + fontWeight: 500, + letterSpacing: -2, + borderRadius: 10, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + backgroundColor: `linear-gradient(86deg, #494F80 8.54%, #5A77B3 94.19%);`, + }, +} diff --git a/src/components/common/Buttons/IconButton/InterestButton.tsx b/src/components/common/Buttons/IconButton/InterestButton.tsx new file mode 100644 index 00000000..942e060e --- /dev/null +++ b/src/components/common/Buttons/IconButton/InterestButton.tsx @@ -0,0 +1,75 @@ +import { Fragment } from 'react' +import { RiStarFill } from 'react-icons/ri' + +import { Divider } from '@/components/common/Divider' +import { Text, TextWrapper } from '@/components/common/Text' +import { palette } from '@/styles/palette' + +import { StyleIconButtonWrapper, StyleIconWrapper } from '.' + +type InterestButtonProps = { + nickName: string + interests: string[] + isDarkMode: boolean +} + +const InterestButton = ({ nickName, interests, isDarkMode }: InterestButtonProps) => { + const setButtonType = isDarkMode ? 'interest-dark' : 'interest' + + return ( + + + + + + + {`${nickName}의 관심사`} + + + {interests.map((interest, index) => ( + + {interest} + {index !== interests.length - 1 && ( + + )} + + ))} + + + + ) +} + +export default InterestButton diff --git a/src/components/common/Buttons/IconButton/KakaoButton.tsx b/src/components/common/Buttons/IconButton/KakaoButton.tsx new file mode 100644 index 00000000..37b7776c --- /dev/null +++ b/src/components/common/Buttons/IconButton/KakaoButton.tsx @@ -0,0 +1,42 @@ +import styled from '@emotion/styled' + +import KakaoIcon from '@/assets/icons/KakaoIcon' +import { Text } from '@/components/common/Text' +import { palette } from '@/styles/palette' + +import { StyleIconWrapper } from '.' + +export const ButtonWrapper = styled.button<{ + buttonTheme: 'kakao' | 'naver' +}>` + width: 320px; + height: 60px; + background-color: ${(props) => (props.buttonTheme === 'naver' ? palette.GREEN : palette.YELLOW)}; + border-radius: 15px; + display: flex; + justify-content: space-between; + align-items: center; + box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.15); +` + +const KakaoButton = () => ( + + + + + + {'카카오톡으로 시작'} + + +) + +export default KakaoButton diff --git a/src/components/common/Buttons/IconButton/NaverButton.tsx b/src/components/common/Buttons/IconButton/NaverButton.tsx new file mode 100644 index 00000000..303574c5 --- /dev/null +++ b/src/components/common/Buttons/IconButton/NaverButton.tsx @@ -0,0 +1,34 @@ +import NaverIcon from '@/assets/icons/NaverIcon' +import { Text } from '@/components/common/Text' +import { palette } from '@/styles/palette' + +import { StyleIconWrapper } from '.' +import { ButtonWrapper } from './KakaoButton' + +const NaverButton = () => { + return ( + + + + + + {'네이버로 시작'} + + + ) +} + +export default NaverButton diff --git a/src/components/common/Buttons/IconButton/ParticularTopicButton.tsx b/src/components/common/Buttons/IconButton/ParticularTopicButton.tsx new file mode 100644 index 00000000..e268f1c2 --- /dev/null +++ b/src/components/common/Buttons/IconButton/ParticularTopicButton.tsx @@ -0,0 +1,84 @@ +import { BiChevronRight, BiSolidConversation } from 'react-icons/bi' + +import { Text, TextWrapper } from '@/components/common/Text' +import { palette } from '@/styles/palette' + +import { StyleIconButtonWrapper, StyleIconWrapper } from '.' + +type ParticularTopicButtonProps = { + isDarkMode: boolean +} + +const ParticularTopicButton = ({ isDarkMode }: ParticularTopicButtonProps) => { + const getButtonType = isDarkMode ? 'particular-topic-dark' : 'particular-topic' + const getIconColor = isDarkMode ? palette.DARK_WHITE : palette.GRAY600 + const getIconBackgroundColor = isDarkMode ? palette.DARK_ICON : palette.GRAY100 + const getSecondTextColor = isDarkMode ? palette.GRAY300 : palette.GRAY500 + + return ( + + + + + + + {'특정 주제로 대화하기'} + + + {'네트워크를 넓혀보세요!'} + + + + + + + ) +} + +export default ParticularTopicButton diff --git a/src/components/common/Buttons/IconButton/RandomMatchingButton.tsx b/src/components/common/Buttons/IconButton/RandomMatchingButton.tsx new file mode 100644 index 00000000..f705d881 --- /dev/null +++ b/src/components/common/Buttons/IconButton/RandomMatchingButton.tsx @@ -0,0 +1,83 @@ +import { BiChevronRight } from 'react-icons/bi' +import { PiTimerBold } from 'react-icons/pi' + +import { Text, TextWrapper } from '@/components/common/Text' +import { palette } from '@/styles/palette' +import { getTimeDelta } from '@/utils/getTimeStamp' + +import { StyleIconButtonWrapper, StyleIconWrapper } from '.' + +type RandomMatchingButtonProps = { + date: string + isDarkMode: boolean +} + +const RandomMatchingButton = ({ date, isDarkMode }: RandomMatchingButtonProps) => { + const setButtonType = isDarkMode ? 'random-matching-dark' : 'random-matching' + + return ( + + + + + + + {'랜덤매칭 시작하기'} + + + {'마지막 채팅: '} {`${getTimeDelta(date)}`} + + + + + + + ) +} + +export default RandomMatchingButton diff --git a/src/components/common/Buttons/IconButton/RandomMatchingJoin.tsx b/src/components/common/Buttons/IconButton/RandomMatchingJoin.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/components/common/Buttons/IconButton/RandomMatchingJoinButton.tsx b/src/components/common/Buttons/IconButton/RandomMatchingJoinButton.tsx new file mode 100644 index 00000000..12174a8b --- /dev/null +++ b/src/components/common/Buttons/IconButton/RandomMatchingJoinButton.tsx @@ -0,0 +1,61 @@ +import { BiChevronRight } from 'react-icons/bi' + +import { Text, TextWrapper } from '@/components/common/Text' + +import { StyleIconButtonWrapper, StyleIconWrapper } from '.' + +type RandomMatchingJoinButtonProps = { + isDarkMode: boolean + moveToRandomMatching: () => void +} + +const RandomMatchingJoinButton = ({ + isDarkMode, + moveToRandomMatching, +}: RandomMatchingJoinButtonProps) => { + const setButtonType = isDarkMode ? 'random-matching-join-dark' : 'random-matching-join' + + return ( + + + + {'매칭방에 접속해주세요!'} + + + + + + + ) +} + +export default RandomMatchingJoinButton diff --git a/src/components/common/Buttons/IconButton/index.tsx b/src/components/common/Buttons/IconButton/index.tsx new file mode 100644 index 00000000..95519bd2 --- /dev/null +++ b/src/components/common/Buttons/IconButton/index.tsx @@ -0,0 +1,46 @@ +import { css } from '@emotion/react' +import styled from '@emotion/styled' + +import { typo } from '@/styles/typo' + +import { iconButtonStyles, IconButtonType } from './IconButtonStyles' +import InterestButton from './InterestButton' +import KakaoButton from './KakaoButton' +import NaverButton from './NaverButton' +import ParticularTopicButton from './ParticularTopicButton' +import RandomMatchingButton from './RandomMatchingButton' + +export const StyleIconButtonWrapper = styled.button<{ + iconButtonType: IconButtonType +}>` + ${({ iconButtonType }) => { + const fontFunc = typo[iconButtonStyles[iconButtonType].font] + return css` + ${fontFunc( + iconButtonStyles[iconButtonType].fontWeight, + iconButtonStyles[iconButtonType].letterSpacing, + )} + width: ${iconButtonStyles[iconButtonType].width}px; + height: ${iconButtonStyles[iconButtonType].height}px; + color: ${iconButtonStyles[iconButtonType].fontColor}; + background: ${iconButtonStyles[iconButtonType].backgroundColor}; + box-shadow: ${iconButtonStyles[iconButtonType].boxShadow}; + border-radius: ${iconButtonStyles[iconButtonType].borderRadius}px; + ` + }} +` + +export const StyleIconWrapper = styled.div<{ + borderRadius?: string + backgroundColor?: string +}>` + width: 35px; + height: 35px; + border-radius: ${(props) => props.borderRadius}; + background-color: ${(props) => props.backgroundColor}; + display: flex; + justify-content: center; + align-items: center; +` + +export { InterestButton, KakaoButton, NaverButton, ParticularTopicButton, RandomMatchingButton } diff --git a/src/components/common/Buttons/NormalButton/NormalButton.tsx b/src/components/common/Buttons/NormalButton/NormalButton.tsx new file mode 100644 index 00000000..db596958 --- /dev/null +++ b/src/components/common/Buttons/NormalButton/NormalButton.tsx @@ -0,0 +1,36 @@ +import { css } from '@emotion/react' +import styled from '@emotion/styled' + +import { typo } from '@/styles/typo' + +import { NormalButtonStyles, NormalButtonType } from './NormalButtonStyles' + +const NormalButton = styled.button<{ + normalButtonType: NormalButtonType + isDarkMode?: boolean +}>` + ${({ normalButtonType, isDarkMode = false }) => { + const processedTypeKey = isDarkMode ? `${normalButtonType}-dark` : normalButtonType + const processedType = ( + NormalButtonStyles[processedTypeKey as NormalButtonType] ? processedTypeKey : normalButtonType + ) as NormalButtonType + + console.log(processedType) + + const fontFunc = typo[NormalButtonStyles[processedType].font] + return css` + ${fontFunc( + NormalButtonStyles[processedType].fontWeight, + NormalButtonStyles[processedType].letterSpacing, + )} + width: ${NormalButtonStyles[processedType].width}px; + height: ${NormalButtonStyles[processedType].height}px; + color: ${NormalButtonStyles[processedType].fontColor}; + background-color: ${NormalButtonStyles[processedType].backgroundColor}; + box-shadow: ${NormalButtonStyles[processedType].boxShadow}; + border-radius: ${NormalButtonStyles[processedType].borderRadius}px; + ` + }} +` + +export default NormalButton diff --git a/src/components/common/Buttons/NormalButton/NormalButtonStyles.ts b/src/components/common/Buttons/NormalButton/NormalButtonStyles.ts new file mode 100644 index 00000000..2f97c3b7 --- /dev/null +++ b/src/components/common/Buttons/NormalButton/NormalButtonStyles.ts @@ -0,0 +1,176 @@ +import { palette } from '@/styles/palette' +import { KeyOfTypo } from '@/styles/theme' + +export type NormalButtonStyle = { + width: number + height: number + fontColor: string + backgroundColor: string + font: KeyOfTypo + fontWeight: number + letterSpacing: number + boxShadow?: string + stroke?: string + borderRadius: number +} + +export type NormalButtonType = + | 'warning-accept' + | 'warning-deny' + | 'nickname-duplicate' + | 'nickname-duplicate-dark' + | 'email-certify' + | 'email-certify-dark' + | 'form-submit' + | 'admin-accept' + | 'admin-deny' + | 'modal-accept' + | 'modal-deny' + | 'matching' + | 'matching-dark' + +export const NormalButtonStyles: Record = { + 'warning-accept': { + width: 113, + height: 36, + fontColor: palette.WHITE, + backgroundColor: palette.RED, + font: 'Body_12', + fontWeight: 600, + letterSpacing: -1, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + borderRadius: 10, + }, + 'warning-deny': { + width: 113, + height: 36, + fontColor: palette.WHITE, + backgroundColor: palette.GRAY500, + font: 'Body_12', + fontWeight: 600, + letterSpacing: -1, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + borderRadius: 10, + }, + 'nickname-duplicate': { + width: 60, + height: 46, + fontColor: palette.BLACK, + backgroundColor: palette.WHITE, + font: 'Body_12', + fontWeight: 400, + letterSpacing: -0.5, + stroke: palette.GRAY200, + borderRadius: 10, + }, + 'nickname-duplicate-dark': { + width: 60, + height: 46, + fontColor: palette.DARK_WHITE, + backgroundColor: palette.GRAY600, + font: 'Body_12', + fontWeight: 400, + letterSpacing: -0.5, + stroke: palette.GRAY200, + borderRadius: 10, + }, + 'email-certify': { + width: 73, + height: 46, + fontColor: palette.BLACK, + backgroundColor: palette.WHITE, + font: 'Body_12', + fontWeight: 400, + letterSpacing: -0.5, + stroke: palette.GRAY200, + borderRadius: 10, + }, + 'email-certify-dark': { + width: 73, + height: 46, + fontColor: palette.WHITE, + backgroundColor: palette.GRAY700, + font: 'Body_12', + fontWeight: 400, + letterSpacing: -0.5, + stroke: palette.GRAY600, + borderRadius: 10, + }, + 'form-submit': { + width: 335, + height: 45, + fontColor: palette.WHITE, + backgroundColor: palette.PRIMARY, + font: 'Body_16', + fontWeight: 600, + letterSpacing: -1, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + borderRadius: 11, + }, + 'admin-accept': { + width: 110, + height: 47, + fontColor: palette.WHITE, + backgroundColor: palette.PRIMARY, + font: 'Body_16', + fontWeight: 600, + letterSpacing: -2, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + borderRadius: 50, + }, + 'admin-deny': { + width: 110, + height: 47, + fontColor: palette.GRAY400, + backgroundColor: palette.GRAY100, + font: 'Body_16', + fontWeight: 600, + letterSpacing: -2, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + borderRadius: 50, + }, + 'modal-accept': { + width: 85, + height: 40, + fontColor: palette.WHITE, + backgroundColor: palette.PRIMARY, + font: 'Body_14', + fontWeight: 600, + letterSpacing: -2, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + borderRadius: 50, + }, + 'modal-deny': { + width: 85, + height: 40, + fontColor: palette.GRAY400, + backgroundColor: palette.GRAY200, + font: 'Body_14', + fontWeight: 600, + letterSpacing: -2, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + borderRadius: 50, + }, + matching: { + width: 123, + height: 45, + fontColor: palette.WHITE, + backgroundColor: palette.TERTIARY, + font: 'Body_14', + fontWeight: 500, + letterSpacing: -1, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + borderRadius: 8, + }, + 'matching-dark': { + width: 123, + height: 45, + fontColor: palette.DARK_WHITE, + backgroundColor: palette.DARK_TERTIARY, + font: 'Body_14', + fontWeight: 500, + letterSpacing: -1, + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.15)', + borderRadius: 8, + }, +} diff --git a/src/components/common/CountNumber/index.tsx b/src/components/common/CountNumber/index.tsx new file mode 100644 index 00000000..018aaf35 --- /dev/null +++ b/src/components/common/CountNumber/index.tsx @@ -0,0 +1,32 @@ +import styled from '@emotion/styled' + +type CountNumberProps = { + currentLength: number + maxLength: number + color: string + right: number +} + +type StyleCountNumberProps = { + color: string + right: number +} + +const CountNumber = ({ right, currentLength, maxLength, color }: CountNumberProps): JSX.Element => { + return ( + {`${currentLength}/${maxLength}`} + ) +} + +const StyleCountNumber = styled.span` + position: relative; + right: ${(props) => props.right}px; + bottom: 3px; + font-size: 12px; + color: ${(props) => props.color}; +` + +export default CountNumber diff --git a/src/components/common/DarkSelectorButton/index.tsx b/src/components/common/DarkSelectorButton/index.tsx new file mode 100644 index 00000000..df56355e --- /dev/null +++ b/src/components/common/DarkSelectorButton/index.tsx @@ -0,0 +1,77 @@ +import styled from '@emotion/styled' +import { useState } from 'react' + +import { palette } from '@/styles/palette' + +type ToggleButtonProps = { + buttonName: string + selectedButtonColor: string + defaultButtonColor?: string + selectedTextColor: string + onClick?: () => void +} + +type StyledButtonProps = { + backgroundColor: string + textColor: string +} + +const DarkSelectorButton = ({ + buttonName, + selectedButtonColor, + defaultButtonColor = palette.WHITE, + selectedTextColor = palette.SECONDARY, + onClick, +}: ToggleButtonProps) => { + const [backgroundColor, setBackgroundColor] = useState(defaultButtonColor) + const [textColor, setTextColor] = useState(palette.SECONDARY) // 텍스트 색상에 대한 state + + const handleButtonClick = () => { + setBackgroundColor((prevColor) => { + if (prevColor === defaultButtonColor) { + setTextColor(selectedTextColor) + return selectedButtonColor + } else { + setTextColor(palette.SECONDARY) + return defaultButtonColor + } + }) + if (onClick) onClick() + } + + return ( + + {buttonName} + + ) +} + +const StyledButton = styled.button` + margin: 0 4px; + height: 36px; + padding: 10px 15px 10px 15px; + font-size: 12px; + cursor: pointer; + border: none; + border-radius: 10px; + background-color: ${(props) => props.backgroundColor}; + transition: background-color 0.3s; + &:hover { + opacity: 0.9; + } + &:focus { + outline: none; + } + color: ${(props) => props.textColor}; + display: inline-block; + vertical-align: middle; + line-height: 1; + font-weight: 600; + letter-spacing: -1px; +` + +export default DarkSelectorButton diff --git a/src/components/common/Divider/index.tsx b/src/components/common/Divider/index.tsx new file mode 100644 index 00000000..af4efe1d --- /dev/null +++ b/src/components/common/Divider/index.tsx @@ -0,0 +1,17 @@ +import styled from '@emotion/styled' + +import { palette } from '@/styles/palette' + +type DividerProps = { + width: number + height: number + margin?: string + isDarkMode: boolean +} + +export const Divider = styled.div` + width: ${({ width }) => width}px; + height: ${({ height }) => height}px; + margin: ${({ margin }) => margin}; + background-color: ${({ isDarkMode }) => (isDarkMode ? palette.GRAY500 : palette.GRAY100)}; +` diff --git a/src/components/common/Flexbox/index.tsx b/src/components/common/Flexbox/index.tsx new file mode 100644 index 00000000..daa3f2b1 --- /dev/null +++ b/src/components/common/Flexbox/index.tsx @@ -0,0 +1,52 @@ +import styled from '@emotion/styled' +import { HTMLAttributes, ReactNode } from 'react' + +export interface FlexBoxProps extends HTMLAttributes { + direction?: 'row' | 'column' + justify?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' + align?: 'flex-start' | 'flex-end' | 'center' | 'baseline' | 'stretch' + gap?: number + fullWidth?: boolean + children: ReactNode +} + +/** + * @param direction : direction / 기본 : row + * @param jusitfy : justify-content / 기본 : center + * @param align : align-items / 기본 : center + * @param gap : gap / 기본 : 0 + * @param fullWidth: : 너비 100% 채울지 / 기본 : false + * @param children : flexbox 내부 요소 + */ + +export const FlexBox = ({ + direction = 'row', + justify = 'center', + align = 'center', + gap = 0, + fullWidth = false, + children, + ...props +}: FlexBoxProps) => { + return ( + + {children} + + ) +} + +const StyledFlexBox = styled.div` + display: flex; + flex-direction: ${(props) => props.direction}; + justify-content: ${(props) => props.justify}; + align-items: ${(props) => props.align}; + gap: ${(props) => props.gap}px; + width: ${(props) => (props.fullWidth ? '100%' : 'auto')}; +` diff --git a/src/components/common/HeroImage/index.tsx b/src/components/common/HeroImage/index.tsx new file mode 100644 index 00000000..09c4f5a5 --- /dev/null +++ b/src/components/common/HeroImage/index.tsx @@ -0,0 +1,19 @@ +import styled from '@emotion/styled' + +import LoginImage from '../assets/LoginImage.svg' + +const HeroImage = () => { + return ( + <> + + + ) +} + +const StyleHeroImage = styled.img` + border-radius: 20px; + width: 306px; + height: 306px; +` + +export default HeroImage diff --git a/src/components/common/InputTimer/index.tsx b/src/components/common/InputTimer/index.tsx new file mode 100644 index 00000000..01dacc46 --- /dev/null +++ b/src/components/common/InputTimer/index.tsx @@ -0,0 +1,42 @@ +import styled from '@emotion/styled' +import { useEffect, useState } from 'react' + +import { palette } from '@/styles/palette' + +type TimerProps = { + duration: number // 초 단위의 지속 시간 + fontSize?: string +} + +const Timer = ({ duration, fontSize = '1rem' }: TimerProps): JSX.Element => { + const [timeLeft, setTimeLeft] = useState(duration) + + useEffect(() => { + if (!timeLeft) return + + const intervalId = setInterval(() => { + setTimeLeft((prevTimeLeft: number) => prevTimeLeft - 1) + }, 1000) + + return () => clearInterval(intervalId) + }, [timeLeft]) + + const formatTime = (time: number) => { + const minutes = Math.floor(time / 60) + const seconds = time % 60 + return `${minutes}:${seconds.toString().padStart(2, '0')}` + } + + return ( + + {formatTime(timeLeft)} + + ) +} + +const StyledTimer = styled.span` + font-size: ${(props) => props.fontSize}; + color: ${palette.RED}; +` + +export default Timer diff --git a/src/components/common/ListRow/AdminListRow.tsx b/src/components/common/ListRow/AdminListRow.tsx new file mode 100644 index 00000000..7976bf03 --- /dev/null +++ b/src/components/common/ListRow/AdminListRow.tsx @@ -0,0 +1,90 @@ +import { FlexBox } from '@/components/common/Flexbox' +import { StyleList } from '@/components/common/ListRow/ProfileListRow' +import { Text } from '@/components/common/Text' +import { palette } from '@/styles/palette' + +type ProfileListRowProps = { + height: number + nickname: string + infoMessage: string | number + isDarkMode: boolean +} +const AdminListRow = ({ height, nickname, infoMessage, isDarkMode }: ProfileListRowProps) => { + const renderInfoMessage = () => { + if (typeof infoMessage === 'number') { + return ( + + + {'누적 '} + + + {infoMessage} + + + {' 회'} + + + ) + } + return ( + + {infoMessage} + + ) + } + + return ( + + + {nickname} + + {renderInfoMessage()} + + ) +} + +export default AdminListRow diff --git a/src/components/common/ListRow/ProfileListRow.tsx b/src/components/common/ListRow/ProfileListRow.tsx new file mode 100644 index 00000000..d687e016 --- /dev/null +++ b/src/components/common/ListRow/ProfileListRow.tsx @@ -0,0 +1,94 @@ +import styled from '@emotion/styled' +import { ReactNode } from 'react' + +import { FlexBox } from '@/components/common/Flexbox' +import { Text } from '@/components/common/Text' +import { palette } from '@/styles/palette' + +export const StyleList = styled(FlexBox)<{ + width: number + height: number +}>` + width: ${({ width }) => width}px; + height: ${({ height }) => height}px; + display: flex; + justify-content: space-between; +` + +const StyleIconWrapper = styled.div<{ + width: number + height: number + borderRadius?: string + backgroundColor: string +}>` + width: ${({ width }) => width}px; + height: ${({ height }) => height}px; + display: flex; + justify-content: center; + align-items: center; + border-radius: ${({ borderRadius }) => borderRadius}; + background-color: ${({ backgroundColor }) => backgroundColor}; +` + +type ProfileListRowProps = { + firstIcon: ReactNode + title: string + additionalContent?: ReactNode | string + isDarkMode?: boolean +} +const ProfileListRow = ({ + firstIcon, + title, + additionalContent, + isDarkMode, +}: ProfileListRowProps) => { + const isAdditionalContentString = typeof additionalContent === 'string' + const additionalContentColor = isAdditionalContentString ? palette.GRAY300 : undefined + + return ( + + + {firstIcon} + + + {title} + + + {additionalContent} + + + ) +} + +export default ProfileListRow diff --git a/src/components/common/Loading/index.tsx b/src/components/common/Loading/index.tsx new file mode 100644 index 00000000..f2987d35 --- /dev/null +++ b/src/components/common/Loading/index.tsx @@ -0,0 +1,20 @@ +import styled from '@emotion/styled' +import { SyncLoader } from 'react-spinners' + +import { palette } from '@/styles/palette' +const Loading = () => { + return ( + + + + ) +} + +const LoadingWrapper = styled.div` + text-align: center; + vertical-align: middle; + position: absolute; + top: 50%; + left: 45%; +` +export default Loading diff --git a/src/components/common/Modal/index.tsx b/src/components/common/Modal/index.tsx new file mode 100644 index 00000000..75b43e9a --- /dev/null +++ b/src/components/common/Modal/index.tsx @@ -0,0 +1,124 @@ +import styled from '@emotion/styled' + +import ExclamationIcon from '@/assets/icons/Exclamation.svg' +import WarningIcon from '@/assets/icons/Warning.svg' +import NormalButton from '@/components/common/Buttons/NormalButton/NormalButton' +import useModalStore from '@/store/ModalStore' +import { palette } from '@/styles/palette' +import { typo } from '@/styles/typo' + +const Modal = () => { + const { modalState, setModalState, okFunc, mainText, subText, type } = useModalStore() + const OkAndClose = () => { + okFunc() + closeModal() + } + const closeModal = () => { + setModalState(false) + } + return ( + <> + {modalState ? ( + + + {type == 'confirm' ? ( + + ) : ( + + )} + + {mainText} + {subText} + {type === 'confirm' ? ( + + + {'확인'} + + + {'취소'} + + + ) : ( + + + {'예, 나가겠습니다.'} + + + {'아니오, 돌아가겠습니다.'} + + + )} + + + ) : ( + '' + )} + + ) +} + +const StyleModalWrapper = styled.div` + z-index: 999; + display: flex; + position: absolute; + justify-content: center; + align-items: center; + width: 100%; + background-color: rgba(0, 0, 0, 0.4); + border-radius: 10px; + top: 0; + left: 0; + right: 0; + bottom: 0; +` +const StyleModal = styled.div<{ type: string }>` + width: 344px; + height: ${({ type }) => (type == 'warn' ? '195.6px' : '246px')}; + z-index: 1; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: white; + border-radius: 10px; + box-shadow: 3px 3px 3px ${palette.GRAY400}; + text-align: center; +` + +const StyleButtonWrapper = styled.span` + justify-content: center; + margin: 10px; + display: flex; +` +const StyleMainText = styled.div<{ subTrue: boolean }>` + color: ${palette.BLACK}; + text-align: center; + font-size: ${typo.Body_20()}; + margin-top: ${({ subTrue }) => (subTrue ? '' : '10px')}; + margin-bottom: ${({ subTrue }) => (subTrue ? '20px' : '30px')}; +` +const StyleSubText = styled.span<{ type: string }>` + color: ${palette.GRAY500}; + text-align: center; + font-size: ${typo.Body_14()}; +` +const StyleIcon = styled.img` + margin: 22px; +` +export default Modal diff --git a/src/components/common/NavigationBar/index.tsx b/src/components/common/NavigationBar/index.tsx new file mode 100644 index 00000000..abfc5def --- /dev/null +++ b/src/components/common/NavigationBar/index.tsx @@ -0,0 +1,68 @@ +import styled from '@emotion/styled' +import { IoChatbox } from 'react-icons/io5' +import { MdHome } from 'react-icons/md' +import { useNavigate } from 'react-router-dom' + +import defaultProfileImage from '@/assets/images/defaultProfileImage.png' +import Avatar from '@/components/common/Avatar' +import { FlexBox } from '@/components/common/Flexbox' +import { palette } from '@/styles/palette' +import { typo } from '@/styles/typo' +const NavigationBar = () => { + const navigate = useNavigate() + const moveFromNavigationBar = (path: string) => { + navigate(`/${path}`) + } + return ( + + + moveFromNavigationBar('chatlist')}> + + + {'이전대화방'} + + + moveFromNavigationBar('')}> + + + {'홈'} + + + moveFromNavigationBar('profile/edit')}> + + + + + {'프로필'} + + + + + ) +} +const StyleWrapper = styled(FlexBox)` + position: absolute; + bottom: 0px; +` +const StyleNavigationText = styled.span` + color: ${palette.GRAY600}; + font-size: ${typo.Body_10()}; +` +const StyleNavigation = styled(FlexBox)` + width: 100%; + height: 71px; + background-color: white; + box-shadow: + 0px 0px 2px 0px rgba(0, 0, 0, 0.24), + 0px 4px 4px 0px rgba(0, 0, 0, 0.14); +` +const StyleNavigationItem = styled.button` + cursor: pointer; +` +const StyleProfileImageWrapper = styled.div` + width: 100%; + height: 100%; + object-fit: cover; +` + +export default NavigationBar diff --git a/src/components/common/Spacing/index.tsx b/src/components/common/Spacing/index.tsx new file mode 100644 index 00000000..75ac5d3a --- /dev/null +++ b/src/components/common/Spacing/index.tsx @@ -0,0 +1,18 @@ +/** @jsxImportSource @emotion/react */ +import { css } from '@emotion/react' + +import { KeyOfPalette, theme } from '@/styles/theme' + +const Spacing = ({ size, color }: { size: number; color?: KeyOfPalette }) => { + return ( +
+ ) +} + +export default Spacing diff --git a/src/components/common/Text/index.tsx b/src/components/common/Text/index.tsx new file mode 100644 index 00000000..42dacb80 --- /dev/null +++ b/src/components/common/Text/index.tsx @@ -0,0 +1,25 @@ +import { css } from '@emotion/react' +import styled from '@emotion/styled' + +import { KeyOfTypo } from '@/styles/theme' +import { typo } from '@/styles/typo' + +export const TextWrapper = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: flex-start; +` + +export const Text = styled.div<{ + font: KeyOfTypo + fontWeight: number + letterSpacing: number +}>` + ${({ font, fontWeight, letterSpacing }) => { + const fontFunc = typo[font] + return css` + ${fontFunc(fontWeight, letterSpacing)} + ` + }} +` diff --git a/src/components/common/WhiteSelectorButton/index.tsx b/src/components/common/WhiteSelectorButton/index.tsx new file mode 100644 index 00000000..4d02fd04 --- /dev/null +++ b/src/components/common/WhiteSelectorButton/index.tsx @@ -0,0 +1,63 @@ +import styled from '@emotion/styled' +import { useState } from 'react' + +import { palette } from '@/styles/palette' + +type ToggleButtonProps = { + buttonName: string + selectedButtonColor: string + defaultButtonColor?: string + onClick?: () => void +} + +type StyledButtonProps = { + backgroundColor: string +} + +const WhiteSelectorButton = ({ + buttonName, + selectedButtonColor, + defaultButtonColor = palette.TERTIARY, + onClick, +}: ToggleButtonProps) => { + const [backgroundColor, setBackgroundColor] = useState(defaultButtonColor) + + const handleButtonClick = () => { + setBackgroundColor((prevColor) => + prevColor === defaultButtonColor ? selectedButtonColor : defaultButtonColor, + ) + if (onClick) onClick() + } + + return ( + + {buttonName} + + ) +} + +const StyledButton = styled.button` + margin: 0 4px; + height: 36px; + padding: 10px 15px 10px 15px; + font-size: 12px; + cursor: pointer; + border: none; + border-radius: 10px; + background-color: ${(props) => props.backgroundColor}; + transition: background-color 0.3s; + &:hover { + opacity: 0.9; + } + &:focus { + outline: none; + } + color: ${palette.WHITE}; + display: inline-block; + vertical-align: middle; + line-height: 1; + letter-spacing: -1px; + font-weight: 600; +` + +export default WhiteSelectorButton diff --git a/src/components/layouts/Layout.tsx b/src/components/layouts/Layout.tsx index ecdc23be..e6e41eb6 100644 --- a/src/components/layouts/Layout.tsx +++ b/src/components/layouts/Layout.tsx @@ -1,12 +1,18 @@ +import 'react-toastify/dist/ReactToastify.css' + import styled from '@emotion/styled' import { Outlet } from 'react-router-dom' +import { ToastContainer } from 'react-toastify' +import Modal from '@/components/common/Modal' import { theme } from '@/styles/theme' const Layout = () => { return ( + + ) } diff --git a/src/hooks/useModal.tsx b/src/hooks/useModal.tsx new file mode 100644 index 00000000..de18310e --- /dev/null +++ b/src/hooks/useModal.tsx @@ -0,0 +1,22 @@ +import Modal from '@/components/common/Modal' +import useModalStore from '@/store/ModalStore' + +type ModalConfirmPropsType = { + type: 'warn' | 'confirm' + okFunc: () => void + mainText: string + subText?: string +} +export const useModal = () => { + const { setModalState, setOkFunc, setMainText, setSubText, setType } = useModalStore() + + const openModal = ({ mainText, subText, okFunc, type }: ModalConfirmPropsType) => { + setModalState(true) + setType(type) + setMainText(mainText) + setSubText(subText) + setOkFunc(okFunc) + } + + return { openModal, Modal } +} diff --git a/src/hooks/useToast.tsx b/src/hooks/useToast.tsx new file mode 100644 index 00000000..cf7581cb --- /dev/null +++ b/src/hooks/useToast.tsx @@ -0,0 +1,25 @@ +import { ReactNode } from 'react' +import { toast } from 'react-toastify' + +type ToastType = 'success' | 'error' | 'info' | 'warning' + +type ToastProps = { + message: string | ReactNode + type: ToastType + isDarkMode: boolean +} + +export const useToast = () => { + const showToast = ({ message, type, isDarkMode }: ToastProps) => { + toast(message, { + position: 'top-center', + draggable: true, + theme: isDarkMode ? 'dark' : 'light', + type, + }) + } + + return { showToast } +} + +export default useToast diff --git a/src/main.tsx b/src/main.tsx index 5ad74cea..b6f72219 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -5,11 +5,17 @@ import ReactDOM from 'react-dom/client' import { BrowserRouter } from 'react-router-dom' import { queryClient } from '@/apis/queryClient' + +import { worker } from '@/mocks/worker' import { globalStyle } from '@/styles/index.tsx' import { theme } from '@/styles/index.tsx' import App from './App.tsx' +if (process.env.NODE_ENV === 'development') { + worker.start() +} + ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts new file mode 100644 index 00000000..027f0d17 --- /dev/null +++ b/src/mocks/handlers.ts @@ -0,0 +1,8 @@ +import { http, HttpResponse } from 'msw' + +export const handlers = [ + // example + http.get('/pets', () => { + return HttpResponse.json(['Tom', 'Jerry', 'Spike']) + }), +] diff --git a/src/mocks/worker.ts b/src/mocks/worker.ts new file mode 100644 index 00000000..d3824e65 --- /dev/null +++ b/src/mocks/worker.ts @@ -0,0 +1,5 @@ +import { setupWorker } from 'msw/browser' + +import { handlers } from './handlers' + +export const worker = setupWorker(...handlers) diff --git a/src/store/ModalStore.tsx b/src/store/ModalStore.tsx new file mode 100644 index 00000000..c87e8751 --- /dev/null +++ b/src/store/ModalStore.tsx @@ -0,0 +1,28 @@ +import { create } from 'zustand' + +type ModalState = { + modalState: boolean + type: 'confirm' | 'warn' + okFunc: () => void + mainText: string + subText?: string | undefined + setType: (type: 'confirm' | 'warn') => void + setSubText: (text: string | undefined) => void + setModalState: (state: boolean) => void + setMainText: (text: string) => void + setOkFunc: (func: () => void) => void +} + +const useModalStore = create((set) => ({ + modalState: false, + okFunc: () => {}, + mainText: '', + subText: '', + type: 'confirm', + setType: (type) => set({ type: type }), + setSubText: (text) => set({ subText: text }), + setModalState: (state) => set({ modalState: state }), + setMainText: (text) => set({ mainText: text }), + setOkFunc: (func) => set({ okFunc: func }), +})) +export default useModalStore diff --git a/src/styles/global.ts b/src/styles/global.ts index cafaa3e1..2230a98c 100644 --- a/src/styles/global.ts +++ b/src/styles/global.ts @@ -6,19 +6,12 @@ export const globalStyle = css` ${emotionReset} @font-face { - font-family: 'InkLipquid'; - src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_one@1.0/InkLipquid.woff') - format('woff'); - font-weight: normal; - font-style: normal; - } - - @font-face { - font-family: 'Pretendard'; + font-family: 'Pretendard-Regular'; src: url('https://cdn.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff') format('woff'); font-weight: 400; font-style: normal; + font-display: swap; } body { diff --git a/src/styles/palette.ts b/src/styles/palette.ts index 774ef581..e19c97dc 100644 --- a/src/styles/palette.ts +++ b/src/styles/palette.ts @@ -1,11 +1,11 @@ export const palette = { PRIMARY: '#5567F1', SECONDARY: '#7382F8', - TERTIORY: '#90AEF6', + TERTIARY: '#90AEF6', GRADIENT: '#ADD2F8', DARK_PRIMARY: '#1D2026', DARK_SECONDARY: '#494F80', - DARK_TERTIORY: '#5A76B2', + DARK_TERTIARY: '#5A76B2', BLACK: '#000000', WHITE: '#FFFFFF', DARK_WHITE: '#FDFDFD', diff --git a/src/styles/typo.ts b/src/styles/typo.ts index 24c019f7..51eed14d 100644 --- a/src/styles/typo.ts +++ b/src/styles/typo.ts @@ -2,44 +2,52 @@ import { css } from '@emotion/react' export const calcRem = (px: number) => `${px / 16}rem` export const typo = { - Body_20: css` + Body_20: (fontWeight: number = 500, letterSpacing?: number) => css` font-family: 'Pretendard'; font-size: ${calcRem(20)}; - font-weight: 500; + font-weight: ${fontWeight}; + letter-spacing: ${letterSpacing}px; `, - Body_18: css` + Body_18: (fontWeight: number = 500, letterSpacing?: number) => css` font-family: 'Pretendard'; font-size: ${calcRem(18)}; - font-weight: 500; + font-weight: ${fontWeight}; + letter-spacing: ${letterSpacing}px; `, - Body_16: css` + Body_16: (fontWeight: number = 400, letterSpacing?: number) => css` font-family: 'Pretendard'; font-size: ${calcRem(16)}; - font-weight: 400; + font-weight: ${fontWeight}; + letter-spacing: ${letterSpacing}px; `, - Body_14: css` + Body_14: (fontWeight: number = 400, letterSpacing?: number) => css` font-family: 'Pretendard'; - font-size: ${calcRem(13)}; - font-weight: 400; + font-size: ${calcRem(14)}; + font-weight: ${fontWeight}; + letter-spacing: ${letterSpacing}px; `, - Body_12: css` + Body_12: (fontWeight: number = 400, letterSpacing?: number) => css` font-family: 'Pretendard'; font-size: ${calcRem(12)}; - font-weight: 400; + font-weight: ${fontWeight}; + letter-spacing: ${letterSpacing}px; `, - Body_10: css` + Body_10: (fontWeight: number = 400, letterSpacing?: number) => css` font-family: 'Pretendard'; font-size: ${calcRem(10)}; - font-weight: 400; + font-weight: ${fontWeight}; + letter-spacing: ${letterSpacing}px; `, - Caption_11: css` + Caption_11: (fontWeight: number = 400, letterSpacing?: number) => css` font-family: 'Pretendard'; font-size: ${calcRem(11)}; - font-weight: 400; + font-weight: ${fontWeight}; + letter-spacing: ${letterSpacing}px; `, - Caption_9: css` + Caption_9: (fontWeight: number = 500, letterSpacing?: number) => css` font-family: 'Pretendard'; font-size: ${calcRem(9)}; - font-weight: 500; + font-weight: ${fontWeight}; + letter-spacing: ${letterSpacing}px; `, } as const diff --git a/src/utils/getTimeStamp.ts b/src/utils/getTimeStamp.ts new file mode 100644 index 00000000..d1ccd7aa --- /dev/null +++ b/src/utils/getTimeStamp.ts @@ -0,0 +1,40 @@ +export const getTimeDelta = (postedDate: string) => { + const dt = new Date(postedDate) + const now = new Date() + const diff = now.getTime() - dt.getTime() + + if (isNaN(diff)) { + return '알 수 없음' + } + + const seconds = Math.floor(diff / 1000) + const minutes = Math.floor(seconds / 60) + const hours = Math.floor(minutes / 60) + const days = Math.floor(hours / 24) + const months = Math.floor(days / 30) + const years = Math.floor(months / 12) + + let result = '' + + switch (true) { + case seconds < 60: + result = `${seconds}초 전` + break + case minutes < 60: + result = `${minutes}분 전` + break + case hours < 24: + result = `${hours}시간 전` + break + case days < 30: + result = `${days}일 전` + break + case months < 12: + result = `${months}달 전` + break + default: + result = `${years}년 전` + } + + return result +} diff --git a/tsconfig.json b/tsconfig.json index 27f4d626..027d4a68 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,7 +29,9 @@ "@/apis/*": ["src/apis/*"], "@/hooks/*": ["src/hooks/*"], "@/assets/*": ["src/assets/*"], - "@/styles/*": ["src/styles/*"] + "@/styles/*": ["src/styles/*"], + "@/mocks/*": ["src/mocks/*"], + "@/store/*": ["src/store/*"] } }, "include": ["src"],