Skip to content

Commit 607cbaf

Browse files
committed
feat : 할 일 및 일정 버튼 구현
1 parent b1b0097 commit 607cbaf

4 files changed

Lines changed: 134 additions & 7 deletions

File tree

app/(with-sidebar)/(home)/page.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ const Page = () => {
2020
<BottomSection className="grid grid-cols-1 gap-6 md:grid-cols-2" />
2121

2222
{/* 3. ButtonSection */}
23-
{/* 버튼 두개 만드쇼 */}
2423
<ButtonSection />
2524
</div>
2625
);

components/home/BottomSection.tsx

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,57 @@
1+
'use client';
2+
3+
import { useState } from 'react';
14
import Card from './Card';
5+
import CheckList, { ChecklistItem } from './CheckList';
26

37
interface BottomSectionProps {
48
className?: string;
59
}
610

7-
const BottomSection = ({ className }: BottomSectionProps) => {
11+
const TODAY_DUMMY = [
12+
{ id: 't1', text: 'React Hooks 정리', checked: false },
13+
{ id: 't2', text: 'GSAP ScrollTrigger 복습', checked: true },
14+
{ id: 't3', text: '알고리즘 1문제 풀기', checked: false },
15+
];
16+
17+
const UPCOMING_DUMMY = [
18+
{ id: 'u1', text: 'Next.js App Router 정리', checked: false },
19+
{ id: 'u2', text: '포트폴리오 리팩토링', checked: false },
20+
];
21+
22+
export default function BottomSection({ className }: BottomSectionProps) {
23+
const [today, setToday] = useState<ChecklistItem[]>(TODAY_DUMMY);
24+
const [upcoming, setUpcoming] = useState<ChecklistItem[]>(UPCOMING_DUMMY);
25+
26+
const toggleToday = (id: string) => {
27+
setToday((prev) =>
28+
prev.map((it) => (it.id === id ? { ...it, checked: !it.checked } : it))
29+
);
30+
};
31+
32+
const toggleUpcoming = (id: string) => {
33+
setUpcoming((prev) =>
34+
prev.map((it) => (it.id === id ? { ...it, checked: !it.checked } : it))
35+
);
36+
};
37+
838
return (
939
<div className={className}>
10-
<Card title="오늘 할 일">대충 할 일</Card>
11-
<Card title="다가오는 일정">대충 일정</Card>
40+
<Card title="오늘 할 일">
41+
<CheckList
42+
items={today}
43+
onToggle={toggleToday}
44+
emptyText="오늘 할 일이 없습니다"
45+
/>
46+
</Card>
47+
48+
<Card title="다가오는 일정">
49+
<CheckList
50+
items={upcoming}
51+
onToggle={toggleUpcoming}
52+
emptyText="다가오는 일정이 없습니다"
53+
/>
54+
</Card>
1255
</div>
1356
);
14-
};
15-
16-
export default BottomSection;
57+
}

components/home/CheckItem.tsx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use client';
2+
3+
import { Check } from 'lucide-react';
4+
5+
type CheckItemProps = {
6+
checked: boolean;
7+
text: string;
8+
onToggle: () => void;
9+
};
10+
11+
export function CheckItem({ checked, text, onToggle }: CheckItemProps) {
12+
return (
13+
<button
14+
type="button"
15+
onClick={onToggle}
16+
className={[
17+
'flex w-full items-center gap-4 rounded-2xl border px-5 py-2 text-left transition',
18+
'bg-gray-50 hover:bg-gray-100',
19+
'border-gray-300',
20+
].join(' ')}
21+
>
22+
<div
23+
className={[
24+
'flex h-6 w-6 items-center justify-center rounded-full border-2 transition',
25+
checked ? 'border-green-500' : 'border-gray-400',
26+
].join(' ')}
27+
>
28+
<Check
29+
className={[
30+
'transition-all',
31+
checked
32+
? 'scale-100 text-green-500 opacity-100'
33+
: 'scale-50 opacity-0',
34+
].join(' ')}
35+
size={16}
36+
strokeWidth={4}
37+
/>
38+
</div>
39+
<span
40+
className={[
41+
'text-sm',
42+
checked ? 'text-gray-400 line-through' : 'text-gray-800',
43+
].join(' ')}
44+
>
45+
{text}
46+
</span>
47+
</button>
48+
);
49+
}

components/home/CheckList.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use client';
2+
3+
import { CheckItem } from './CheckItem';
4+
5+
export type ChecklistItem = {
6+
id: string;
7+
text: string;
8+
checked: boolean;
9+
};
10+
11+
interface CheckListProps {
12+
items: ChecklistItem[];
13+
onToggle: (id: string) => void;
14+
emptyText?: string;
15+
}
16+
17+
export default function CheckList({
18+
items,
19+
onToggle,
20+
emptyText = '아직 항목이 없습니다',
21+
}: CheckListProps) {
22+
if (items.length === 0) {
23+
return <p className="text-sm text-gray-400">{emptyText}</p>;
24+
}
25+
26+
return (
27+
<div className="space-y-3">
28+
{items.map((item) => (
29+
<CheckItem
30+
key={item.id}
31+
checked={item.checked}
32+
text={item.text}
33+
onToggle={() => onToggle(item.id)}
34+
/>
35+
))}
36+
</div>
37+
);
38+
}

0 commit comments

Comments
 (0)