Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .github/workflows/publish-storybook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ name: Publish Storybook
# https://www.chromatic.com/docs/github-actions/

on:
push:
branches:
- main
workflow_dispatch:
inputs:
pr_number:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export const LockedCharacterCard = styled(CardContainerBase)`
padding-bottom: 2.25rem; /* 의도적으로 토큰으로 정의되지 않은 값 사용 */
padding-left: ${getToken('padding.5')};
padding-right: ${getToken('padding.5')};
border: 1px dashed #d2d4d5; /* HACK: 토큰에 정의되어 있지 않아 임시로 하드코딩함 */
border: 1px dashed ${getToken('border.normal')};
opacity: 0.5;
`;

export const CharacterImage = styled.img`
Expand Down
4 changes: 2 additions & 2 deletions src/features/character-management/ui/CharacterItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import * as S from './index.styles';
function LockedCharacterCard() {
return (
<S.LockedCharacterCard aria-label="잠긴 캐릭터">
{/* HACK : 정의되지 않은 토큰이라 #D2D4D5를 그대로 사용 */}
<Certified width={62} color="#D2D4D5" />
{/* HACK: gray.90(#c7c9cb)에 대응하는 아이콘용 semantic 토큰 없음 */}
<Certified width={62} color="#c7c9cb" />
</S.LockedCharacterCard>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,5 @@ export const Star = styled(SvgStar)<{ $active: boolean }>`
color: ${({ $active }) =>
$active
? getToken('fg.accent-yellow.normal')
: // HACK: 비활성 별 색상(구 gray[100]=#d2d4d5)에 대응하는 semantic 토큰이 없어 근사값 사용
getToken('fg.inverse.neutral')};
: getToken('fill.alternative')};
`;
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { useState } from 'react';
import {
ActionArea,
BottomSheet,
Button,
Input,
Keypad,
KeyValue,
Chip,
PriceDisplay,
} from '@/shared/design-system/ui';
import {
Expand Down Expand Up @@ -86,18 +86,14 @@ function ExpenseAmountInput({
<PriceDisplay value={formattedInput} />
<S.QuickAddContainer>
{QUICK_ADD_BUTTONS.map(({ label, amount }) => (
<Button
<Chip
key={amount}
label={label}
variant="unselected"
onClick={() => handleQuickAdd(amount)}
variant="secondary"
size="small"
>
{label}
</Button>
/>
))}
<Button onClick={handleClearInput} variant="red" size="small">
전체삭제
</Button>
<Chip label="전체삭제" variant="red" onClick={handleClearInput} />
</S.QuickAddContainer>
<Keypad onPress={handleKeypadPress} />
<ActionArea
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
Accordion,
useAccordionContext,
NameChip,
Chip,
} from '@/shared/design-system/ui';
import SvgCarbonEdit from '@/shared/assets/svgs/icon/CarbonEdit';
import SvgClose from '@/shared/assets/svgs/icon/Close';
Expand Down Expand Up @@ -83,7 +83,7 @@ function SettlementSummary({
<Accordion.Content>
<S.MemberChipList>
{memberExpenses.map((member) => (
<NameChip
<Chip
key={member.id}
label={
member.role === 'MANAGER'
Expand Down
6 changes: 1 addition & 5 deletions src/pages/expenseDetail/ui/ExpenseMemberItem/index.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,7 @@ export const TextButtonWrapper = styled.button<{ $isActive: boolean }>`
align-items: center;
cursor: pointer;
color: ${({ $isActive }) =>
$isActive
? getToken('fg.primary.normal')
: getToken(
'fill.normal-disable'
)}; /* HACK: #ACAFB2로 정의된 토큰이 없어 의미상 유사한 토큰을 임의로 사용함 */
$isActive ? getToken('fg.primary.normal') : getToken('fg.normal-disable')};
> svg {
display: ${({ $isActive }) => ($isActive ? 'block' : 'none')};
}
Expand Down
4 changes: 2 additions & 2 deletions src/pages/expenseDetail/ui/ExpenseTimelineContent/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NameChip } from '@/shared/design-system/ui';
import { Chip } from '@/shared/design-system/ui';
import { ExpenseDetail } from '@/entities/expense/model/expense.type';
import * as S from './index.styles';

