From 92ec1490af74a351cd107f3d0bb43909f2b1d42b Mon Sep 17 00:00:00 2001 From: kimkyuhong Date: Mon, 21 Oct 2024 22:23:29 +0900 Subject: [PATCH 01/11] =?UTF-8?q?docs:=20svg=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/asset/svg/ic_tooltip_arrow.svg | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/common/asset/svg/ic_tooltip_arrow.svg diff --git a/src/common/asset/svg/ic_tooltip_arrow.svg b/src/common/asset/svg/ic_tooltip_arrow.svg new file mode 100644 index 00000000..0aee3559 --- /dev/null +++ b/src/common/asset/svg/ic_tooltip_arrow.svg @@ -0,0 +1,3 @@ + + + From 8605c2e3d4624039e9c2550e16da82ff2d0bf4b9 Mon Sep 17 00:00:00 2001 From: kimkyuhong Date: Mon, 21 Oct 2024 22:59:17 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20ToolTip=20=EA=B3=B5=ED=86=B5=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/component/ToolTip/ToolTip.tsx | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/common/component/ToolTip/ToolTip.tsx diff --git a/src/common/component/ToolTip/ToolTip.tsx b/src/common/component/ToolTip/ToolTip.tsx new file mode 100644 index 00000000..1bdc813d --- /dev/null +++ b/src/common/component/ToolTip/ToolTip.tsx @@ -0,0 +1,30 @@ +import { HTMLAttributes } from 'react'; + +import Arrow from '@/common/asset/svg/ic_tooltip_arrow.svg?react'; +import { + arrowPositionStyle, + arrowStyle, + containerStyle, + messageStyle, + positionStyle, +} from '@/common/component/ToolTip/ToolTip.style'; + +export interface ToolTipProps extends HTMLAttributes { + position?: 'top' | 'right' | 'bottom' | 'left'; + message: string; + margin?: number; +} + +const ToolTip = ({ position = 'right', message, margin = 0, children }: ToolTipProps) => { + return ( +
+ {children} + + + {message} + +
+ ); +}; + +export default ToolTip; From 11e126f8e9aca37deb84775a42dbb556c0c2977e Mon Sep 17 00:00:00 2001 From: kimkyuhong Date: Mon, 21 Oct 2024 22:59:38 +0900 Subject: [PATCH 03/11] =?UTF-8?q?style:=20ToolTip=20style=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/component/ToolTip/ToolTip.style.ts | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/common/component/ToolTip/ToolTip.style.ts diff --git a/src/common/component/ToolTip/ToolTip.style.ts b/src/common/component/ToolTip/ToolTip.style.ts new file mode 100644 index 00000000..9a6034f8 --- /dev/null +++ b/src/common/component/ToolTip/ToolTip.style.ts @@ -0,0 +1,84 @@ +import { css } from '@emotion/react'; + +import { ToolTipProps } from '@/common/component/ToolTip/ToolTip'; +import { theme } from '@/common/style/theme/theme'; + +export const containerStyle = css({ + position: 'relative', + border: '1px solid', + '&:hover': { + '& > span': { + display: 'block', + }, + }, +}); + +export const messageStyle = css({ + display: 'none', + position: 'absolute', + + padding: '1rem', + borderRadius: '8px', + + backgroundColor: `${theme.colors.gray_900}`, + font: `${theme.text.body08}`, + color: `${theme.colors.white}`, +}); + +export const positionStyle = (position: Required['position'], margin: number) => { + const style = { + top: css({ + left: '50%', + bottom: '100%', + transform: `translateX(-50%) translateY(calc(-${margin}rem - 8px) )`, + }), + bottom: css({ + left: '50%', + up: '100%', + transform: `translateX(-50%) translateY(calc(${margin}rem + 8px))`, + }), + left: css({ + top: '50%', + right: '100%', + transform: `translateY(-50%) translateX(calc(-${margin}rem - 8px))`, + }), + right: css({ + top: '50%', + left: '100%', + transform: `translateY(-50%) translateX(calc(${margin}rem + 8px))`, + }), + }; + + return style[position]; +}; + +export const arrowStyle = css({ + position: 'absolute', +}); + +export const arrowPositionStyle = (position: Required['position']) => { + const style = { + top: css({ + left: '50%', + top: '99%', + transform: `translateX(-50%) rotate(270deg)`, + }), + bottom: css({ + left: '50%', + bottom: '98%', + transform: `translateX(-50%) rotate(90deg)`, + }), + left: css({ + top: '50%', + left: '98%', + transform: `translateY(-50%) rotate(180deg)`, + }), + right: css({ + top: '50%', + right: '98%', + transform: `translateY(-50%) `, + }), + }; + + return style[position]; +}; From c280cc18433d5746c9bbdeaea5154873550baa07 Mon Sep 17 00:00:00 2001 From: kimkyuhong Date: Mon, 21 Oct 2024 23:00:07 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20storybook=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/story/common/ToolTip.stories.tsx | 47 ++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/story/common/ToolTip.stories.tsx diff --git a/src/story/common/ToolTip.stories.tsx b/src/story/common/ToolTip.stories.tsx new file mode 100644 index 00000000..237c3241 --- /dev/null +++ b/src/story/common/ToolTip.stories.tsx @@ -0,0 +1,47 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import Flex from '@/common/component/Flex/Flex'; +import ToolTip from '@/common/component/ToolTip/ToolTip'; +import { theme } from '@/common/style/theme/theme'; + +const meta = { + title: 'Common/ToolTip', + component: ToolTip, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + position: { + control: { type: 'radio' }, + options: ['top', 'bottom', 'left', 'right'], + }, + message: { + control: { type: 'text' }, + }, + }, + args: { + position: 'top', + message: 'ToolTip', + margin: 0.8, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const DefaultToolTip: Story = { + args: { + children: ( + + 호버 + + ), + }, +}; From d3358a8a1728c512af79955d6bb25f2af600386e Mon Sep 17 00:00:00 2001 From: kimkyuhong Date: Wed, 23 Oct 2024 15:50:19 +0900 Subject: [PATCH 05/11] =?UTF-8?q?chore:=20=EC=82=AC=EA=B3=A0=20=EC=88=98?= =?UTF-8?q?=EC=8A=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ic_check.svg | 3 - package.json | 11 +- pnpm-lock.yaml | 111 ++++++++++++----- src/App.tsx | 30 +++-- src/common/asset/img/tooltip.png | Bin 0 -> 555 bytes src/common/asset/svg/ic_add_team.svg | 3 + src/common/asset/svg/ic_alert_no.svg | 10 ++ src/common/asset/svg/ic_alert_yes.svg | 11 ++ .../asset/svg/ic_calendar_arrow_left.svg | 4 + .../asset/svg/ic_calendar_arrow_right.svg | 4 + src/common/asset/svg/ic_file.svg | 3 + src/common/asset/svg/ic_folder.svg | 2 +- src/common/asset/svg/ic_folder_large.svg | 3 + src/common/asset/svg/ic_handover_fill.svg | 3 + src/common/asset/svg/ic_image_file.svg | 3 + src/common/asset/svg/ic_pdf_file.svg | 7 ++ src/common/asset/svg/ic_pencil.svg | 3 + src/common/asset/svg/ic_setting_gray.svg | 3 + src/common/asset/svg/ic_three_dots.svg | 5 + src/common/asset/svg/ic_timeline.svg | 6 + src/common/asset/svg/ic_tooltip.svg | 11 ++ src/common/asset/svg/ic_tooltip_arrow(3).svg | 3 + src/common/asset/svg/ic_trash.svg | 4 + src/common/asset/svg/ic_word_file.svg | 8 ++ src/common/component/Button/Button.style.ts | 35 ++++-- src/common/component/Button/Button.tsx | 4 +- .../component/CheckBox/CheckBox.style.ts | 34 ++++++ src/common/component/CheckBox/CheckBox.tsx | 23 ++++ .../component/CommandButton/CommandButton.tsx | 3 +- .../DatePicker/Calendar/Calendar.style.ts | 99 ++++++++++++--- .../DatePicker/Calendar/Calendar.tsx | 29 ----- .../Calendar/DatePickerCalendar.tsx | 32 +++-- .../Calendar/Dates/CalendarDates.tsx | 61 +++++----- .../Calendar/Dates/util/dateStyle.ts | 64 ++++++++++ .../DatePicker/Calendar/Days/CalendarDays.tsx | 4 +- .../Calendar/Header/CalendarHeader.tsx | 19 ++- .../DatePickerContainer.tsx | 11 -- .../Trigger/DatePickerTrigger.style.ts | 7 ++ .../DatePicker/Trigger/DatePickerTrigger.tsx | 43 +++++-- ...ickerContainer.style.ts => index.style.ts} | 2 - src/common/component/DatePicker/index.tsx | 47 ++++++- .../component/Menu/MenuItem/MenuItem.style.ts | 5 +- .../component/Menu/MenuItem/MenuItem.tsx | 2 +- .../component/Menu/MenuList/MenuList.style.ts | 1 - src/common/component/Text/Text.style.ts | 8 ++ src/common/component/Text/Text.tsx | 2 +- src/common/component/ToolTip/ToolTip.style.ts | 24 ++-- src/common/component/ToolTip/ToolTip.tsx | 3 +- src/common/hook/useDatePicker.ts | 38 ++++++ src/common/router/Router.tsx | 102 ++++++++++++---- src/common/router/lazy.ts | 12 ++ src/common/style/theme/theme.ts | 14 ++- .../archiving/index/ArchivingPage.style.ts | 9 +- .../component/DaySection/DaySection.style.ts | 2 +- .../DocumentBar/DocumentBar.style.ts | 14 +-- .../component/DocumentBar/DocumentBar.tsx | 25 +--- src/page/deleted/.gitkeep | 0 src/page/drive/.gitkeep | 0 src/page/handover/.gitkeep | 0 src/page/showcase/index/ShowcasePage.style.ts | 3 - .../component/ContentBox/ContentBox.style.ts | 37 ++++++ .../component/ContentBox/ContentBox.tsx | 51 ++++++++ src/shared/component/FileGrid/FileGrid.tsx | 81 ++++++++++++ src/shared/component/FileGrid/FolderGrid.tsx | 57 +++++++++ src/shared/component/FileGrid/icon.tsx | 20 +++ src/shared/component/FileGrid/index.style.ts | 35 ++++++ src/shared/component/Header/Header.style.ts | 16 +++ src/shared/component/Header/Header.tsx | 24 ++++ .../component/SideNavBar/LeftSidebar.tsx | 16 ++- .../LeftSidebarItem/LeftSidebarMenuItem.tsx | 2 +- src/shared/type/content.ts | 1 + src/shared/util/file.ts | 17 +++ src/shared/util/file.tsx | 4 - src/story/common/Button.stories.tsx | 2 +- src/story/common/CheckBox.stories.tsx | 28 +++++ src/story/common/CommandButton.stories.tsx | 4 +- src/story/common/DatePicker.stories.tsx | 25 +--- src/story/shared/ContentBox.stories.tsx | 115 ++++++++++++++++++ src/story/shared/FileGrid.stories.tsx | 47 +++++++ src/story/shared/FolderGrid.stories.tsx | 27 ++++ src/story/shared/Header.stories.tsx | 23 ++++ vite.config.ts | 16 ++- 82 files changed, 1380 insertions(+), 300 deletions(-) delete mode 100644 ic_check.svg create mode 100644 src/common/asset/img/tooltip.png create mode 100644 src/common/asset/svg/ic_add_team.svg create mode 100644 src/common/asset/svg/ic_alert_no.svg create mode 100644 src/common/asset/svg/ic_alert_yes.svg create mode 100644 src/common/asset/svg/ic_calendar_arrow_left.svg create mode 100644 src/common/asset/svg/ic_calendar_arrow_right.svg create mode 100644 src/common/asset/svg/ic_file.svg create mode 100644 src/common/asset/svg/ic_folder_large.svg create mode 100644 src/common/asset/svg/ic_handover_fill.svg create mode 100644 src/common/asset/svg/ic_image_file.svg create mode 100644 src/common/asset/svg/ic_pdf_file.svg create mode 100644 src/common/asset/svg/ic_pencil.svg create mode 100644 src/common/asset/svg/ic_setting_gray.svg create mode 100644 src/common/asset/svg/ic_three_dots.svg create mode 100644 src/common/asset/svg/ic_timeline.svg create mode 100644 src/common/asset/svg/ic_tooltip.svg create mode 100644 src/common/asset/svg/ic_tooltip_arrow(3).svg create mode 100644 src/common/asset/svg/ic_trash.svg create mode 100644 src/common/asset/svg/ic_word_file.svg create mode 100644 src/common/component/CheckBox/CheckBox.style.ts create mode 100644 src/common/component/CheckBox/CheckBox.tsx delete mode 100644 src/common/component/DatePicker/Calendar/Calendar.tsx create mode 100644 src/common/component/DatePicker/Calendar/Dates/util/dateStyle.ts delete mode 100644 src/common/component/DatePicker/DatePickerContainer/DatePickerContainer.tsx create mode 100644 src/common/component/DatePicker/Trigger/DatePickerTrigger.style.ts rename src/common/component/DatePicker/{DatePickerContainer/DatePickerContainer.style.ts => index.style.ts} (89%) create mode 100644 src/common/hook/useDatePicker.ts create mode 100644 src/common/router/lazy.ts create mode 100644 src/page/deleted/.gitkeep create mode 100644 src/page/drive/.gitkeep create mode 100644 src/page/handover/.gitkeep create mode 100644 src/shared/component/ContentBox/ContentBox.style.ts create mode 100644 src/shared/component/ContentBox/ContentBox.tsx create mode 100644 src/shared/component/FileGrid/FileGrid.tsx create mode 100644 src/shared/component/FileGrid/FolderGrid.tsx create mode 100644 src/shared/component/FileGrid/icon.tsx create mode 100644 src/shared/component/FileGrid/index.style.ts create mode 100644 src/shared/component/Header/Header.style.ts create mode 100644 src/shared/component/Header/Header.tsx create mode 100644 src/shared/type/content.ts create mode 100644 src/shared/util/file.ts delete mode 100644 src/shared/util/file.tsx create mode 100644 src/story/common/CheckBox.stories.tsx create mode 100644 src/story/shared/ContentBox.stories.tsx create mode 100644 src/story/shared/FileGrid.stories.tsx create mode 100644 src/story/shared/FolderGrid.stories.tsx create mode 100644 src/story/shared/Header.stories.tsx diff --git a/ic_check.svg b/ic_check.svg deleted file mode 100644 index 38ef4d5e..00000000 --- a/ic_check.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/package.json b/package.json index d09ef7aa..c47c358b 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,6 @@ "build-storybook": "storybook build", "chromatic": "npx chromatic --project-token=chpt_f4088febbfb82b7", "typeCheck": "tsc --noEmit", - "bundler": "npx vite-bundle-visualizer", "check": "concurrently \"pnpm lint\" \"pnpm typeCheck\"" }, "dependencies": { @@ -24,8 +23,9 @@ "mime": "^4.0.4", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-error-boundary": "^4.0.13", - "react-router-dom": "^6.24.1" + "react-hook-form": "^7.53.1", + "react-router-dom": "^6.24.1", + "zustand": "^5.0.0" }, "devDependencies": { "@chromatic-com/storybook": "^1.6.1", @@ -67,14 +67,13 @@ "lottie-react": "^2.4.0", "msw": "^2.3.1", "prettier": "^3.3.2", - "react-hook-form": "^7.52.1", + "rollup-plugin-visualizer": "^5.12.0", "storybook": "^8.2.6", "typescript": "^5.2.2", "typescript-eslint": "^7.14.1", "vite": "^5.3.2", "vite-plugin-svgr": "^4.2.0", - "vite-tsconfig-paths": "^4.3.2", - "zustand": "^4.5.4" + "vite-tsconfig-paths": "^4.3.2" }, "pnpm": { "patchedDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a48e7a1f..c2e00458 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,12 +37,15 @@ importers: react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) - react-error-boundary: - specifier: ^4.0.13 - version: 4.0.13(react@18.3.1) + react-hook-form: + specifier: ^7.53.1 + version: 7.53.1(react@18.3.1) react-router-dom: specifier: ^6.24.1 version: 6.24.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + zustand: + specifier: ^5.0.0 + version: 5.0.0(@types/react@18.3.3)(react@18.3.1)(use-sync-external-store@1.2.0(react@18.3.1)) devDependencies: '@chromatic-com/storybook': specifier: ^1.6.1 @@ -161,9 +164,9 @@ importers: prettier: specifier: ^3.3.2 version: 3.3.2 - react-hook-form: - specifier: ^7.52.1 - version: 7.52.1(react@18.3.1) + rollup-plugin-visualizer: + specifier: ^5.12.0 + version: 5.12.0(rollup@4.18.0) storybook: specifier: ^8.2.6 version: 8.2.6(@babel/preset-env@7.24.7(@babel/core@7.24.7)) @@ -182,9 +185,6 @@ importers: vite-tsconfig-paths: specifier: ^4.3.2 version: 4.3.2(typescript@5.5.2)(vite@5.3.2(@types/node@20.14.9)) - zustand: - specifier: ^4.5.4 - version: 4.5.4(@types/react@18.3.3)(react@18.3.1) packages: @@ -2428,6 +2428,10 @@ packages: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -3111,6 +3115,11 @@ packages: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -3212,6 +3221,10 @@ packages: resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} engines: {node: '>= 0.4'} + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} @@ -3620,6 +3633,10 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -3846,14 +3863,9 @@ packages: react: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0 react-dom: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0 - react-error-boundary@4.0.13: - resolution: {integrity: sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==} - peerDependencies: - react: '>=16.13.1' - - react-hook-form@7.52.1: - resolution: {integrity: sha512-uNKIhaoICJ5KQALYZ4TOaOLElyM+xipord+Ha3crEFhTntdLvWZqVY49Wqd/0GiVCA/f9NjemLeiNPjG7Hpurg==} - engines: {node: '>=12.22.0'} + react-hook-form@7.53.1: + resolution: {integrity: sha512-6aiQeBda4zjcuaugWvim9WsGqisoUk+etmFEsSUMm451/Ic8L/UAb7sRtMj3V+Hdzm6mMjU1VhiSzYUZeBm0Vg==} + engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 @@ -3982,6 +3994,16 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + rollup-plugin-visualizer@5.12.0: + resolution: {integrity: sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ==} + engines: {node: '>=14'} + hasBin: true + peerDependencies: + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rollup: + optional: true + rollup@4.18.0: resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -4097,6 +4119,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -4587,13 +4613,14 @@ packages: resolution: {integrity: sha512-c6T13b6qYcJZvck7QbEFXrFX/Mu2KOjvAGiKHmYMUg96jxNpfP6i+psGW72BOPxOIDUJrORG+Kyu7quMX9CQBQ==} engines: {node: '>=18'} - zustand@4.5.4: - resolution: {integrity: sha512-/BPMyLKJPtFEvVL0E9E9BTUM63MNyhPGlvxk1XjrfWTUlV+BR8jufjsovHzrtR6YNcBEcL7cMHovL1n9xHawEg==} - engines: {node: '>=12.7.0'} + zustand@5.0.0: + resolution: {integrity: sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ==} + engines: {node: '>=12.20.0'} peerDependencies: - '@types/react': '>=16.8' + '@types/react': '>=18.0.0' immer: '>=9.0.6' - react: '>=16.8' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' peerDependenciesMeta: '@types/react': optional: true @@ -4601,6 +4628,8 @@ packages: optional: true react: optional: true + use-sync-external-store: + optional: true snapshots: @@ -7255,6 +7284,8 @@ snapshots: es-errors: 1.3.0 gopd: 1.0.1 + define-lazy-prop@2.0.0: {} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 @@ -8135,6 +8166,8 @@ snapshots: dependencies: has-tostringtag: 1.0.2 + is-docker@2.2.1: {} + is-extglob@2.1.1: {} is-finalizationregistry@1.0.2: @@ -8213,6 +8246,10 @@ snapshots: call-bind: 1.0.7 get-intrinsic: 1.2.4 + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + isarray@2.0.5: {} isexe@2.0.0: {} @@ -8607,6 +8644,12 @@ snapshots: dependencies: mimic-fn: 4.0.0 + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -8830,12 +8873,7 @@ snapshots: react-dom: 18.3.1(react@18.3.1) react-is: 18.1.0 - react-error-boundary@4.0.13(react@18.3.1): - dependencies: - '@babel/runtime': 7.24.7 - react: 18.3.1 - - react-hook-form@7.52.1(react@18.3.1): + react-hook-form@7.53.1(react@18.3.1): dependencies: react: 18.3.1 @@ -8982,6 +9020,15 @@ snapshots: dependencies: glob: 7.2.3 + rollup-plugin-visualizer@5.12.0(rollup@4.18.0): + dependencies: + open: 8.4.2 + picomatch: 2.3.1 + source-map: 0.7.4 + yargs: 17.7.2 + optionalDependencies: + rollup: 4.18.0 + rollup@4.18.0: dependencies: '@types/estree': 1.0.5 @@ -9129,6 +9176,8 @@ snapshots: source-map@0.6.1: {} + source-map@0.7.4: {} + space-separated-tokens@2.0.2: {} statuses@2.0.1: {} @@ -9491,6 +9540,7 @@ snapshots: use-sync-external-store@1.2.0(react@18.3.1): dependencies: react: 18.3.1 + optional: true util-deprecate@1.0.2: {} @@ -9648,9 +9698,8 @@ snapshots: yoctocolors-cjs@2.1.1: {} - zustand@4.5.4(@types/react@18.3.3)(react@18.3.1): - dependencies: - use-sync-external-store: 1.2.0(react@18.3.1) + zustand@5.0.0(@types/react@18.3.3)(react@18.3.1)(use-sync-external-store@1.2.0(react@18.3.1)): optionalDependencies: '@types/react': 18.3.3 react: 18.3.1 + use-sync-external-store: 1.2.0(react@18.3.1) diff --git a/src/App.tsx b/src/App.tsx index e94cc105..4a62dec8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,14 +1,14 @@ import { css } from '@emotion/react'; import * as Sentry from '@sentry/react'; -import { Outlet, useNavigate } from 'react-router-dom'; +import { Outlet, useLocation, useNavigate } from 'react-router-dom'; import { useQueryErrorResetBoundary } from '@tanstack/react-query'; import ErrorBoundary from '@/common/component/ErrorBoundary/ErrorBoundary'; -import { theme } from '@/common/style/theme/theme'; import { HTTPError } from '@/shared/api/HTTPError'; +import Header from '@/shared/component/Header/Header'; import Login from '@/shared/component/Login/Login'; import ModalContainer from '@/shared/component/Modal/ModalContainer'; import SNB from '@/shared/component/SideNavBar/LeftSidebar'; @@ -21,6 +21,11 @@ const App = () => { const { reset } = useQueryErrorResetBoundary(); + const { pathname } = useLocation(); + + /** 아카이빙 페이지 DocumentBar를 위한 라우트별 동적 패딩 */ + const isArchivingPage = pathname === '/archiving'; + Sentry.init({ dsn: import.meta.env.VITE_SENTRY_DSN, integrations: [Sentry.browserTracingIntegration()], @@ -50,7 +55,8 @@ const App = () => { -
+
+
@@ -58,11 +64,19 @@ const App = () => { ); }; -const layoutStyle = css({ - height: '100%', +const layoutStyle = (flag: boolean) => + css({ + display: 'flex', + flexDirection: 'column', + + height: '100%', + width: 'calc(100% - 7.6rem)', - borderRadius: '16px', - backgroundColor: theme.colors.white, -}); + padding: flag ? '0' : '2rem 3.4rem 4.8rem 3.2rem', + + marginLeft: '7.6rem', + + overflow: 'hidden', + }); export default App; diff --git a/src/common/asset/img/tooltip.png b/src/common/asset/img/tooltip.png new file mode 100644 index 0000000000000000000000000000000000000000..a13363c51b8f4e360c04546e7640c2c116225637 GIT binary patch literal 555 zcmV+`0@VG9P) zT$|90jdcg zXiPRmH%KC(P;fHeEO-QkVGPQ#k>InQDV2#LaN?%}a^vP9VFJ@apLQ3qlH7J*VnYfkCi4=(#))DzGXh7`y zgnY50MWtXWMlce(7ztn`bdgBl9w?5;46Z~1wm@+>V!QQ(T^OS|yWTs@R0|ptjg8uttn-`q@ReT9o?#fxgE|q>5CZn6K9C)z tzo%e~ug>0?1Z6sG(K>f`bJ-rg@&imtjBGY5pL_rS002ovPDHLkV1g;j;FJIW literal 0 HcmV?d00001 diff --git a/src/common/asset/svg/ic_add_team.svg b/src/common/asset/svg/ic_add_team.svg new file mode 100644 index 00000000..679110b4 --- /dev/null +++ b/src/common/asset/svg/ic_add_team.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/common/asset/svg/ic_alert_no.svg b/src/common/asset/svg/ic_alert_no.svg new file mode 100644 index 00000000..21bf61d1 --- /dev/null +++ b/src/common/asset/svg/ic_alert_no.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/common/asset/svg/ic_alert_yes.svg b/src/common/asset/svg/ic_alert_yes.svg new file mode 100644 index 00000000..68de9dd5 --- /dev/null +++ b/src/common/asset/svg/ic_alert_yes.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/common/asset/svg/ic_calendar_arrow_left.svg b/src/common/asset/svg/ic_calendar_arrow_left.svg new file mode 100644 index 00000000..ff1e7632 --- /dev/null +++ b/src/common/asset/svg/ic_calendar_arrow_left.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/common/asset/svg/ic_calendar_arrow_right.svg b/src/common/asset/svg/ic_calendar_arrow_right.svg new file mode 100644 index 00000000..4f45ff0e --- /dev/null +++ b/src/common/asset/svg/ic_calendar_arrow_right.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/common/asset/svg/ic_file.svg b/src/common/asset/svg/ic_file.svg new file mode 100644 index 00000000..ed202994 --- /dev/null +++ b/src/common/asset/svg/ic_file.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/common/asset/svg/ic_folder.svg b/src/common/asset/svg/ic_folder.svg index 93882671..1b5bcc77 100644 --- a/src/common/asset/svg/ic_folder.svg +++ b/src/common/asset/svg/ic_folder.svg @@ -1,4 +1,4 @@ - + diff --git a/src/common/asset/svg/ic_folder_large.svg b/src/common/asset/svg/ic_folder_large.svg new file mode 100644 index 00000000..63754f81 --- /dev/null +++ b/src/common/asset/svg/ic_folder_large.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/common/asset/svg/ic_handover_fill.svg b/src/common/asset/svg/ic_handover_fill.svg new file mode 100644 index 00000000..7a5f639a --- /dev/null +++ b/src/common/asset/svg/ic_handover_fill.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/common/asset/svg/ic_image_file.svg b/src/common/asset/svg/ic_image_file.svg new file mode 100644 index 00000000..6a0700b3 --- /dev/null +++ b/src/common/asset/svg/ic_image_file.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/common/asset/svg/ic_pdf_file.svg b/src/common/asset/svg/ic_pdf_file.svg new file mode 100644 index 00000000..00b12bcc --- /dev/null +++ b/src/common/asset/svg/ic_pdf_file.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/common/asset/svg/ic_pencil.svg b/src/common/asset/svg/ic_pencil.svg new file mode 100644 index 00000000..7254b764 --- /dev/null +++ b/src/common/asset/svg/ic_pencil.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/common/asset/svg/ic_setting_gray.svg b/src/common/asset/svg/ic_setting_gray.svg new file mode 100644 index 00000000..bbc74745 --- /dev/null +++ b/src/common/asset/svg/ic_setting_gray.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/common/asset/svg/ic_three_dots.svg b/src/common/asset/svg/ic_three_dots.svg new file mode 100644 index 00000000..f2b34b17 --- /dev/null +++ b/src/common/asset/svg/ic_three_dots.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/common/asset/svg/ic_timeline.svg b/src/common/asset/svg/ic_timeline.svg new file mode 100644 index 00000000..8ed53de3 --- /dev/null +++ b/src/common/asset/svg/ic_timeline.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/common/asset/svg/ic_tooltip.svg b/src/common/asset/svg/ic_tooltip.svg new file mode 100644 index 00000000..1c41a51f --- /dev/null +++ b/src/common/asset/svg/ic_tooltip.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/common/asset/svg/ic_tooltip_arrow(3).svg b/src/common/asset/svg/ic_tooltip_arrow(3).svg new file mode 100644 index 00000000..c0373fb2 --- /dev/null +++ b/src/common/asset/svg/ic_tooltip_arrow(3).svg @@ -0,0 +1,3 @@ + + + diff --git a/src/common/asset/svg/ic_trash.svg b/src/common/asset/svg/ic_trash.svg new file mode 100644 index 00000000..ec9a5364 --- /dev/null +++ b/src/common/asset/svg/ic_trash.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/common/asset/svg/ic_word_file.svg b/src/common/asset/svg/ic_word_file.svg new file mode 100644 index 00000000..160d8342 --- /dev/null +++ b/src/common/asset/svg/ic_word_file.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/common/component/Button/Button.style.ts b/src/common/component/Button/Button.style.ts index e42e6b71..5124bc52 100644 --- a/src/common/component/Button/Button.style.ts +++ b/src/common/component/Button/Button.style.ts @@ -10,10 +10,6 @@ export const buttonStyle = css({ alignItems: 'center', gap: '0.4rem', - width: '100%', - - padding: '1.6rem 1.4rem', - border: 'none', borderRadius: '8px', @@ -58,11 +54,11 @@ export const variantStyle = (variant: Required['variant']) => { }, }), outline: css({ - border: `1px solid ${theme.colors.gray_300}`, - color: theme.colors.gray_800, backgroundColor: theme.colors.white, + boxShadow: theme.shadow.inset, + '&:hover': { backgroundColor: theme.colors.gray_100, }, @@ -88,13 +84,36 @@ export const variantStyle = (variant: Required['variant']) => { export const sizeStyle = (size: Required['size']) => { const style = { + /** Button_46 */ + xLarge: css({ + padding: '1.6rem 1.4rem', + + ...theme.text.body06, + }), + /** Button_40 */ large: css({ - ...theme.text.body04, + padding: '1.4rem', + + ...theme.text.body08, }), + /** Button_36 */ medium: css({ - ...theme.text.body06, + padding: '1.2rem 1.4rem', + + ...theme.text.body08, }), + /** Button_32 */ small: css({ + padding: '1rem 1.4rem', + + ...theme.text.body08, + }), + /** Button_24 */ + xSmall: css({ + padding: '0.6rem 1rem', + + borderRadius: '1.2rem', + ...theme.text.body08, }), }; diff --git a/src/common/component/Button/Button.tsx b/src/common/component/Button/Button.tsx index d9e36ae4..2e0934a6 100644 --- a/src/common/component/Button/Button.tsx +++ b/src/common/component/Button/Button.tsx @@ -6,10 +6,10 @@ import { buttonStyle, sizeStyle, variantStyle } from './Button.style'; export interface ButtonProps extends ButtonHTMLAttributes { variant?: 'primary' | 'secondary' | 'tertiary' | 'outline' | 'underline'; - size?: Extract; + size?: Extract; } -const Button = ({ variant = 'primary', children, size = 'small', ...props }: ButtonProps) => { +const Button = ({ variant = 'primary', children, size = 'medium', ...props }: ButtonProps) => { return (
- - - -
- ); -}; - -export default Calendar; diff --git a/src/common/component/DatePicker/Calendar/DatePickerCalendar.tsx b/src/common/component/DatePicker/Calendar/DatePickerCalendar.tsx index 4dcfdb86..1770935b 100644 --- a/src/common/component/DatePicker/Calendar/DatePickerCalendar.tsx +++ b/src/common/component/DatePicker/Calendar/DatePickerCalendar.tsx @@ -1,17 +1,33 @@ -import Calender from './Calendar'; +import { containerStyle } from '@/common/component/DatePicker/Calendar/Calendar.style'; +import CalendarDates from '@/common/component/DatePicker/Calendar/Dates/CalendarDates'; +import CalendarDays from '@/common/component/DatePicker/Calendar/Days/CalendarDays'; +import CalendarHeader from '@/common/component/DatePicker/Calendar/Header/CalendarHeader'; +import useCalendar from '@/common/hook/useCalendar'; interface DatePickerCalendarProps { - selectedDate: Date | null; + selectedDate: Date; + endDate: Date | null; setSelectedDate: (date: Date) => void; - isOpen: boolean; + variant: 'single' | 'range'; } -const DatePickerCalendar = ({ selectedDate, setSelectedDate, isOpen }: DatePickerCalendarProps) => { - return isOpen ? ( -
- +const DatePickerCalendar = ({ selectedDate, endDate, setSelectedDate, variant }: DatePickerCalendarProps) => { + const { currentMonth, currentMonthAllDates, weekDays, toNextMonth, toPrevMonth } = useCalendar(selectedDate); + + return ( +
+ + +
- ) : null; + ); }; export default DatePickerCalendar; diff --git a/src/common/component/DatePicker/Calendar/Dates/CalendarDates.tsx b/src/common/component/DatePicker/Calendar/Dates/CalendarDates.tsx index 22f08e6c..03b305dc 100644 --- a/src/common/component/DatePicker/Calendar/Dates/CalendarDates.tsx +++ b/src/common/component/DatePicker/Calendar/Dates/CalendarDates.tsx @@ -1,39 +1,42 @@ -import { isSameDay, isSameMonth } from 'date-fns'; +import { isSameMonth } from 'date-fns'; -import { - dateStyle, - datesContainerStyle, - hoverDateStyle, - outOfMonthStyle, - selectedDateStyle, -} from '@/common/component/DatePicker/Calendar/Calendar.style'; +import { dateStyle, datesContainerStyle } from '@/common/component/DatePicker/Calendar/Calendar.style'; +import { getDateStyle } from '@/common/component/DatePicker/Calendar/Dates/util/dateStyle'; interface CalendarDatesProps { currentMonth: Date; currentMonthAllDates: Date[]; - selectedDate: Date; + selectedDate: Date | null; + endDate: Date | null; setSelectedDate: (date: Date) => void; + variant: 'single' | 'range'; } -const CalendarDates = ({ currentMonth, currentMonthAllDates, selectedDate, setSelectedDate }: CalendarDatesProps) => ( -
- {currentMonthAllDates.map((date, index) => ( -
setSelectedDate(date)} - onKeyDown={(e) => (e.key === 'Enter' ? setSelectedDate(date) : null)}> - {date.getDate()} -
- ))} -
-); +const CalendarDates = ({ + currentMonth, + currentMonthAllDates, + selectedDate, + endDate, + setSelectedDate, +}: CalendarDatesProps) => { + return ( +
+ {currentMonthAllDates.map((date, index) => ( +
setSelectedDate(date)} + onKeyDown={(e) => { + if (e.key === 'Enter') setSelectedDate(date); + }}> + {isSameMonth(currentMonth, date) ? date.getDate() : ''} +
+ ))} +
+ ); +}; export default CalendarDates; diff --git a/src/common/component/DatePicker/Calendar/Dates/util/dateStyle.ts b/src/common/component/DatePicker/Calendar/Dates/util/dateStyle.ts new file mode 100644 index 00000000..0b634e1e --- /dev/null +++ b/src/common/component/DatePicker/Calendar/Dates/util/dateStyle.ts @@ -0,0 +1,64 @@ +import { endOfMonth, getDay, isSameDay, isSameMonth, isWithinInterval, startOfMonth } from 'date-fns'; + +import { + hoverDateStyle, + rangeDateStyle, + selectedDateStyle, + selectedEndDateStyle, + selectedStartDateStyle, +} from '@/common/component/DatePicker/Calendar/Calendar.style'; + +export const getDateStyle = (date: Date, selectedDate: Date | null, endDate: Date | null, currentMonth: Date) => { + // 현재 달의 날짜가 선택된 날짜 범위 내에 있는지 확인 + const handleDateInRange = (date: Date) => + selectedDate && + endDate && + isWithinInterval(date, { start: selectedDate, end: endDate }) && + isSameMonth(currentMonth, date); + + const isSelected = selectedDate && isSameDay(selectedDate, date); + const isEndDate = endDate && isSameDay(endDate, date); + const isSameStartEndDate = isSelected && isEndDate; + const isInRange = handleDateInRange(date); + + const isStartOfWeek = getDay(date) === 0 && isInRange; // 일요일이며 선택된 기간 내에 있는지 확인 + const isEndOfWeek = getDay(date) === 6 && isInRange; // 토요일이며 선택된 기간 내에 있는지 확인 + const isStartOfMonth = isSameDay(date, startOfMonth(currentMonth)); + const isEndOfMonth = isSameDay(date, endOfMonth(currentMonth)); + + //// 선택된 날짜가 월의 마지막 날인지 확인 + const isStartDateEndOfMonth = selectedDate && isSameDay(selectedDate, endOfMonth(currentMonth)); + // 종료 날짜가 다음 달의 첫 번째 날인지 확인 + const isEndDateStartOfNextMonth = endDate && isSameDay(endDate, startOfMonth(currentMonth)); + + if (isStartDateEndOfMonth && isInRange) { + return selectedDateStyle; + } + + if (isEndDateStartOfNextMonth && isInRange) { + return selectedDateStyle; + } + + if (isSameMonth(currentMonth, date)) { + if (endDate && selectedDate) { + if (isSameStartEndDate) return selectedDateStyle; + if (isStartOfMonth && isEndDate) return selectedDateStyle; + if (isEndOfMonth && isSelected) return selectedDateStyle; + if (isSelected || (isStartOfWeek && isInRange) || (isStartOfMonth && isInRange)) { + return selectedStartDateStyle; + } + if (isEndDate || (isEndOfWeek && isInRange) || (isEndOfMonth && isInRange)) { + return selectedEndDateStyle; + } + if (isInRange) { + return rangeDateStyle; + } + } else if (isSelected) { + return selectedDateStyle; + } else { + return hoverDateStyle; + } + } + + return null; +}; diff --git a/src/common/component/DatePicker/Calendar/Days/CalendarDays.tsx b/src/common/component/DatePicker/Calendar/Days/CalendarDays.tsx index 530d3a1d..c8fc78c8 100644 --- a/src/common/component/DatePicker/Calendar/Days/CalendarDays.tsx +++ b/src/common/component/DatePicker/Calendar/Days/CalendarDays.tsx @@ -1,4 +1,4 @@ -import { datesContainerStyle, dayStyle } from '@/common/component/DatePicker/Calendar/Calendar.style'; +import { datesContainerStyle } from '@/common/component/DatePicker/Calendar/Calendar.style'; import Text from '@/common/component/Text/Text'; interface CalendarDaysProps { @@ -8,7 +8,7 @@ interface CalendarDaysProps { const CalendarDays = ({ weekDays }: CalendarDaysProps) => (
{weekDays.map((day, index) => ( - + {day} ))} diff --git a/src/common/component/DatePicker/Calendar/Header/CalendarHeader.tsx b/src/common/component/DatePicker/Calendar/Header/CalendarHeader.tsx index 0e5ab0f6..239b3643 100644 --- a/src/common/component/DatePicker/Calendar/Header/CalendarHeader.tsx +++ b/src/common/component/DatePicker/Calendar/Header/CalendarHeader.tsx @@ -1,10 +1,9 @@ import { format } from 'date-fns'; -import { ko } from 'date-fns/locale'; -import ArrowLeft from '@/common/asset/svg/ic_arrow_left.svg?react'; -import ArrowRight from '@/common/asset/svg/ic_arrow_right.svg?react'; +import ArrowLeft from '@/common/asset/svg/ic_calendar_arrow_left.svg?react'; +import ArrowRight from '@/common/asset/svg/ic_calendar_arrow_right.svg?react'; import Flex from '@/common/component/Flex/Flex'; -import Heading from '@/common/component/Heading/Heading'; +import Text from '@/common/component/Text/Text'; interface CalendarHeaderProps { currentMonth: Date; @@ -13,12 +12,12 @@ interface CalendarHeaderProps { } const CalendarHeader = ({ currentMonth, onClickPrev, onClickNext }: CalendarHeaderProps) => ( - - - - {format(currentMonth, 'yyyy년 MM월', { locale: ko })} - - + + + + {format(currentMonth, 'yyyy.MM')} + + ); diff --git a/src/common/component/DatePicker/DatePickerContainer/DatePickerContainer.tsx b/src/common/component/DatePicker/DatePickerContainer/DatePickerContainer.tsx deleted file mode 100644 index 6f9015dd..00000000 --- a/src/common/component/DatePicker/DatePickerContainer/DatePickerContainer.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { ComponentPropsWithRef, forwardRef } from 'react'; - -import { containerStyle } from '@/common/component/DatePicker/DatePickerContainer/DatePickerContainer.style'; - -const DatePickerContainer = forwardRef>(({ children }, ref) => ( -
- {children} -
-)); - -export default DatePickerContainer; diff --git a/src/common/component/DatePicker/Trigger/DatePickerTrigger.style.ts b/src/common/component/DatePicker/Trigger/DatePickerTrigger.style.ts new file mode 100644 index 00000000..9570d619 --- /dev/null +++ b/src/common/component/DatePicker/Trigger/DatePickerTrigger.style.ts @@ -0,0 +1,7 @@ +import { css } from '@emotion/react'; + +import { theme } from '@/common/style/theme/theme'; + +export const textStyle = css({ + color: theme.colors.gray_800, +}); diff --git a/src/common/component/DatePicker/Trigger/DatePickerTrigger.tsx b/src/common/component/DatePicker/Trigger/DatePickerTrigger.tsx index 530e56dc..2c4e518b 100644 --- a/src/common/component/DatePicker/Trigger/DatePickerTrigger.tsx +++ b/src/common/component/DatePicker/Trigger/DatePickerTrigger.tsx @@ -1,24 +1,47 @@ import { format } from 'date-fns'; +import { textStyle } from '@/common/component/DatePicker/Trigger/DatePickerTrigger.style'; +import Flex from '@/common/component/Flex/Flex'; import Input from '@/common/component/Input/Input'; +import Text from '@/common/component/Text/Text'; interface DatePickerTriggerProps { selectedDate: Date | null; + endDate?: Date | null; onClick: () => void; width?: string; + variant: 'single' | 'range'; } -const DatePickerTrigger = ({ selectedDate, onClick, width = '10.3rem' }: DatePickerTriggerProps) => { +const DatePickerTrigger = ({ selectedDate, endDate, onClick, width, variant }: DatePickerTriggerProps) => { return ( - + + + {variant === 'range' && ( + <> + + ~ + + + + )} + ); }; diff --git a/src/common/component/DatePicker/DatePickerContainer/DatePickerContainer.style.ts b/src/common/component/DatePicker/index.style.ts similarity index 89% rename from src/common/component/DatePicker/DatePickerContainer/DatePickerContainer.style.ts rename to src/common/component/DatePicker/index.style.ts index 0f66a720..760cd3f3 100644 --- a/src/common/component/DatePicker/DatePickerContainer/DatePickerContainer.style.ts +++ b/src/common/component/DatePicker/index.style.ts @@ -3,7 +3,5 @@ import { css } from '@emotion/react'; export const containerStyle = css({ display: 'flex', flexDirection: 'column', - gap: '0.4rem', - position: 'relative', }); diff --git a/src/common/component/DatePicker/index.tsx b/src/common/component/DatePicker/index.tsx index 82bf38fe..beb74529 100644 --- a/src/common/component/DatePicker/index.tsx +++ b/src/common/component/DatePicker/index.tsx @@ -1,10 +1,47 @@ import DatePickerCalendar from '@/common/component/DatePicker/Calendar/DatePickerCalendar'; -import DatePickerContainer from '@/common/component/DatePicker/DatePickerContainer/DatePickerContainer'; import DatePickerTrigger from '@/common/component/DatePicker/Trigger/DatePickerTrigger'; +import { containerStyle } from '@/common/component/DatePicker/index.style'; +import { useDatePicker } from '@/common/hook/useDatePicker'; +import { useOutsideClick } from '@/common/hook/useOutsideClick'; +import { useOverlay } from '@/common/hook/useOverlay'; -const DatePicker = Object.assign(DatePickerContainer, { - Trigger: DatePickerTrigger, - Calendar: DatePickerCalendar, -}); +interface DatePickerProps { + variant: 'single' | 'range'; + triggerWidth?: string; +} + +const DatePicker = ({ variant, triggerWidth = '10.3rem' }: DatePickerProps) => { + const { isOpen, close, toggle } = useOverlay(); + const ref = useOutsideClick(close); + const { selectedDate, endDate, handleSelectDate, clearDates } = useDatePicker(variant); + + const handleInputClick = () => { + // 캘린더가 닫혀 있고, 시작날짜와 종료날짜가 모두 선택된 경우에만 날짜 초기화 + if (!isOpen && selectedDate && endDate) { + clearDates(); + } + toggle(); + }; + + return ( +
+ + {isOpen && ( + + )} +
+ ); +}; export default DatePicker; diff --git a/src/common/component/Menu/MenuItem/MenuItem.style.ts b/src/common/component/Menu/MenuItem/MenuItem.style.ts index 3c095ab8..9caf19a9 100644 --- a/src/common/component/Menu/MenuItem/MenuItem.style.ts +++ b/src/common/component/Menu/MenuItem/MenuItem.style.ts @@ -5,6 +5,7 @@ import { theme } from '@/common/style/theme/theme'; export const containerStyle = css({ display: 'flex', + alignItems: 'center', gap: '0.8rem', cursor: 'pointer', @@ -12,7 +13,7 @@ export const containerStyle = css({ export const variantStyle = (variant: Required['variant']) => { const style = { - primary: { + primary: css({ padding: '0.8rem', backgroundColor: theme.colors.gray_100, @@ -27,7 +28,7 @@ export const variantStyle = (variant: Required['variant']) => { outline: 0, backgroundColor: theme.colors.blue_100, }, - }, + }), }; return style[variant]; diff --git a/src/common/component/Menu/MenuItem/MenuItem.tsx b/src/common/component/Menu/MenuItem/MenuItem.tsx index 9815737f..49d9b4c0 100644 --- a/src/common/component/Menu/MenuItem/MenuItem.tsx +++ b/src/common/component/Menu/MenuItem/MenuItem.tsx @@ -22,7 +22,7 @@ const MenuItem = ({ variant = 'primary', LeftIcon, onSelect, children, ...props onClick={onSelect} {...props}> {LeftIcon} -

{children}

+ {children} ); }; diff --git a/src/common/component/Menu/MenuList/MenuList.style.ts b/src/common/component/Menu/MenuList/MenuList.style.ts index 70a372ac..55b2c8c2 100644 --- a/src/common/component/Menu/MenuList/MenuList.style.ts +++ b/src/common/component/Menu/MenuList/MenuList.style.ts @@ -10,7 +10,6 @@ export const containerStyle = css({ position: 'absolute', - whiteSpace: 'nowrap', zIndex: theme.zIndex.overlayTop, }); diff --git a/src/common/component/Text/Text.style.ts b/src/common/component/Text/Text.style.ts index 9b6e70ac..7d544b74 100644 --- a/src/common/component/Text/Text.style.ts +++ b/src/common/component/Text/Text.style.ts @@ -38,6 +38,14 @@ export const textStyle = (tag: Required['tag']) => { fontSize: theme.text.body08.fontSize, lineHeight: theme.text.body08.lineHeight, }), + body9: css({ + fontSize: theme.text.body09.fontSize, + lineHeight: theme.text.body09.lineHeight, + }), + body10: css({ + fontSize: theme.text.body10.fontSize, + lineHeight: theme.text.body10.lineHeight, + }), }; return style[tag]; }; diff --git a/src/common/component/Text/Text.tsx b/src/common/component/Text/Text.tsx index b7864c8d..9746cdb0 100644 --- a/src/common/component/Text/Text.tsx +++ b/src/common/component/Text/Text.tsx @@ -3,7 +3,7 @@ import { HTMLAttributes } from 'react'; import { textStyle } from './Text.style'; export interface TextProps extends HTMLAttributes { - tag?: 'body1' | 'body2' | 'body3' | 'body4' | 'body5' | 'body6' | 'body7' | 'body8'; + tag?: 'body1' | 'body2' | 'body3' | 'body4' | 'body5' | 'body6' | 'body7' | 'body8' | 'body9' | 'body10'; } const Text = ({ tag = 'body3', children, ...props }: TextProps) => { diff --git a/src/common/component/ToolTip/ToolTip.style.ts b/src/common/component/ToolTip/ToolTip.style.ts index 9a6034f8..2a668e72 100644 --- a/src/common/component/ToolTip/ToolTip.style.ts +++ b/src/common/component/ToolTip/ToolTip.style.ts @@ -1,5 +1,6 @@ import { css } from '@emotion/react'; +import toolTipImg from '@/common/asset/img/tooltip.png'; import { ToolTipProps } from '@/common/component/ToolTip/ToolTip'; import { theme } from '@/common/style/theme/theme'; @@ -17,10 +18,15 @@ export const messageStyle = css({ display: 'none', position: 'absolute', + backgroundImage: `url(${toolTipImg})`, + backgroundSize: 'cover', + backgroundPosition: 'left', + backgroundRepeat: 'no-repeat', + width: 'max-content', padding: '1rem', borderRadius: '8px', - backgroundColor: `${theme.colors.gray_900}`, + // backgroundColor: `${theme.colors.gray_900}`, font: `${theme.text.body08}`, color: `${theme.colors.white}`, }); @@ -60,23 +66,23 @@ export const arrowPositionStyle = (position: Required['position']) const style = { top: css({ left: '50%', - top: '99%', - transform: `translateX(-50%) rotate(270deg)`, + top: 'calc(100% - 1px)', + transform: `translateX(-50%) translateY(-1px) rotate(270deg)`, }), bottom: css({ left: '50%', - bottom: '98%', - transform: `translateX(-50%) rotate(90deg)`, + bottom: 'calc(100% - 1px)', + transform: `translateX(-50%) translateY(1px) rotate(90deg)`, }), left: css({ top: '50%', - left: '98%', - transform: `translateY(-50%) rotate(180deg)`, + left: 'calc(100% - 1px)', + transform: `translateY(-50%) translateX(-1px) rotate(180deg)`, }), right: css({ top: '50%', - right: '98%', - transform: `translateY(-50%) `, + right: 'calc(100% - 1px)', + transform: `translateY(-50%) translateX(1px)`, }), }; diff --git a/src/common/component/ToolTip/ToolTip.tsx b/src/common/component/ToolTip/ToolTip.tsx index 1bdc813d..08b38806 100644 --- a/src/common/component/ToolTip/ToolTip.tsx +++ b/src/common/component/ToolTip/ToolTip.tsx @@ -1,5 +1,6 @@ import { HTMLAttributes } from 'react'; +import Tooltip from '@/common/asset/svg/ic_tooltip.svg?react'; import Arrow from '@/common/asset/svg/ic_tooltip_arrow.svg?react'; import { arrowPositionStyle, @@ -20,7 +21,7 @@ const ToolTip = ({ position = 'right', message, margin = 0, children }: ToolTipP
{children} - + {/* */} {message}
diff --git a/src/common/hook/useDatePicker.ts b/src/common/hook/useDatePicker.ts new file mode 100644 index 00000000..a9c4c4ff --- /dev/null +++ b/src/common/hook/useDatePicker.ts @@ -0,0 +1,38 @@ +import { isBefore } from 'date-fns'; + +import { useState } from 'react'; + +export const useDatePicker = (variant: 'single' | 'range') => { + const [selectedDate, setSelectedDate] = useState(null); + const [endDate, setEndDate] = useState(null); + + const handleSelectDate = (date: Date) => { + if (variant === 'range') { + if (!selectedDate || (selectedDate && endDate)) { + setSelectedDate(date); + setEndDate(null); + } else { + if (isBefore(date, selectedDate)) { + setEndDate(selectedDate); + setSelectedDate(date); + } else { + setEndDate(date); + } + } + } else { + setSelectedDate(date); + } + }; + + const clearDates = () => { + setSelectedDate(null); + setEndDate(null); + }; + + return { + selectedDate, + endDate, + handleSelectDate, + clearDates, + }; +}; diff --git a/src/common/router/Router.tsx b/src/common/router/Router.tsx index e603bbf6..0bc23c9a 100644 --- a/src/common/router/Router.tsx +++ b/src/common/router/Router.tsx @@ -1,21 +1,23 @@ import App from '@/App'; +import { Suspense } from 'react'; import { Outlet, RouterProvider, createBrowserRouter, useNavigate } from 'react-router-dom'; import ErrorBoundary from '@/common/component/ErrorBoundary/ErrorBoundary'; - -import ArchivingPage from '@/page/archiving/index/ArchivingPage'; -import LandingPage from '@/page/landing/LandingPage'; -import LoginPage from '@/page/login/index/LoginPage'; -import PasswordAuthPage from '@/page/login/password/auth/PasswordAuthPage'; -import PasswordResetPage from '@/page/login/password/reset/PasswordResetPage'; -import ShowcasePage from '@/page/showcase/index/ShowcasePage'; -import TermPage from '@/page/signUp/index/TermPage'; -import InfoFormPage from '@/page/signUp/info/InfoFormPage'; +import { + ArchivingPage, + ComingsoonPage, + ErrorPage, + InfoFormPage, + LandingPage, + LoginPage, + PasswordAuthPage, + PasswordResetPage, + ShowcasePage, + TermPage, +} from '@/common/router/lazy'; import { PATH } from '@/shared/constant/path'; -import ComingsoonPage from '@/shared/page/comingsoonPage/ComingsoonPage'; -import ErrorPage from '@/shared/page/errorPage/ErrorPage'; const Public = () => { const navigate = useNavigate(); @@ -33,48 +35,102 @@ const router = createBrowserRouter([ { path: PATH.ROOT, element: , - errorElement: , + errorElement: ( + + + + ), children: [ - { path: PATH.LANDING, element: }, + { + path: PATH.LANDING, + element: ( + + + + ), + }, { path: PATH.LOGIN, - element: , + element: ( + + + + ), }, { path: PATH.SIGNUP, - element: , + element: ( + + + + ), }, { path: PATH.SIGNUP_INFO, - element: , + element: ( + + + + ), }, { path: PATH.SIGNUP_PASSWORD, - element: , + element: ( + + + + ), }, { path: PATH.PASSWORD_AUTH, - element: , + element: ( + + + + ), }, { path: PATH.PASSWORD_RESET, - element: , + element: ( + + + + ), }, ], }, { path: PATH.ROOT, element: , - errorElement: , + errorElement: ( + + + + ), children: [ - { path: PATH.SHOWCASE, element: }, + { + path: PATH.SHOWCASE, + element: ( + + + + ), + }, { path: PATH.ARCHIVING, - element: , + element: ( + + + + ), }, { path: PATH.COMING_SOON, - element: , + element: ( + + + + ), }, ], }, diff --git a/src/common/router/lazy.ts b/src/common/router/lazy.ts new file mode 100644 index 00000000..b06ed410 --- /dev/null +++ b/src/common/router/lazy.ts @@ -0,0 +1,12 @@ +import { lazy } from 'react'; + +export const LandingPage = lazy(() => import('@/page/landing/LandingPage')); +export const LoginPage = lazy(() => import('@/page/login/index/LoginPage')); +export const TermPage = lazy(() => import('@/page/signUp/index/TermPage')); +export const InfoFormPage = lazy(() => import('@/page/signUp/info/InfoFormPage')); +export const PasswordAuthPage = lazy(() => import('@/page/login/password/auth/PasswordAuthPage')); +export const PasswordResetPage = lazy(() => import('@/page/login/password/reset/PasswordResetPage')); +export const ShowcasePage = lazy(() => import('@/page/showcase/index/ShowcasePage')); +export const ArchivingPage = lazy(() => import('@/page/archiving/index/ArchivingPage')); +export const ErrorPage = lazy(() => import('@/shared/page/errorPage/ErrorPage')); +export const ComingsoonPage = lazy(() => import('@/shared/page/comingsoonPage/ComingsoonPage')); diff --git a/src/common/style/theme/theme.ts b/src/common/style/theme/theme.ts index 526399dd..0bb1ea7d 100644 --- a/src/common/style/theme/theme.ts +++ b/src/common/style/theme/theme.ts @@ -2,33 +2,45 @@ const colors = { black: '#0E121B', black_shade: 'linear-gradient(270deg, rgba(0, 0, 0, 0.00) 0%, rgba(0, 0, 0, 0.70) 100%)', dimmed: 'rgba(0, 0, 0, 0.40)', + gray_900: '#323A4C', gray_800: '#525866', gray_700: '#6B6B6B', + gray_600: '#909090', gray_500: '#99A1B2', gray_400: '#CCD1DD', gray_300: '#DFE1E8', gray_200: '#ECECF1', gray_100: '#F8F8FB', + white: '#FFFFFF', + key_600: '#444EE4', key_500: '#6D77FF', key_200: '#E3E8FF', key_100: '#F3F5FF', + sementic_red: '#FE4F60', sementic_success: '#1FC16B', + red_200: '#EB736D', red_100: '#FFE6E8', + yellow_200: '#F19234', yellow_100: '#F8E2CB', + green_200: '#49B078', green_100: '#C4F2E5', + purple_200: '#856ECF', purple_100: '#DCD8FA', + blue_200: '#607AD4', blue_100: '#E2E8F8', + pink_200: '#F175C0', pink_100: '#F8E1F5', + sky_200: '#48ABD2', sky_100: '#D3EFFA', }; @@ -113,7 +125,7 @@ const zIndex = { } as const; const shadow = { - inset: `inset 0 0 0 1px ${colors.gray_200}`, + inset: `inset 0 0 0 1px ${colors.gray_300}`, inset_focus: `inset 0 0 0 1px ${colors.key_500}`, shadow01: '0px 2px 8px 0px rgba(99, 99, 99, 0.2)', // 6 shadow02: '0px 4px 10px rgba(0, 0, 0, 0.1)', diff --git a/src/page/archiving/index/ArchivingPage.style.ts b/src/page/archiving/index/ArchivingPage.style.ts index 4d1b2cad..5b43d3fd 100644 --- a/src/page/archiving/index/ArchivingPage.style.ts +++ b/src/page/archiving/index/ArchivingPage.style.ts @@ -6,15 +6,8 @@ import { Block } from '@/page/archiving/index/type/blockType'; export const pageStyle = () => css({ - justifyContent: 'center', - alignItems: 'center', - width: '100%', height: '100%', - - paddingLeft: '6rem', - - overflow: 'hidden', }); export const timelineStyle = () => @@ -30,7 +23,7 @@ export const timelineStyle = () => }); export const contentStyle = css({ - maxHeight: '60rem', + width: '100%', flexDirection: 'column', gap: '2rem', diff --git a/src/page/archiving/index/component/DaySection/DaySection.style.ts b/src/page/archiving/index/component/DaySection/DaySection.style.ts index e92adfb0..c58591fa 100644 --- a/src/page/archiving/index/component/DaySection/DaySection.style.ts +++ b/src/page/archiving/index/component/DaySection/DaySection.style.ts @@ -6,7 +6,7 @@ export const dayStyle = (isEven: boolean, isToday: boolean) => css({ position: 'relative', width: '6rem', - height: 'calc(100vh + 4rem)', + height: 'calc(100vh - 8rem - 21.4rem - 4.8rem)', backgroundColor: isToday && isEven diff --git a/src/page/archiving/index/component/DocumentBar/DocumentBar.style.ts b/src/page/archiving/index/component/DocumentBar/DocumentBar.style.ts index 2335c824..a61efc0f 100644 --- a/src/page/archiving/index/component/DocumentBar/DocumentBar.style.ts +++ b/src/page/archiving/index/component/DocumentBar/DocumentBar.style.ts @@ -4,20 +4,18 @@ import { theme } from '@/common/style/theme/theme'; export const containerStyle = (blockSelected: string) => css({ - position: 'sticky', + position: 'relative', - top: '0', - right: '0', zIndex: theme.zIndex.overlayMiddle, - width: blockSelected ? '28rem' : 0, - height: 'calc(100vh - 0.8rem);', - marginLeft: '6rem', + width: blockSelected ? '27rem' : 0, + height: 'calc(100vh)', + + overflow: 'hidden', borderRadius: '16px', boxShadow: '0px 2px 10px 0px rgba(0, 0, 0, 0.10)', backgroundColor: theme.colors.white, - transform: blockSelected ? 'translateX(0)' : 'translateX(28rem)', - transition: '0.4s ease-in-out', + transition: 'all 0.4s ease', }); diff --git a/src/page/archiving/index/component/DocumentBar/DocumentBar.tsx b/src/page/archiving/index/component/DocumentBar/DocumentBar.tsx index 3bec5fb3..9b5c7dde 100644 --- a/src/page/archiving/index/component/DocumentBar/DocumentBar.tsx +++ b/src/page/archiving/index/component/DocumentBar/DocumentBar.tsx @@ -1,10 +1,8 @@ -import { ForwardedRef, forwardRef, useState } from 'react'; +import { ForwardedRef, forwardRef } from 'react'; -import { Tab } from '@/common/component/Tab'; +import { theme } from '@/common/style/theme/theme'; import { containerStyle } from '@/page/archiving/index/component/DocumentBar/DocumentBar.style'; -import Selected from '@/page/archiving/index/component/DocumentBar/Selected/Selected'; -import Total from '@/page/archiving/index/component/DocumentBar/Total/Total'; import { Block } from '@/page/archiving/index/type/blockType'; interface DocumentBarProps { @@ -12,25 +10,10 @@ interface DocumentBarProps { onClose: () => void; } -const DocumentBar = ({ selectedBlock, onClose }: DocumentBarProps, ref: ForwardedRef) => { - const [selectedTab, setSelectedTab] = useState(0); - - const handleTabClick = (tabId: number) => { - setSelectedTab(tabId); - }; - +const DocumentBar = ({ selectedBlock }: DocumentBarProps, ref: ForwardedRef) => { return ( ); }; diff --git a/src/page/deleted/.gitkeep b/src/page/deleted/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/page/drive/.gitkeep b/src/page/drive/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/page/handover/.gitkeep b/src/page/handover/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/page/showcase/index/ShowcasePage.style.ts b/src/page/showcase/index/ShowcasePage.style.ts index 5721fd26..6f16cb85 100644 --- a/src/page/showcase/index/ShowcasePage.style.ts +++ b/src/page/showcase/index/ShowcasePage.style.ts @@ -7,9 +7,6 @@ export const containerStyle = css({ gap: '3.6rem', width: '100%', - minHeight: '100vh', - - padding: '5.6rem 11.6rem 20rem 11.6rem', borderRadius: '16px', }); diff --git a/src/shared/component/ContentBox/ContentBox.style.ts b/src/shared/component/ContentBox/ContentBox.style.ts new file mode 100644 index 00000000..51091a08 --- /dev/null +++ b/src/shared/component/ContentBox/ContentBox.style.ts @@ -0,0 +1,37 @@ +import { css } from '@emotion/react'; + +import { theme } from '@/common/style/theme/theme'; + +export const sectionStyle = css({ + width: '100%', + + padding: '1.6rem', + + border: `1px solid ${theme.colors.gray_300}`, + borderRadius: '16px', +}); + +export const titleStyle = css({ + display: 'flex', + alignItems: 'center', + gap: '0.8rem', + + ...theme.text.body04, + fontWeight: 500, + + whiteSpace: 'nowrap', +}); + +export const headerStyle = css({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + + paddingBottom: '1.6rem', +}); + +export const contentOptionStyle = css({ + width: '100%', + + padding: '0.8rem 0', +}); diff --git a/src/shared/component/ContentBox/ContentBox.tsx b/src/shared/component/ContentBox/ContentBox.tsx new file mode 100644 index 00000000..5c737a2c --- /dev/null +++ b/src/shared/component/ContentBox/ContentBox.tsx @@ -0,0 +1,51 @@ +import { ComponentPropsWithoutRef, ReactNode } from 'react'; + +import IcFile from '@/common/asset/svg/ic_file.svg?react'; +import IcTimeLine from '@/common/asset/svg/ic_timeline.svg?react'; +import IcDeleted from '@/common/asset/svg/ic_trash.svg?react'; +import Divider from '@/common/component/Divider/Divider'; +import Heading from '@/common/component/Heading/Heading'; + +import { + contentOptionStyle, + headerStyle, + sectionStyle, + titleStyle, +} from '@/shared/component/ContentBox/ContentBox.style'; +import { Content } from '@/shared/type/content'; + +interface ContentBoxProps extends ComponentPropsWithoutRef<'section'> { + /** ContentBox를 활용할 도메인, timeline | file | deleted */ + variant: Content; + + title: string; + children: ReactNode; + + headerOption?: ReactNode; + contentOption?: ReactNode; +} + +const ICON_BY_VARIANT = { + timeline: , + file: , + deleted: , +}; + +const ContentBox = ({ variant, title, headerOption, contentOption, children }: ContentBoxProps) => { + return ( +
+
+ + {ICON_BY_VARIANT[variant]} + {title} + + {headerOption} +
+ +
{contentOption}
+ {children} +
+ ); +}; + +export default ContentBox; diff --git a/src/shared/component/FileGrid/FileGrid.tsx b/src/shared/component/FileGrid/FileGrid.tsx new file mode 100644 index 00000000..a3193912 --- /dev/null +++ b/src/shared/component/FileGrid/FileGrid.tsx @@ -0,0 +1,81 @@ +import IcOption from '@/common/asset/svg/ic_three_dots.svg?react'; +import Flex from '@/common/component/Flex/Flex'; +import Heading from '@/common/component/Heading/Heading'; +import Menu from '@/common/component/Menu/Menu'; +import MenuItem from '@/common/component/Menu/MenuItem/MenuItem'; +import MenuList from '@/common/component/Menu/MenuList/MenuList'; +import Text from '@/common/component/Text/Text'; +import { useOverlay } from '@/common/hook'; +import { theme } from '@/common/style/theme/theme'; + +import { FILE_ICON, OPTION_ICON } from '@/shared/component/FileGrid/icon'; +import { + cardStyle, + iconWrapperStyle, + nameStyle, + optionTextStyle, + textStyle, +} from '@/shared/component/FileGrid/index.style'; +import { getFileVolume } from '@/shared/util/file'; + +type FileGridProps = { + title: string; + /** API 명세에 따라 달라질 수 있음 + 추후 삭제 */ + type: 'pdf' | 'image' | 'word'; + volume: number; + + /** + * [TODO] + * onDownLoad + * onDelete + * onShowNote + */ +}; + +const FileGrid = ({ title, type, volume }: FileGridProps) => { + const { isOpen, close, toggle } = useOverlay(); + + return ( +
+
{FILE_ICON[type]}
+ + + + {title} + + + + + console.log('select')}> + 파일 다운로드 + + console.log('select')}> + 휴지통으로 이동 + + console.log('select')}> + 인수인계 노트 보기 + + + + + + + + {type} 문서 + + + {getFileVolume(volume)} + + + +
+ ); +}; + +export default FileGrid; diff --git a/src/shared/component/FileGrid/FolderGrid.tsx b/src/shared/component/FileGrid/FolderGrid.tsx new file mode 100644 index 00000000..b5be1fa2 --- /dev/null +++ b/src/shared/component/FileGrid/FolderGrid.tsx @@ -0,0 +1,57 @@ +import IcFolder from '@/common/asset/svg/ic_folder_large.svg?react'; +import IcOption from '@/common/asset/svg/ic_three_dots.svg?react'; +import Flex from '@/common/component/Flex/Flex'; +import Heading from '@/common/component/Heading/Heading'; +import Menu from '@/common/component/Menu/Menu'; +import MenuItem from '@/common/component/Menu/MenuItem/MenuItem'; +import MenuList from '@/common/component/Menu/MenuList/MenuList'; +import { useOverlay } from '@/common/hook'; +import { theme } from '@/common/style/theme/theme'; + +import { OPTION_ICON } from '@/shared/component/FileGrid/icon'; +import { cardStyle, iconWrapperStyle, nameStyle, optionTextStyle } from '@/shared/component/FileGrid/index.style'; + +type FolderGridProps = { + title: string; + /** API 명세에 따라 달라질 수 있음 + 추후 삭제 */ + + /** + * TODO + * onChangeName + * onDownloadAll + * onDelete + */ +}; + +const FolderGrid = ({ title }: FolderGridProps) => { + const { isOpen, close, toggle } = useOverlay(); + + return ( +
+
{}
+ + + + {title} + + + + + + console.log('select')}> + 이름 변경 + + console.log('select')}> + 폴더 전체 다운로드 + + console.log('select')}> + 휴지통으로 이동 + + + + +
+ ); +}; + +export default FolderGrid; diff --git a/src/shared/component/FileGrid/icon.tsx b/src/shared/component/FileGrid/icon.tsx new file mode 100644 index 00000000..abda0c46 --- /dev/null +++ b/src/shared/component/FileGrid/icon.tsx @@ -0,0 +1,20 @@ +import IcDownload from '@/common/asset/svg/ic_download.svg?react'; +import IcHandOver from '@/common/asset/svg/ic_handover_fill.svg?react'; +import IcImage from '@/common/asset/svg/ic_image_file.svg?react'; +import IcPDF from '@/common/asset/svg/ic_pdf_file.svg?react'; +import IcChangeName from '@/common/asset/svg/ic_pencil.svg?react'; +import IcTrash from '@/common/asset/svg/ic_trash.svg?react'; +import IcWord from '@/common/asset/svg/ic_word_file.svg?react'; + +export const OPTION_ICON = { + download: , + deleted: , + handover: , + name: , +}; + +export const FILE_ICON = { + pdf: , + word: , + image: , +}; diff --git a/src/shared/component/FileGrid/index.style.ts b/src/shared/component/FileGrid/index.style.ts new file mode 100644 index 00000000..1205b7a1 --- /dev/null +++ b/src/shared/component/FileGrid/index.style.ts @@ -0,0 +1,35 @@ +import { css } from '@emotion/react'; + +import { theme } from '@/common/style/theme/theme'; + +export const cardStyle = css({ + width: '100%', + height: '16rem', + + padding: '2.4rem 2rem', + + border: `1px solid ${theme.colors.gray_300}`, + borderRadius: '12px', +}); + +export const iconWrapperStyle = css({ + width: '100%', + + padding: '1.2rem 0 2rem 0', +}); + +export const nameStyle = css({ + ...theme.text.body06, + fontWeight: 500, +}); + +export const textStyle = css({ + color: theme.colors.gray_500, +}); + +export const optionTextStyle = css({ + ...theme.text.body08, + backgroundColor: theme.colors.white, + + fontWeight: 400, +}); diff --git a/src/shared/component/Header/Header.style.ts b/src/shared/component/Header/Header.style.ts new file mode 100644 index 00000000..9c0061d0 --- /dev/null +++ b/src/shared/component/Header/Header.style.ts @@ -0,0 +1,16 @@ +import { css } from '@emotion/react'; + +import { theme } from '@/common/style/theme/theme'; + +export const headerStyle = css({ + width: 'fit-content', + + paddingBottom: '2rem', + + backgroundColor: theme.colors.white, + + '& > h1': { + ...theme.heading.heading05, + fontWeight: 600, + }, +}); diff --git a/src/shared/component/Header/Header.tsx b/src/shared/component/Header/Header.tsx new file mode 100644 index 00000000..2d3037c2 --- /dev/null +++ b/src/shared/component/Header/Header.tsx @@ -0,0 +1,24 @@ +import { useLocation } from 'react-router-dom'; + +import Heading from '@/common/component/Heading/Heading'; + +import { headerStyle } from '@/shared/component/Header/Header.style'; + +const Header = () => { + /** TODO: 추후 global State 혹은 localStorage에 저장 */ + const title = 'TIKI 워크스페이스'; + + const { pathname } = useLocation(); + + const hasNoSidebar = pathname !== '/archiving'; + + return ( + hasNoSidebar && ( +
+ {title} +
+ ) + ); +}; + +export default Header; diff --git a/src/shared/component/SideNavBar/LeftSidebar.tsx b/src/shared/component/SideNavBar/LeftSidebar.tsx index 960af532..5f25a05d 100644 --- a/src/shared/component/SideNavBar/LeftSidebar.tsx +++ b/src/shared/component/SideNavBar/LeftSidebar.tsx @@ -11,6 +11,7 @@ import TikiLogo from '@/common/asset/svg/logo_symbol.svg?react'; import Menu from '@/common/component/Menu/Menu'; import MenuItem from '@/common/component/Menu/MenuItem/MenuItem'; import MenuList from '@/common/component/Menu/MenuList/MenuList'; +import ToolTip from '@/common/component/ToolTip/ToolTip'; import { useOverlay } from '@/common/hook'; import { useOutsideClick } from '@/common/hook/useOutsideClick'; @@ -77,12 +78,15 @@ const LeftSidebar = () => {