Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
7051d89
refactor: 인라인 스타일 제거
yoouyeon Dec 26, 2025
aaa6a57
chore: Storybook preview에서 Chromatic 스냅샷 기본 비활성화
yoouyeon Dec 26, 2025
5f7810f
chore: Storybook MSW 애드온 추가
yoouyeon Dec 27, 2025
ecb7743
refactor: 로그인 페이지 진입용 LoginEntranceView 컴포넌트 분리
yoouyeon Dec 27, 2025
0648d54
chore: guest·group 토큰 API에 useMock 옵션 추가
yoouyeon Dec 27, 2025
04f2861
chore: Storybook 8.6.12로 업데이트
yoouyeon Dec 27, 2025
20f17ac
test: Flex 프로퍼티 변경 전 스냅샷 기준용 Storybook 스토리 추가
yoouyeon Dec 27, 2025
64e78e7
chore: Chromatic 스냅샷 변경에 따른 PR 코멘트 로직 개선
yoouyeon Dec 27, 2025
97eb452
fix: 패딩 단위를 디자인 시스템 기준으로 수정
yoouyeon Dec 27, 2025
7127074
feat: Text 컴포넌트에 style prop 추가
yoouyeon Dec 27, 2025
7634487
style: ExpenseTimeHeader 레이아웃 구조 정리
yoouyeon Dec 27, 2025
30f522d
refactor: AddMember 레이아웃 구조 정리
yoouyeon Dec 27, 2025
8b4b01d
fix: Flex spacing 단위를 디자인 시스템 기준으로 수정
yoouyeon Dec 27, 2025
f45060a
design: HomePage 레이아웃 조정
yoouyeon Dec 27, 2025
2f1bb2b
style: LoginEntranceView gap 단위를 디자인 시스템 기준으로 수정
yoouyeon Dec 28, 2025
67a02d4
style: SelectGroupPage 레이아웃·스타일 정리
yoouyeon Dec 28, 2025
747bddc
docs: Flex 컴포넌트 사용 주석 추가
yoouyeon Dec 28, 2025
3a0c907
fix: width 속성 문법 오류 수정
yoouyeon Dec 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions .github/workflows/publish-storybook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,23 @@ jobs:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
onlyChanged: true # Only run Chromatic on changed stories

- name: Comment on PR
- name: Comment on PR (with snapshot changes)
if: steps.chromatic.outputs.changeCount != '0'
uses: thollander/actions-comment-pull-request@v3
with:
message: '✨ **Storybook preview** : ${{ steps.chromatic.outputs.storybookUrl }}'
message: |
✨ Storybook
👉 ${{ steps.chromatic.outputs.storybookUrl }}

📸 변경된 스냅샷
👉 ${{ steps.chromatic.outputs.buildUrl }}

- name: Comment on PR (no snapshot changes)
if: steps.chromatic.outputs.changeCount == '0'
uses: thollander/actions-comment-pull-request@v3
with:
message: |
✨ Storybook
👉 ${{ steps.chromatic.outputs.storybookUrl }}

✅ 스냅샷 변경 없음
9 changes: 8 additions & 1 deletion .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import type { Preview } from '@storybook/react';

import { initialize, mswLoader } from 'msw-storybook-addon';
import { ThemeProvider } from 'styled-components';
import { withThemeFromJSXProvider } from '@storybook/addon-themes';
import theme from '../src/shared/styles/theme';
import GlobalStyles from '../src/shared/styles/globalStyles';

// Initialize MSW
initialize();