Expand All @@ -21,7 +21,7 @@ function ExpenseTimelineContent({ expense }: ExpenseTimelineContentProps) {
</S.MemberChipHeader>
<S.MemberChipList>
{expense.groupMembers.map((name) => (
<NameChip key={name} label={name} variant="black" size="s" />
<Chip key={name} label={name} variant="black" size="s" />
))}
</S.MemberChipList>
</S.MemberChipContainer>
Expand Down
50 changes: 12 additions & 38 deletions src/shared/design-system/ui/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,35 +43,28 @@ type Story = StoryObj<typeof Button>;

export const Default: Story = {};

const gridStyle = {
display: 'grid',
gridTemplateColumns: '3rem repeat(6, auto)',
gap: 8,
alignItems: 'center',
justifyItems: 'start',
} as const;

export const Showcase: Story = {
render: () => (
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
<div
style={{
display: 'grid',
gridTemplateColumns: '3rem repeat(5, auto)',
gap: 8,
alignItems: 'center',
}}
>
<div style={gridStyle}>
<span />
{VARIANTS.map((variant) => (
<span key={variant} style={{ fontSize: 12, textAlign: 'center' }}>
<span key={variant} style={{ fontSize: 12 }}>
{variant}
</span>
))}
<span style={{ fontSize: 12, textAlign: 'center' }}>disabled</span>
<span style={{ fontSize: 12 }}>disabled</span>
</div>
{SIZES.map((size) => (
<div
key={size}
style={{
display: 'grid',
gridTemplateColumns: '3rem repeat(5, auto)',
gap: 8,
alignItems: 'center',
}}
>
<div key={size} style={gridStyle}>
<span style={{ fontSize: 12, fontWeight: 'bold' }}>{size}</span>
{VARIANTS.map((variant) => (
<Button key={variant} variant={variant} size={size}>
Expand All @@ -86,22 +79,3 @@ export const Showcase: Story = {
</div>
),
};

export const Disabled: Story = {
render: () => (
<div
style={{
display: 'flex',
gap: 8,
flexWrap: 'wrap',
alignItems: 'center',
}}
>
{VARIANTS.map((variant) => (
<Button key={variant} variant={variant} disabled>
label
</Button>
))}
</div>
),
};
4 changes: 3 additions & 1 deletion src/shared/design-system/ui/Button/Button.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ const sizeStyles = {
medium: css`
padding: ${getToken('padding.4')} ${getToken('padding.5')};
${applyTypography('typography.body.medium-semibold')}
border-radius: ${getToken('radius.lg')};
`,
small: css`
padding: ${getToken('padding.3')} ${getToken('padding.5')};
${applyTypography('typography.body.small-semibold')}
border-radius: ${getToken('radius.lg')};
`,
xsmall: css`
height: 1.75rem;
padding: 0 ${getToken('padding.4')};
${applyTypography('typography.caption.small-medium')}
border-radius: ${getToken('radius.md')};
`,
};

Expand Down Expand Up @@ -64,7 +67,6 @@ export const Button = styled.button<StyledButtonProps>`
justify-content: center;
align-items: center;
gap: ${getToken('gap.2')};
border-radius: ${getToken('radius.full')};
border: none;
cursor: pointer;
white-space: nowrap;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import type { Meta, StoryObj } from '@storybook/react';
import { NameChip } from './NameChip';
import type { NameChipVariant, NameChipSize } from './NameChip';
import { Chip } from './Chip';
import type { ChipVariant, ChipSize } from './Chip';

const VARIANTS: NameChipVariant[] = [
const VARIANTS: ChipVariant[] = [
'selected',
'unselected',
'disabled',
'red',
'black',
];
const SIZES: NameChipSize[] = ['m', 's'];
const SIZES: ChipSize[] = ['m', 's'];

const meta: Meta<typeof NameChip> = {
title: 'Components/NameChip',
component: NameChip,
const meta: Meta<typeof Chip> = {
title: 'Components/Chip',
component: Chip,
tags: ['autodocs'],
argTypes: {
variant: {
Expand All @@ -36,7 +36,7 @@ const meta: Meta<typeof NameChip> = {
};

export default meta;
type Story = StoryObj<typeof NameChip>;
type Story = StoryObj<typeof Chip>;

export const Default: Story = {};

Expand All @@ -50,11 +50,30 @@ export const Showcase: Story = {
>
<span style={{ width: 16, fontSize: 12 }}>{size}</span>
{VARIANTS.map((variant) => (
<NameChip
<Chip key={variant} variant={variant} size={size} label="김모또" />
))}
</div>
))}
</div>
),
};

export const AsButton: Story = {
render: () => (
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
{SIZES.map((size) => (
<div
key={size}
style={{ display: 'flex', gap: 8, alignItems: 'center' }}
>
<span style={{ width: 16, fontSize: 12 }}>{size}</span>
{VARIANTS.map((variant) => (
<Chip
key={variant}
variant={variant}
size={size}
label="김모또"
onClick={() => alert(`${variant} 클릭`)}
/>
))}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import {
applyTypography,
} from '@/shared/design-system';

interface StyledNameChipProps {
interface StyledChipProps {
$variant: 'selected' | 'unselected' | 'disabled' | 'red' | 'black';
$size: 'm' | 's';
$clickable?: boolean;
}

// HACK: s size는 12px Medium이지만 해당 semantic token 없음.
Expand Down Expand Up @@ -52,13 +53,19 @@ const variantStyles = {
`,
};

export const Chip = styled.div<StyledNameChipProps>`
export const ChipRoot = styled.div<StyledChipProps>`
display: inline-flex;
align-items: center;
justify-content: center;
gap: ${getToken('gap.1')};
border-radius: ${getToken('radius.full')};
white-space: nowrap;
${({ $clickable }) =>
$clickable &&
css`
border: none;
cursor: pointer;
`}
${({ $size }) => sizeStyles[$size]}
${({ $variant }) => variantStyles[$variant]}
`;
31 changes: 31 additions & 0 deletions src/shared/design-system/ui/Chip/Chip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { MouseEventHandler } from 'react';
import * as S from './Chip.styles';

type ChipVariant = 'selected' | 'unselected' | 'disabled' | 'red' | 'black';
type ChipSize = 'm' | 's';

interface ChipProps {
label: string;
variant?: ChipVariant;
size?: ChipSize;
onClick?: MouseEventHandler<HTMLButtonElement>;
}

function Chip(props: ChipProps) {
const { label, variant = 'selected', size = 'm', onClick } = props;

return (
<S.ChipRoot
as={onClick ? 'button' : 'div'}
$variant={variant}
$size={size}
$clickable={!!onClick}
onClick={onClick}
>
{label}
</S.ChipRoot>
);
}

export { Chip };
export type { ChipProps, ChipVariant, ChipSize };
2 changes: 2 additions & 0 deletions src/shared/design-system/ui/Chip/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Chip } from './Chip';
export type { ChipProps, ChipVariant, ChipSize } from './Chip';
20 changes: 20 additions & 0 deletions src/shared/design-system/ui/Input/Input.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const meta: Meta<InputProps> = {
label: { control: 'text' },
required: { control: 'boolean' },
placeholder: { control: 'text' },
helpText: { control: 'text' },
value: { control: 'text' },
},
args: {
Expand Down Expand Up @@ -56,6 +57,25 @@ export const Showcase: Story = {
),
};

export const WithHelpText: Story = {
render: () => (
<div
style={{ display: 'flex', flexDirection: 'column', gap: 32, width: 350 }}
>
{STATES.map((state) => (
<Input
key={state}
label={state}
required
placeholder="placeholder"
state={state}
helpText="메시지를 입력해주세요."
/>
))}
</div>
),
};

export const PriceVariant: Story = {
render: () => (
<div
Expand Down
Loading
Loading