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
33 changes: 22 additions & 11 deletions src/common/component/Mandalart/Mandalart.css.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
import { style } from '@vanilla-extract/css';

export const gridDefault = style({
const baseGrid = {
display: 'grid',
gridTemplateColumns: 'repeat(3, 1fr)',
gap: '1.6rem',
width: 'fit-content',
gap: '1.2rem',
margin: '0 auto',
});

export const gridSmall = style({
display: 'grid',
gridTemplateColumns: 'repeat(3, 1fr)',
gap: '2rem',
width: 'fit-content',
margin: '0 auto',
});
};

export const grid = {
TODO_SUB: style({
...baseGrid,
gap: '1rem',
}),
TODO_MAIN: style({
...baseGrid,
gap: '1.6rem',
}),
TODO_EDIT: style({
...baseGrid,
gap: '2rem',
}),
MY_MANDAL: style({
...baseGrid,
gap: '3rem',
}),
};
122 changes: 46 additions & 76 deletions src/common/component/Mandalart/Mandalart.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react-vite';

import Mandalart, { type Cycle } from './Mandalart';
import Mandalart from './Mandalart';
import { MOCK_MANDALART_DATA } from './mock';

const meta = {
Expand All @@ -13,95 +13,65 @@ const meta = {
},
},
tags: ['autodocs'],
argTypes: {
type: {
control: 'select',
options: ['TODO_SUB', 'TODO_MAIN', 'TODO_EDIT', 'MY_MANDAL'],
},
},
Comment on lines +16 to +21
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5) 스토리북에서 직접 타입을 선택할 수 있게 한 게 너무 좋네요 !! 컴포넌트 테스트가 훨씬 편해질 것 같아요 ㅡㅡ

} satisfies Meta<typeof Mandalart>;

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