const preview: Preview = {
parameters: {
chromatic: { disableSnapshot: true }, // 기본적으로 Chromatic 스냅샷 비활성화 (필요한 스토리에서만 활성화한다)
controls: {
matchers: {
color: /(background|color)$/i,
Expand All @@ -25,6 +29,9 @@ const preview: Preview = {
GlobalStyles,
}),
],

// Provide the MSW addon loader globally
loaders: [mswLoader],
};

export default preview;
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"@storybook/addon-onboarding": "^8.5.0",
"@storybook/addon-themes": "^8.5.2",
"@storybook/blocks": "^8.5.0",
"@storybook/react": "^8.5.0",
"@storybook/react": "^8.6.12",
"@storybook/react-vite": "^8.5.0",
"@storybook/test": "^8.5.0",
"@tanstack/eslint-plugin-query": "^5.68.0",
Expand Down Expand Up @@ -84,8 +84,9 @@
"eslint-plugin-storybook": "^0.11.2",
"globals": "^15.14.0",
"msw": "^2.7.0",
"msw-storybook-addon": "^2.0.6",
"prettier": "^3.4.2",
"storybook": "^8.5.0",
"storybook": "^8.6.12",
"storybook-addon-pseudo-states": "^4.0.2",
"typescript": "^5.7.3",
"typescript-eslint": "^8.18.2",
Expand Down
4 changes: 3 additions & 1 deletion src/entities/auth/api/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export interface GuestTokenData {
}

export const getGuestToken = async (): Promise<GuestTokenData> => {
const response = await axiosInstance.get('/user/guest/token');
const response = await axiosInstance.get('/user/guest/token', {
useMock: true,
});
return response.data;
};
4 changes: 3 additions & 1 deletion src/entities/group/api/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ export const getGroupHeader = (
groupToken: string
): Promise<GroupHeaderResponse> => {
return axiosInstance
.get(`/group/header?groupToken=${groupToken}`)
.get(`/group/header?groupToken=${groupToken}`, {
useMock: true,
})
.then((res) => res.data);
};

Expand Down
19 changes: 19 additions & 0 deletions src/pages/addAccountStep/ui/BankNameDrawer/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Meta, StoryObj } from '@storybook/react';
import BankNameDrawer from './index';

const meta: Meta<typeof BankNameDrawer> = {
title: 'ui/BankNameDrawer',
component: BankNameDrawer,
parameters: {
chromatic: { disableSnapshot: false },
},
};

export default meta;
type Story = StoryObj<typeof BankNameDrawer>;

