diff --git a/src/common/component/Mandalart/Mandalart.css.ts b/src/common/component/Mandalart/Mandalart.css.ts index bfd216d2..90ae18dc 100644 --- a/src/common/component/Mandalart/Mandalart.css.ts +++ b/src/common/component/Mandalart/Mandalart.css.ts @@ -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', + }), +}; diff --git a/src/common/component/Mandalart/Mandalart.stories.tsx b/src/common/component/Mandalart/Mandalart.stories.tsx index fae6f167..96489ebb 100644 --- a/src/common/component/Mandalart/Mandalart.stories.tsx +++ b/src/common/component/Mandalart/Mandalart.stories.tsx @@ -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 = { @@ -13,95 +13,65 @@ const meta = { }, }, tags: ['autodocs'], + argTypes: { + type: { + control: 'select', + options: ['TODO_SUB', 'TODO_MAIN', 'TODO_EDIT', 'MY_MANDAL'], + }, + }, } satisfies Meta; export default meta; type Story = StoryObj; -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) => ( -
+ render: () => ( +
-

Default 사이즈

- +

TODO_SUB (96px)

+
-

Small 사이즈

- +

TODO_MAIN (196px)

+ +
+
+

TODO_EDIT (160px)

+ +
+
+

MY_MANDAL (298px)

+
), }; - -export const Small: Story = { - args: { - mainGoal: '메인 목표를 입력하세요', - subGoals: CUSTOM_GOALS.subGoals, - size: 'small', - }, - render: (args) => , -}; - -export const WithCustomGoals: Story = { - args: CUSTOM_GOALS, - render: (args) => , -}; - -export const WithCustomGoalsSmall: Story = { - args: { - ...CUSTOM_GOALS, - size: 'small', - }, - render: (args) => , -}; diff --git a/src/common/component/Mandalart/Mandalart.tsx b/src/common/component/Mandalart/Mandalart.tsx index c9978e05..06a51d84 100644 --- a/src/common/component/Mandalart/Mandalart.tsx +++ b/src/common/component/Mandalart/Mandalart.tsx @@ -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'; -export type MandalartSize = 'small' | 'default'; +export type MandalartType = 'TODO_SUB' | 'TODO_MAIN' | 'TODO_EDIT' | 'MY_MANDAL'; export interface SubGoal { title: string; @@ -16,7 +16,8 @@ export interface SubGoal { interface MandalartProps { mainGoal?: string; subGoals?: SubGoal[]; - size?: MandalartSize; + type: MandalartType; + onGoalClick?: (position: number) => void; } const CENTER_INDEX = 4; @@ -24,29 +25,31 @@ 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(null); const handleGoalClick = (position: number) => { setSelectedGoal(selectedGoal === position ? null : position); + onGoalClick?.(position); }; const renderSquare = (index: number) => { if (index === CENTER_INDEX) { - return ; + return
; } const subGoalIndex = index > CENTER_INDEX ? index - 1 : index; const subGoal = subGoals[subGoalIndex]; return ( - handleGoalClick(subGoalIndex)} - size={size} + type={type} /> ); }; @@ -55,7 +58,7 @@ const Mandalart = ({ .fill(null) .map((_, index) => renderSquare(index)); - return
{squares}
; + return
{squares}
; }; export default Mandalart; diff --git a/src/common/component/Mandalart/Square/Square.css.ts b/src/common/component/Mandalart/Square/Square.css.ts index dfed555f..42db9f53 100644 --- a/src/common/component/Mandalart/Square/Square.css.ts +++ b/src/common/component/Mandalart/Square/Square.css.ts @@ -7,81 +7,138 @@ export const squareContainer = style({ margin: '0 auto', }); -const baseCellDefault = style({ - borderRadius: '8px', - cursor: 'pointer', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - textAlign: 'center', - width: '19.6rem', - height: '19.6rem', - boxSizing: 'border-box', -}); - -const baseCellSmall = style({ - borderRadius: '8px', - cursor: 'pointer', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - textAlign: 'center', - width: '16rem', - height: '16rem', - boxSizing: 'border-box', -}); - -export const mainCellDefault = style([ - baseCellDefault, - fonts.title03, - { - color: colors.white01, - backgroundImage: colors.gradient04, +const SQUARE_TYPES = { + TODO_SUB: { + width: '9.6rem', + height: '9.6rem', + padding: '0.6rem', + mainFont: fonts.body04, + subFont: fonts.caption01, }, -]); - -export const mainCellSmall = style([ - baseCellSmall, - fonts.subtitle01, - { - color: colors.white01, - backgroundImage: colors.gradient04, + TODO_MAIN: { + width: '19.6rem', + height: '19.6rem', padding: '1.4rem', + mainFont: fonts.title03, + subFont: fonts.subtitle01, + }, + TODO_EDIT: { + width: '16rem', + height: '16rem', + padding: '1.2rem', + mainFont: fonts.subtitle01, + subFont: fonts.subtitle05, }, -]); + MY_MANDAL: { + width: '29.8rem', + height: '29.8rem', + padding: '4.4rem', + mainFont: fonts.display02, + subFont: fonts.title01, + }, +} as const; -export const subCellDefault = style([ - baseCellDefault, - fonts.subtitle01, - { - color: colors.grey8, - background: colors.grey2, - ':hover': { - background: colors.grey3, +const createBaseCell = (type: keyof typeof SQUARE_TYPES) => + style({ + borderRadius: '8px', + cursor: 'pointer', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + textAlign: 'center', + width: SQUARE_TYPES[type].width, + height: SQUARE_TYPES[type].height, + padding: SQUARE_TYPES[type].padding, + boxSizing: 'border-box', + }); + +export const mainCell = { + TODO_SUB: style([ + createBaseCell('TODO_SUB'), + SQUARE_TYPES.TODO_SUB.mainFont, + { + color: colors.white01, + backgroundImage: colors.gradient04, + }, + ]), + TODO_MAIN: style([ + createBaseCell('TODO_MAIN'), + SQUARE_TYPES.TODO_MAIN.mainFont, + { + color: colors.white01, + backgroundImage: colors.gradient04, + }, + ]), + TODO_EDIT: style([ + createBaseCell('TODO_EDIT'), + SQUARE_TYPES.TODO_EDIT.mainFont, + { + color: colors.white01, + backgroundImage: colors.gradient04, + }, + ]), + MY_MANDAL: style([ + createBaseCell('MY_MANDAL'), + SQUARE_TYPES.MY_MANDAL.mainFont, + { + color: colors.white01, + backgroundImage: colors.gradient05, }, - selectors: { - '&[data-completed="true"]': { - border: '0.4rem solid #305088', + ]), +}; + +export const subCell = { + TODO_SUB: style([ + createBaseCell('TODO_SUB'), + SQUARE_TYPES.TODO_SUB.subFont, + { + color: colors.grey8, + background: colors.grey3, + ':hover': { background: colors.grey2, }, }, - }, -]); - -export const subCellSmall = style([ - baseCellSmall, - fonts.subtitle05, - { - color: colors.grey8, - background: colors.grey2, - ':hover': { + ]), + TODO_MAIN: style([ + createBaseCell('TODO_MAIN'), + SQUARE_TYPES.TODO_MAIN.subFont, + { + color: colors.grey8, background: colors.grey3, + ':hover': { + background: colors.grey2, + }, + selectors: { + '&[data-completed="true"]': { + border: '0.4rem solid #305088', + background: colors.grey2, + }, + }, }, - selectors: { - '&[data-completed="true"]': { - border: '0.3rem solid #305088', + ]), + TODO_EDIT: style([ + createBaseCell('TODO_EDIT'), + SQUARE_TYPES.TODO_EDIT.subFont, + { + color: colors.grey8, + background: colors.grey3, + ':hover': { background: colors.grey2, }, + selectors: { + '&[data-completed="true"]': { + border: '0.3rem solid #305088', + background: colors.grey2, + }, + }, }, - }, -]); + ]), + MY_MANDAL: style([ + createBaseCell('MY_MANDAL'), + SQUARE_TYPES.MY_MANDAL.subFont, + { + color: colors.white01, + backgroundImage: colors.gradient04, + }, + ]), +}; diff --git a/src/common/component/Mandalart/Square/Square.stories.tsx b/src/common/component/Mandalart/Square/Square.stories.tsx index 6bb5411e..a76b82cd 100644 --- a/src/common/component/Mandalart/Square/Square.stories.tsx +++ b/src/common/component/Mandalart/Square/Square.stories.tsx @@ -1,12 +1,13 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Square } from '.'; +import { Main, Sub } from '.'; +import type { MandalartType } from '../Mandalart'; import { colors } from '@/style/token'; const meta = { title: 'Components/Square', - component: Square.Main, + component: Main, parameters: { layout: 'centered', backgrounds: { @@ -14,39 +15,41 @@ const meta = { }, }, tags: ['autodocs'], -} satisfies Meta; + argTypes: { + type: { + control: 'select', + options: ['TODO_SUB', 'TODO_MAIN', 'TODO_EDIT', 'MY_MANDAL'], + }, + }, +} satisfies Meta; export default meta; type Story = StoryObj; const handleClick = () => {}; +const TypePreview = ({ title, type }: { title: string; type: MandalartType }) => ( +
+

{title}

+
+
+ + +
+
+); + export const Default: Story = { args: { content: '상위 목표', + type: 'TODO_MAIN', }, - render: (args) => ( -
-
-

Default 사이즈

-

- 메인: title03 / 서브: subtitle01 -

-
- - -
-
-
-

Small 사이즈

-

- 메인: body04 / 서브: subtitle05 -

-
- - -
-
+ render: () => ( +
+ + + +
), }; @@ -54,16 +57,25 @@ export const Default: Story = { export const MainGoal: Story = { args: { content: '메인 목표를 입력하세요', + type: 'TODO_MAIN', }, - render: (args) => ( -
+ render: () => ( +
-

Default 사이즈 (title03)

- +

TODO_SUB (96px)

+
-

Small 사이즈 (body04)

- +

TODO_MAIN (196px)

+
+
+
+

TODO_EDIT (160px)

+
+
+
+

MY_MANDAL (298px)

+
), @@ -72,43 +84,76 @@ export const MainGoal: Story = { export const SubGoalStates: Story = { args: { content: '세부 목표를 입력하세요', + type: 'TODO_MAIN', }, - render: (args) => ( -
+ render: () => ( +
+
+

TODO_SUB (96px)

+
+ + +
+
+
+

TODO_MAIN (196px)

+
+ + +
+
-

Default 사이즈 (subtitle01)

-
-
-

기본 상태

- -
-
-

완료 상태

- -
+

TODO_EDIT (160px)

+
+ +
-

Small 사이즈 (subtitle05)

-
-
-

기본 상태

- -
-
-

완료 상태

- -
+

MY_MANDAL (298px)

+
+ +
diff --git a/src/common/component/Mandalart/Square/Square.tsx b/src/common/component/Mandalart/Square/Square.tsx index 6034773e..7ea6ca2d 100644 --- a/src/common/component/Mandalart/Square/Square.tsx +++ b/src/common/component/Mandalart/Square/Square.tsx @@ -1,5 +1,5 @@ import * as styles from './Square.css'; -import type { MandalartSize } from '../Mandalart'; +import type { MandalartType } from '../Mandalart'; export interface SquareProps { children: React.ReactNode; @@ -7,7 +7,7 @@ export interface SquareProps { export interface CellProps { content: string; - size?: MandalartSize; + type: MandalartType; } export interface SubCellProps extends CellProps { @@ -19,24 +19,18 @@ export const Root = ({ children }: SquareProps) => { return
{children}
; }; -export const Main = ({ content, size = 'default' }: CellProps) => { +export const Main = ({ content, type }: CellProps) => { return (
-
- {content} -
+
{content}
); }; -export const Sub = ({ content, isCompleted, onClick, size = 'default' }: SubCellProps) => { +export const Sub = ({ content, isCompleted, onClick, type }: SubCellProps) => { return (
-
+
{content}
diff --git a/src/common/component/Mandalart/Square/index.ts b/src/common/component/Mandalart/Square/index.ts index 72a6c083..36ed6054 100644 --- a/src/common/component/Mandalart/Square/index.ts +++ b/src/common/component/Mandalart/Square/index.ts @@ -1,9 +1,4 @@ import { Root, Main, Sub } from './Square'; -export const Square = { - Root, - Main, - Sub, -} as const; - -export type { SquareProps, CellProps } from './Square'; +export { Root, Main, Sub }; +export type { SquareProps, CellProps, SubCellProps } from './Square'; diff --git a/src/common/component/Mandalart/mock.ts b/src/common/component/Mandalart/mock.ts index 4819abfb..124793f5 100644 --- a/src/common/component/Mandalart/mock.ts +++ b/src/common/component/Mandalart/mock.ts @@ -1,48 +1,52 @@ -import type { SubGoal } from './Mandalart'; +import type { Cycle, SubGoal } from './Mandalart'; -export const MOCK_MANDALART_DATA = { - mainGoal: '나인도트 1등하기', +interface MockMandalartData { + mainGoal: string; + subGoals: SubGoal[]; +} + +export const MOCK_MANDALART_DATA: MockMandalartData = { + mainGoal: '메인 목표를 입력하세요', subGoals: [ { - title: '이현준 갈구기', + title: '세부 목표를 입력하세요', position: 0, - cycle: 'DAILY', + cycle: 'DAILY' as Cycle, }, { - title: '매일 운동하기', + title: '세부 목표를 입력하세요', position: 1, - cycle: 'DAILY', + cycle: 'DAILY' as Cycle, }, { - title: '일찍 일어나기', + title: '세부 목표를 입력하세요', position: 2, - cycle: 'DAILY', + cycle: 'DAILY' as Cycle, }, { - title: '계획 세우기', + title: '세부 목표를 입력하세요', position: 3, - cycle: 'WEEKLY', + cycle: 'DAILY' as Cycle, }, { - title: '시간 관리하기', + title: '세부 목표를 입력하세요', position: 4, - cycle: 'WEEKLY', + cycle: 'DAILY' as Cycle, }, { - title: '건강 관리하기', + title: '세부 목표를 입력하세요', position: 5, - cycle: 'DAILY', + cycle: 'DAILY' as Cycle, }, { - title: '긍정적으로 생각하기', + title: '세부 목표를 입력하세요', position: 6, - cycle: 'DAILY', + cycle: 'DAILY' as Cycle, }, { - title: '꾸준히 노력하기', + title: '세부 목표를 입력하세요', position: 7, - cycle: 'DAILY', + cycle: 'DAILY' as Cycle, }, - ] as SubGoal[], - completedGoals: [], + ], }; diff --git a/src/page/home/Home.tsx b/src/page/home/Home.tsx index 09cc3a59..d1211fec 100644 --- a/src/page/home/Home.tsx +++ b/src/page/home/Home.tsx @@ -1,7 +1,13 @@ +import Mandalart from '@/common/component/Mandalart/Mandalart'; + const Home = () => { return (

+ + + +
); }; diff --git a/src/style/token/typography.css.ts b/src/style/token/typography.css.ts index ccae5160..5cdba738 100644 --- a/src/style/token/typography.css.ts +++ b/src/style/token/typography.css.ts @@ -9,6 +9,11 @@ export const fonts = { fontWeight: '700', lineHeight: '140%', }, + display03: { + fontSize: '3.2rem', + fontWeight: '600', + lineHeight: '140%', + }, title01: { fontSize: '2.8rem', fontWeight: '600', @@ -29,6 +34,11 @@ export const fonts = { fontWeight: '600', lineHeight: '140%', }, + title05: { + fontSize: '2.4rem', + fontWeight: '400', + lineHeight: '140%', + }, subtitle01: { fontSize: '2rem', fontWeight: '700',