const CUSTOM_GOALS = {
mainGoal: '나인도트 1등하기',
subGoals: [
{
title: '이현준 갈구기',
position: 0,
cycle: 'DAILY' as Cycle,
},
{
title: '매일 운동하기',
position: 1,
cycle: 'DAILY' as Cycle,
},
{
title: '일찍 일어나기',
position: 2,
cycle: 'DAILY' as Cycle,
},
{
title: '계획 세우기',
position: 3,
cycle: 'WEEKLY' as Cycle,
},
{
title: '시간 관리하기',
position: 4,
cycle: 'WEEKLY' as Cycle,
},
{
title: '건강 관리하기',
position: 5,
cycle: 'DAILY' as Cycle,
},
{
title: '긍정적으로 생각하기',
position: 6,
cycle: 'DAILY' as Cycle,
},
{
title: '꾸준히 노력하기',
position: 7,
cycle: 'DAILY' as Cycle,
},
],
completedGoals: [1, 3, 5],
export const Default: Story = {
args: {
mainGoal: MOCK_MANDALART_DATA.mainGoal,
subGoals: MOCK_MANDALART_DATA.subGoals,
type: 'TODO_MAIN',
},
};

export const Default: Story = {
export const AllTypes: Story = {
args: {
mainGoal: '메인 목표를 입력하세요',
mainGoal: MOCK_MANDALART_DATA.mainGoal,
subGoals: MOCK_MANDALART_DATA.subGoals,
type: 'TODO_MAIN',
},
render: (args) => (
<div style={{ display: 'flex', gap: '2rem' }}>
render: () => (
<div style={{ display: 'flex', flexDirection: 'column', gap: '4rem' }}>
<div>
<h3 style={{ color: 'white', marginBottom: '1rem' }}>Default 사이즈</h3>
<Mandalart {...args} />
<h3 style={{ marginBottom: '1rem' }}>TODO_SUB (96px)</h3>
<Mandalart
mainGoal={MOCK_MANDALART_DATA.mainGoal}
subGoals={MOCK_MANDALART_DATA.subGoals}
type="TODO_SUB"
/>
</div>
<div>
<h3 style={{ color: 'white', marginBottom: '1rem' }}>Small 사이즈</h3>
<Mandalart {...args} size="small" />
<h3 style={{ marginBottom: '1rem' }}>TODO_MAIN (196px)</h3>
<Mandalart
mainGoal={MOCK_MANDALART_DATA.mainGoal}
subGoals={MOCK_MANDALART_DATA.subGoals}
type="TODO_MAIN"
/>
</div>
<div>
<h3 style={{ marginBottom: '1rem' }}>TODO_EDIT (160px)</h3>
<Mandalart
mainGoal={MOCK_MANDALART_DATA.mainGoal}
subGoals={MOCK_MANDALART_DATA.subGoals}
type="TODO_EDIT"
/>
</div>
<div>
<h3 style={{ marginBottom: '1rem' }}>MY_MANDAL (298px)</h3>
<Mandalart
mainGoal={MOCK_MANDALART_DATA.mainGoal}
subGoals={MOCK_MANDALART_DATA.subGoals}
type="MY_MANDAL"
/>
</div>
</div>
),
};

export const Small: Story = {
args: {
mainGoal: '메인 목표를 입력하세요',
subGoals: CUSTOM_GOALS.subGoals,
size: 'small',
},
render: (args) => <Mandalart {...args} />,
};

export const WithCustomGoals: Story = {
args: CUSTOM_GOALS,
render: (args) => <Mandalart {...args} />,
};

export const WithCustomGoalsSmall: Story = {
args: {
...CUSTOM_GOALS,
size: 'small',
},
render: (args) => <Mandalart {...args} />,
};
19 changes: 11 additions & 8 deletions src/common/component/Mandalart/Mandalart.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useState } from 'react';

import { Square } from './Square';
import { Main, Sub } from './Square';
import * as styles from './Mandalart.css';
import { MOCK_MANDALART_DATA } from './mock';

export type Cycle = 'DAILY' | 'WEEKLY' | 'ONCE';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3) 여기 부분은 다른 컴포넌트에서도 사용돼서 타입으로 따로 분리해주셔도 좋을 것 같아요 ..!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 따로 이슈 파서 진행하는 게 좋을 것 같아요!
새봄 님이 만드신 CycleDropDown에서 사용돼서 한꺼번에 수정하도록 하겠습니다람쥐

export type MandalartSize = 'small' | 'default';
export type MandalartType = 'TODO_SUB' | 'TODO_MAIN' | 'TODO_EDIT' | 'MY_MANDAL';

export interface SubGoal {
title: string;
Expand All @@ -16,37 +16,40 @@ export interface SubGoal {
interface MandalartProps {
mainGoal?: string;
subGoals?: SubGoal[];
size?: MandalartSize;
type: MandalartType;
onGoalClick?: (position: number) => void;
}

const CENTER_INDEX = 4;

const Mandalart = ({
mainGoal = MOCK_MANDALART_DATA.mainGoal,
subGoals = MOCK_MANDALART_DATA.subGoals,
size = 'default',
type,
onGoalClick,
}: MandalartProps) => {
const [selectedGoal, setSelectedGoal] = useState<number | null>(null);

const handleGoalClick = (position: number) => {
setSelectedGoal(selectedGoal === position ? null : position);
onGoalClick?.(position);
};
Comment on lines 33 to 36
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3) onGoalClick 호출을 상태 업데이트 전에 하는 게 좋지 않을까요 ?? 부모 컴포넌트에서 최신 상태를 받을 수 있도록 하면 좋을 것 같다는 생각이 들었습니다 !!


const renderSquare = (index: number) => {
if (index === CENTER_INDEX) {
return <Square.Main key={index} content={mainGoal} size={size} />;
return <Main key={index} content={mainGoal} type={type} />;
}

const subGoalIndex = index > CENTER_INDEX ? index - 1 : index;
const subGoal = subGoals[subGoalIndex];

return (
<Square.Sub
<Sub
key={index}
content={subGoal.title}
isCompleted={selectedGoal === subGoalIndex}
onClick={() => handleGoalClick(subGoalIndex)}
size={size}
type={type}
/>
);
};
Expand All @@ -55,7 +58,7 @@ const Mandalart = ({
.fill(null)
.map((_, index) => renderSquare(index));

return <div className={size === 'small' ? styles.gridSmall : styles.gridDefault}>{squares}</div>;
return <div className={styles.grid[type]}>{squares}</div>;
};

export default Mandalart;
Loading