export const Default: Story = {
args: {
open: true,
},
};
2 changes: 1 addition & 1 deletion src/pages/addAccountStep/ui/BankNameDrawer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function BankNameDrawer({ open, onClose, setBankName }: BankNameDrawerProps) {
<Flex
direction="column"
pt={32}
px={5}
px={20}
height="70dvh"
borderRadius={12}
width="100%"
Expand Down
1 change: 1 addition & 0 deletions src/pages/billDetail/ui/CurvedProgressBar/index.style.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import styled from 'styled-components';

export const Wrapper = styled.div`
margin-top: ${({ theme }) => theme.unit[20]};
display: flex;
justify-content: center;
align-items: center;
Expand Down
71 changes: 71 additions & 0 deletions src/pages/billDetail/ui/ExpenseTimeHeader/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Meta, StoryObj } from '@storybook/react';
import { waitFor, within } from '@storybook/test';
import { createMemoryRouter, RouterProvider } from 'react-router';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { http, HttpResponse } from 'msw';
import ExpenseTimeHeader from './index';

/**
* NOTE
* Flex 컴포넌트의 gap / padding 관련 변경에 대비해서
* 스냅샷 기준을 만들기 위해 추가한 스토리입니다.
*
* 나중에 유지보수가 과도해질 경우 삭제해도 괜찮습니다.
*/

const queryClient = new QueryClient();

const meta: Meta<typeof ExpenseTimeHeader> = {
title: 'ui/ExpenseTimeHeader',
component: ExpenseTimeHeader,
parameters: {
chromatic: { disableSnapshot: false },
msw: {
handlers: [
http.get('http://localhost:3000/api/v1/group/header', () => {
return HttpResponse.json({
groupName: '모또 정기모임',
totalAmount: 150000,
deadline: '2025-12-26T23:59:59Z',
bank: '국민은행',
accountNumber: '123456-78-910111',
});
}),
],
},
},
decorators: [
(Story) => {
const mockRouter = createMemoryRouter([
{
path: '/*',
element: <Story />,
loader: () => ({ groupToken: 'mock-group-token' }),
},
]);
return (
<QueryClientProvider client={queryClient}>
<RouterProvider router={mockRouter} />
</QueryClientProvider>
);
},
],
};

export default meta;
type Story = StoryObj<typeof ExpenseTimeHeader>;

export const Default: Story = {
args: {
totalMember: 6,
paidMember: 3,
status: 'success',
isChecked: false,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await waitFor(() => {
canvas.getByText('정산을 완료해주세요');
});
},
};
9 changes: 7 additions & 2 deletions src/pages/billDetail/ui/ExpenseTimeHeader/index.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ export const ModdoImage = styled.img`
export const ExpenseChip = styled.div`
display: flex;
background: ${({ theme }) => theme.color.semantic.primary.default};
color: ${({ theme }) => theme.color.semantic.text.inverse};
border-radius: ${({ theme }) => theme.radius.circle};
padding: ${({ theme }) => `${theme.unit[12]} ${theme.unit[20]}`};
font-size: ${TextVariant('body1Sb')};
`;

export const TotalMoney = styled.span`
Expand All @@ -56,6 +54,13 @@ export const TimeBox = styled.div`
align-items: center;
`;

export const Timer = styled.div`
display: grid;
width: 174px;
grid-template-columns: repeat(5, auto);
place-items: center;
`;

export const TimeSep = styled.span`
color: ${({ theme }) => theme.color.semantic.secondary.strong};
font-size: 1.75rem;
Expand Down
73 changes: 34 additions & 39 deletions src/pages/billDetail/ui/ExpenseTimeHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,19 +172,18 @@ function ExpenseTimeHeader({
</Flex>
}
sub={
<Flex gap={theme.unit[4]} alignItems="center">
<Flex gap={4} alignItems="center">
정산 계좌: {accountFormat}
<Button
variant="text"
onClick={() => handleCopyButtonClick(accountFormat)}
>
<Copy width={theme.unit[16]} height={theme.unit[16]} />
<Copy width={16} height={16} />
</Button>
</Flex>
}
bgColor="semantic.background.normal.alternative"
/>
<div style={{ height: `${theme.unit[20]}` }} />
<CurvedProgressBar percentage={percentage}>
<S.ModdoButton onClick={handleModdoButtonClick}>
<S.ModdoImage src={StatusContent[status].image} />
Expand All @@ -195,10 +194,13 @@ function ExpenseTimeHeader({
width="32"
style={{ paddingRight: `${theme.unit[8]}` }}
/>
<Text as="p" variant="body1Sb" color="semantic.orange.default">
<Text variant="body1Sb" color="semantic.orange.default">
{paidMember}
</Text>
{`/${totalMember} 정산 완료`}
<Text
variant="body1Sb"
color="semantic.text.inverse"
>{`/${totalMember} 정산 완료`}</Text>
</S.ExpenseChip>
<Crown
width={theme.unit[24]}
Expand All @@ -209,45 +211,38 @@ function ExpenseTimeHeader({
{(headerData?.totalAmount ?? 0).toLocaleString('ko-KR')}원
</S.TotalMoney>
</CurvedProgressBar>
<Flex
direction="column"
pl={theme.unit[20]}
pr={theme.unit[20]}
gap={theme.unit[12]}
>
<Flex direction="column" px={20} gap={12}>
<Text variant="body1Sb" color="semantic.text.strong">
정산 마감까지 남은 시간
</Text>
<S.TimeBox>
<Flex direction="column" width={174} alignItems="center">
<Flex justifyContent="center" alignItems="center">
{([hours, minutes, seconds] as number[]).map(
(time, index, arr) => (
// eslint-disable-next-line react/no-array-index-key
<React.Fragment key={index}>
<Text
variant="heading1"
color={
status === 'failure'
? 'semantic.state.danger'
: 'semantic.text.strong'
}
>
{String(time).padStart(2, '0')}
</Text>
{index < arr.length - 1 && <S.TimeSep>:</S.TimeSep>}
</React.Fragment>
)
)}
</Flex>
<Flex justifyContent="space-between" width="100%" pl={2.5} pr={2.5}>
{['시', '분', '초'].map((label) => (
<Text key={label} color="semantic.text.subtle">
{label}
<S.Timer>
{([hours, minutes, seconds] as number[]).map((time, index, arr) => (
// eslint-disable-next-line react/no-array-index-key
<React.Fragment key={index}>
<Text
variant="heading1"
color={
status === 'failure'
? 'semantic.state.danger'
: 'semantic.text.strong'
}
>
{String(time).padStart(2, '0')}
</Text>
))}
</Flex>
</Flex>
{index < arr.length - 1 && <S.TimeSep>:</S.TimeSep>}
</React.Fragment>
))}
{['시', '분', '초'].map((label, idx) => (
<Text
key={label}
color="semantic.text.subtle"
style={{ gridColumn: idx * 2 + 1 }}
>
{label}
</Text>
))}
</S.Timer>
</S.TimeBox>
</Flex>
<Modal
Expand Down
27 changes: 27 additions & 0 deletions src/pages/home/HomePage.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Meta, StoryObj } from '@storybook/react';
import { createMemoryRouter, RouterProvider } from 'react-router';
import HomePage from './HomePage';

const meta: Meta<typeof HomePage> = {
title: 'pages/HomePage',
component: HomePage,
parameters: {
chromatic: { disableSnapshot: false },
},
decorators: [
(Story) => {
const mockRouter = createMemoryRouter([
{
path: '/*',
element: <Story />,
},
]);
return <RouterProvider router={mockRouter} />;
},
],
};

export default meta;
type Story = StoryObj<typeof HomePage>;

export const Default: Story = {};
Loading