Skip to content

Commit deaa027

Browse files
Feat(client): Time picker 구현 (#49)
* setting: default white, black color token 추가 * feat: 최소한의 스타일만 가진 headless default time picker 구현 * chore: ncdai/react-wheel-picker 의존성 추가 * feat: wheel picker 공통 component 구현 * chore: index에 공통 picker 컴포넌트 export 추가 * feat: onboarding time picker 구현 * feat: onboarding page 추가 * chore: time picker client onboarding로 파일 위치 변경 * feat: pds vite config에 vite-tsconfig-paths 의존성 및 설정 추가 * chore: cn export 하던 lib 절대 경로 제거 * chore: 사용하지 않는 코드 제거 * fix: design-system 내 lib, icons 절대 경로를 상대 경로로 수정 * feat: time picker state 로직 추가 * feat: onSave 인터페이스 구현 * refactor: mouse event handler import 추가
1 parent bb59c9d commit deaa027

File tree

22 files changed

+195
-24
lines changed

22 files changed

+195
-24
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const OnBoarding = () => {
2+
return <div>OnBoarding</div>;
3+
};
4+
5+
export default OnBoarding;

apps/client/src/pages/onBoarding/components/.gitkeep

Whitespace-only changes.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import {
2+
Button,
3+
WheelPicker,
4+
WheelPickerOption,
5+
WheelPickerWrapper,
6+
} from '@pinback/design-system/ui';
7+
import { MouseEventHandler, useState } from 'react';
8+
9+
const createArray = (length: number, add = 0): WheelPickerOption[] =>
10+
Array.from({ length }, (_, i) => {
11+
const value = i + add;
12+
return {
13+
label: value.toString().padStart(2, '0'),
14+
value: value.toString(),
15+
};
16+
});
17+
18+
const hourOptions = createArray(12, 1);
19+
const minuteOptions = createArray(60);
20+
const meridiemOptions: WheelPickerOption[] = [
21+
{ label: 'AM', value: 'AM' },
22+
{ label: 'PM', value: 'PM' },
23+
];
24+
25+
interface TimePickerProps {
26+
onSave: (time: { hour: string; minute: string; meridiem: string }) => void;
27+
onCancel: () => void;
28+
onClick: MouseEventHandler<HTMLDivElement>;
29+
}
30+
31+
const TimePicker = ({ onSave, onCancel, onClick }: TimePickerProps) => {
32+
const [selectedHour, setSelectedHour] = useState(hourOptions[0].value);
33+
const [selectedMinute, setSelectedMinute] = useState(minuteOptions[0].value);
34+
const [selectedMeridiem, setSelectedMeridiem] = useState(
35+
meridiemOptions[0].value
36+
);
37+
38+
return (
39+
<div
40+
onClick={onClick}
41+
className="common-shadow flex w-[26rem] flex-col items-center px-[1.6rem]"
42+
>
43+
<WheelPickerWrapper className="flex h-[16.8rem] !items-center py-[0.8rem]">
44+
<WheelPicker
45+
options={hourOptions}
46+
aria-label="시"
47+
infinite
48+
optionItemHeight={56}
49+
onValueChange={(value: string) => setSelectedHour(value)}
50+
/>
51+
<p className="bod y2-m z-2 mx-[0.8rem] flex h-[5.6rem] items-center justify-center">
52+
:
53+
</p>
54+
<WheelPicker
55+
options={minuteOptions}
56+
aria-label="분"
57+
infinite
58+
optionItemHeight={56}
59+
onValueChange={(value: string) => setSelectedMinute(value)}
60+
/>
61+
<div className="mx-[0.4rem]" />
62+
<WheelPicker
63+
options={meridiemOptions}
64+
aria-label="오전/오후"
65+
optionItemHeight={56}
66+
onValueChange={(value: string) => setSelectedMeridiem(value)}
67+
/>
68+
</WheelPickerWrapper>
69+
<div className="flex w-full gap-[1.2rem] pb-[2.4rem] pt-[0.8rem]">
70+
<Button variant="secondary" onClick={onCancel}>
71+
취소
72+
</Button>
73+
<Button
74+
variant="primary"
75+
onClick={() =>
76+
onSave({
77+
hour: selectedHour,
78+
minute: selectedMinute,
79+
meridiem: selectedMeridiem,
80+
})
81+
}
82+
>
83+
확인
84+
</Button>
85+
</div>
86+
</div>
87+
);
88+
};
89+
90+
export default TimePicker;

apps/client/src/routes/router.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Category from '@pages/category/Category';
22
import Level from '@pages/level/Level';
33
import MyBookmark from '@pages/myBookmark/MyBookmark';
4+
import OnBoarding from '@pages/onBoarding/OnBoarding';
45
import Remind from '@pages/remind/Remind';
56
import { ROUTES_CONFIG } from '@routes/routesConfig';
67
import { createBrowserRouter } from 'react-router-dom';
@@ -27,6 +28,10 @@ export const router = createBrowserRouter([
2728
path: ROUTES_CONFIG.level.path,
2829
element: <Level />,
2930
},
31+
{
32+
path: ROUTES_CONFIG.onBoarding.path,
33+
element: <OnBoarding />,
34+
},
3035
],
3136
},
3237
]);

apps/client/src/routes/routesConfig.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,8 @@ export const ROUTES_CONFIG = {
1515
title: '레벨',
1616
path: '/level',
1717
},
18+
onBoarding: {
19+
title: '온보딩',
20+
path: '/onBoarding',
21+
},
1822
};

packages/design-system/components.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,8 @@
1717
"lib": "@/lib",
1818
"hooks": "@/hooks"
1919
},
20-
"iconLibrary": "lucide"
20+
"iconLibrary": "lucide",
21+
"registries": {
22+
"@ncdai": "https://chanhdai.com/r/{name}.json"
23+
}
2124
}

packages/design-system/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@
4848
"typescript": "5.9.2",
4949
"typescript-eslint": "^8.39.1",
5050
"vite": "^7.1.2",
51+
"vite-tsconfig-paths": "^5.1.4",
5152
"vitest": "^3.2.4"
5253
},
5354
"dependencies": {
55+
"@ncdai/react-wheel-picker": "^1.0.15",
5456
"@pivanov/vite-plugin-svg-sprite": "^3.1.3",
5557
"@radix-ui/react-progress": "^1.1.7",
5658
"@radix-ui/react-slot": "^1.2.3",

packages/design-system/src/components/badge/Badge.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Meta, StoryObj } from '@storybook/react-vite';
22
import { within, userEvent } from '@storybook/test';
3-
import Badge, { type BadgeProps } from './Badge';
3+
import Badge from './Badge';
44

55
const meta: Meta<typeof Badge> = {
66
title: 'Components/Badge',

packages/design-system/src/components/button/Button.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { cn } from '@/lib';
21
import { cva } from 'class-variance-authority';
2+
import { cn } from '../../lib/utils';
33

44
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
55
variant?: 'primary' | 'secondary';

packages/design-system/src/components/card/MyBookmarkCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Icon } from '@/icons';
21
import chippiNoImage from '../../assets/chippi_no_image.svg';
2+
import { Icon } from '../../icons';
33
import BaseCard from './BaseCard';
44

55
interface MyBookmarkCardProps {

0 commit comments

Comments
 (0)