From 918a2bc3e5ac8cce48682e400baf9e2378a490f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A0=95=EC=9B=90?= Date: Tue, 10 Feb 2026 03:36:25 +0900 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20=EC=82=AC=EC=9D=B4=EB=93=9C=EB=B0=94?= =?UTF-8?q?=20=EC=97=B4=EB=A6=AC=EA=B3=A0=20=EB=8B=AB=ED=9E=90=EB=95=8C=20?= =?UTF-8?q?=EB=AA=A8=EC=85=98=20=EC=B6=94=EA=B0=80,=20Gnb=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=ED=99=9C=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 23 +++--- pnpm-lock.yaml | 38 ++++++++++ src/components/sidebar/Sidebar.stories.tsx | 4 +- src/components/sidebar/Sidebar.tsx | 75 +++++++++++++++---- .../sidebar/styles/Sidebar.module.css | 3 +- 5 files changed, 113 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index aa4ec8f..774e4bd 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "clsx": "^2.1.1", + "framer-motion": "^12.34.0", "next": "16.1.3", "react": "19.2.3", "react-calendar": "^6.0.0", @@ -26,31 +27,31 @@ "zod": "^4.3.5" }, "devDependencies": { + "@chromatic-com/storybook": "^5.0.0", "@commitlint/cli": "^20.3.1", "@commitlint/config-conventional": "^20.3.1", + "@storybook/addon-a11y": "^10.2.3", + "@storybook/addon-docs": "^10.2.3", + "@storybook/addon-vitest": "^10.2.3", + "@storybook/nextjs-vite": "^10.2.3", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "@vitest/browser-playwright": "^4.0.18", + "@vitest/coverage-v8": "^4.0.18", "eslint": "^9", "eslint-config-next": "16.1.3", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.5.5", + "eslint-plugin-storybook": "^10.2.3", "husky": "^9.1.7", "lint-staged": "^16.2.7", + "playwright": "^1.58.1", "prettier": "^3.8.0", - "typescript": "^5", "storybook": "^10.2.3", - "@storybook/nextjs-vite": "^10.2.3", - "@chromatic-com/storybook": "^5.0.0", - "@storybook/addon-vitest": "^10.2.3", - "@storybook/addon-a11y": "^10.2.3", - "@storybook/addon-docs": "^10.2.3", + "typescript": "^5", "vite": "^7.3.1", - "eslint-plugin-storybook": "^10.2.3", - "vitest": "^4.0.18", - "playwright": "^1.58.1", - "@vitest/browser-playwright": "^4.0.18", - "@vitest/coverage-v8": "^4.0.18" + "vitest": "^4.0.18" }, "lint-staged": { "*.{ts,tsx,js,jsx}": [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 81805e3..3d792c8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ importers: clsx: specifier: ^2.1.1 version: 2.1.1 + framer-motion: + specifier: ^12.34.0 + version: 12.34.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) next: specifier: 16.1.3 version: 16.1.3(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -2024,6 +2027,20 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + framer-motion@12.34.0: + resolution: {integrity: sha512-+/H49owhzkzQyxtn7nZeF4kdH++I2FWrESQ184Zbcw5cEqNHYkE5yxWxcTLSj5lNx3NWdbIRy5FHqUvetD8FWg==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -2557,6 +2574,12 @@ packages: module-alias@2.2.3: resolution: {integrity: sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==} + motion-dom@12.34.0: + resolution: {integrity: sha512-Lql3NuEcScRDxTAO6GgUsRHBZOWI/3fnMlkMcH5NftzcN37zJta+bpbMAV9px4Nj057TuvRooMK7QrzMCgtz6Q==} + + motion-utils@12.29.2: + resolution: {integrity: sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A==} + mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} @@ -5427,6 +5450,15 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + framer-motion@12.34.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + motion-dom: 12.34.0 + motion-utils: 12.29.2 + tslib: 2.8.1 + optionalDependencies: + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + fsevents@2.3.2: optional: true @@ -5930,6 +5962,12 @@ snapshots: module-alias@2.2.3: {} + motion-dom@12.34.0: + dependencies: + motion-utils: 12.29.2 + + motion-utils@12.29.2: {} + mrmime@2.0.1: {} ms@2.1.3: {} diff --git a/src/components/sidebar/Sidebar.stories.tsx b/src/components/sidebar/Sidebar.stories.tsx index e4b0a3a..586f5ef 100644 --- a/src/components/sidebar/Sidebar.stories.tsx +++ b/src/components/sidebar/Sidebar.stories.tsx @@ -4,7 +4,7 @@ import Image from 'next/image'; import Sidebar from './Sidebar'; import SidebarButton from './SidebarButton'; import SidebarTeamSelect from './SidebarTeamSelect'; -import SidebarAddButton from './SidebarAddButton'; +import GnbAddButton from '@/components/Button/domain/GnbAddButton/GnbAddButton'; import chessSmall from '@/assets/icons/chess/chessSmall.svg'; import chessBig from '@/assets/icons/chess/chessBig.svg'; import boardSmall from '@/assets/icons/board/boardSmall.svg'; @@ -41,7 +41,7 @@ export const LoggedIn: Story = { ), addButton: (isCollapsed: boolean) => ( <> - {!isCollapsed && } + {!isCollapsed && {}} />}
+
- {isCollapsed ? ( - COWORKERS - ) : ( - COWORKERS - )} + + {isCollapsed ? ( + + COWORKERS + + ) : ( + + COWORKERS + + )} +
- {teamSelect && (typeof teamSelect === 'function' ? teamSelect(isCollapsed) : teamSelect)} - {typeof children === 'function' ? children(isCollapsed) : children} - {addButton && (typeof addButton === 'function' ? addButton(isCollapsed) : addButton)} + + + {teamSelect && + (typeof teamSelect === 'function' ? teamSelect(isCollapsed) : teamSelect)} + {typeof children === 'function' ? children(isCollapsed) : children} + {addButton && (typeof addButton === 'function' ? addButton(isCollapsed) : addButton)} + +
{footer ? (
@@ -68,14 +103,22 @@ export default function Sidebar({ ) : profileImage ? (
{profileImage}
- {!isCollapsed && ( -
- {profileName} - {profileTeam} -
- )} + + {!isCollapsed && ( + + {profileName} + {profileTeam} + + )} +
) : null} - + ); } diff --git a/src/components/sidebar/styles/Sidebar.module.css b/src/components/sidebar/styles/Sidebar.module.css index 7d29474..1262980 100644 --- a/src/components/sidebar/styles/Sidebar.module.css +++ b/src/components/sidebar/styles/Sidebar.module.css @@ -5,6 +5,7 @@ display: flex; flex-direction: column; background: var(--color-background-inverse); + overflow: hidden; } @media (max-width: 767px) { @@ -14,7 +15,6 @@ } .collapsed { - width: 72px; position: relative; } @@ -64,6 +64,7 @@ padding: 0 16px; gap: 8px; flex: 1; + white-space: nowrap; } .collapsed .content { From 61285dcb9519d160348d080c42b6220f45cb9afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A0=95=EC=9B=90?= Date: Tue, 10 Feb 2026 03:38:23 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=EC=82=AC=EC=9D=B4=EB=93=9C=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC=20=EB=B2=84=ED=8A=BC=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/sidebar/styles/Sidebar.module.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/sidebar/styles/Sidebar.module.css b/src/components/sidebar/styles/Sidebar.module.css index 1262980..ea5d6dd 100644 --- a/src/components/sidebar/styles/Sidebar.module.css +++ b/src/components/sidebar/styles/Sidebar.module.css @@ -5,7 +5,6 @@ display: flex; flex-direction: column; background: var(--color-background-inverse); - overflow: hidden; } @media (max-width: 767px) { @@ -65,6 +64,7 @@ gap: 8px; flex: 1; white-space: nowrap; + overflow: hidden; } .collapsed .content { From df4a74514744216c0c47722490a36521e5d075cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A0=95=EC=9B=90?= Date: Tue, 10 Feb 2026 15:04:44 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20=EB=A0=8C=EB=8D=94=EB=A7=81=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=A4=91=EB=B3=B5=20=ED=97=AC=ED=8D=BC=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=EB=A5=BC=20=ED=86=B5=ED=95=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/input/AccountInput.stories.tsx | 74 +++++++++++ .../input/ActionTextArea.stories.tsx | 54 ++++++++ .../input/ChangePassword.stories.tsx | 116 ++++++++++++++++++ src/components/input/CommentInput.stories.tsx | 42 +++++++ src/components/input/TextArea.stories.tsx | 65 ++++++++++ src/components/sidebar/Sidebar.tsx | 18 +-- 6 files changed, 362 insertions(+), 7 deletions(-) create mode 100644 src/components/input/AccountInput.stories.tsx create mode 100644 src/components/input/ActionTextArea.stories.tsx create mode 100644 src/components/input/ChangePassword.stories.tsx create mode 100644 src/components/input/CommentInput.stories.tsx create mode 100644 src/components/input/TextArea.stories.tsx diff --git a/src/components/input/AccountInput.stories.tsx b/src/components/input/AccountInput.stories.tsx new file mode 100644 index 0000000..f9c41cd --- /dev/null +++ b/src/components/input/AccountInput.stories.tsx @@ -0,0 +1,74 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; + +import AccountInput from './AccountInput'; + +const meta = { + title: 'Components/AccountInput', + component: AccountInput, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + args: { + email: 'user@example.com', + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const WithButton: Story = { + args: { + email: 'user@example.com', + children: ( + + ), + }, +}; + +export const Overview: Story = { + render: () => ( +
+ + + + +
+ ), + parameters: { + controls: { disable: true }, + }, +}; diff --git a/src/components/input/ActionTextArea.stories.tsx b/src/components/input/ActionTextArea.stories.tsx new file mode 100644 index 0000000..cb7ea88 --- /dev/null +++ b/src/components/input/ActionTextArea.stories.tsx @@ -0,0 +1,54 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; + +import { fn } from 'storybook/test'; + +import ActionTextArea from './ActionTextArea'; + +const meta = { + title: 'Components/ActionTextArea', + component: ActionTextArea, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + args: { + placeholder: '텍스트를 입력해 주세요.', + onSubmit: fn(), + onChange: fn(), + }, + argTypes: { + disabled: { + control: 'boolean', + }, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const WithPlaceholder: Story = { + args: { + placeholder: '댓글을 입력해 주세요.', + }, +}; + +export const Overview: Story = { + render: () => ( +
+ + +
+ ), + parameters: { + controls: { disable: true }, + }, +}; diff --git a/src/components/input/ChangePassword.stories.tsx b/src/components/input/ChangePassword.stories.tsx new file mode 100644 index 0000000..4fcb328 --- /dev/null +++ b/src/components/input/ChangePassword.stories.tsx @@ -0,0 +1,116 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; + +import { fn } from 'storybook/test'; + +import ChangePassword from './ChangePassword'; + +const meta = { + title: 'Components/ChangePassword', + component: ChangePassword, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + args: { + isEditing: false, + newPasswordProps: { + onChange: fn(), + }, + confirmPasswordProps: { + onChange: fn(), + }, + }, + argTypes: { + isEditing: { + control: 'boolean', + }, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const Editing: Story = { + args: { + isEditing: true, + }, +}; + +export const WithError: Story = { + args: { + isEditing: true, + confirmPasswordProps: { + errorMessage: '비밀번호가 일치하지 않습니다.', + }, + }, +}; + +export const WithButtons: Story = { + args: { + isEditing: true, + children: ( +
+ + +
+ ), + }, +}; + +export const Overview: Story = { + render: () => ( +
+
+

비활성 상태

+ +
+
+

편집 상태

+ +
+
+

에러 상태

+ +
+
+ ), + parameters: { + controls: { disable: true }, + }, +}; diff --git a/src/components/input/CommentInput.stories.tsx b/src/components/input/CommentInput.stories.tsx new file mode 100644 index 0000000..bb33c3d --- /dev/null +++ b/src/components/input/CommentInput.stories.tsx @@ -0,0 +1,42 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; + +import { fn } from 'storybook/test'; + +import CommentInput from './CommentInput'; + +const meta = { + title: 'Components/CommentInput', + component: CommentInput, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + args: { + placeholder: '댓글을 달아주세요.', + onSubmit: fn(), + onChange: fn(), + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const Overview: Story = { + render: () => ( +
+ +
+ ), + parameters: { + controls: { disable: true }, + }, +}; diff --git a/src/components/input/TextArea.stories.tsx b/src/components/input/TextArea.stories.tsx new file mode 100644 index 0000000..92a17bd --- /dev/null +++ b/src/components/input/TextArea.stories.tsx @@ -0,0 +1,65 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; + +import { fn } from 'storybook/test'; + +import TextArea from './TextArea'; + +const meta = { + title: 'Components/TextArea', + component: TextArea, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + args: { + placeholder: '텍스트를 입력해 주세요.', + onChange: fn(), + }, + argTypes: { + rows: { + control: 'number', + }, + disabled: { + control: 'boolean', + }, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const WithRows: Story = { + args: { + rows: 5, + placeholder: '여러 줄 입력', + }, +}; + +export const Disabled: Story = { + args: { + disabled: true, + value: '비활성 상태', + }, +}; + +export const Overview: Story = { + render: () => ( +
+