|
|
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Checkbox } from "@/components/ui/checkbox";
import React, { useEffect, useState } from "react";
// 임시 데이터
const initialTodos = [
{
id: 1,
title: "React 환경에서 shadcn 설치 정리",
description: "설치 명령어와 폴더 구조를 정리해서 노션에 기록하기",
tag: "오늘",
done: false,
},
{
id: 2,
title: "Tailwind + shadcn 버튼 스타일 실험",
description: "variant, size, className 커스터마이징 테스트",
tag: "UI 연습",
done: false,
},
{
id: 3,
title: "TODO 페이지 기본 레이아웃 정리",
description: "좌측 TODO / 우측 달력 자리 레이아웃 고정",
tag: "진행중",
done: true,
},
];
const STORAGE_KEY = "shared-todo-list-v1"; // 향후 로컬스토리지 저장용 키
const TodoPage = () => {
const [todos, setTodos] = useState(initialTodos);
const [newTitle, setNewTitle] = useState("");
// localStorage에서 불러오기
useEffect(() => {
const savedTodos = localStorage.getItem(STORAGE_KEY);
if (savedTodos) {
try {
const parsedTodos = JSON.parse(savedTodos);
if (Array.isArray(parsedTodos)) {
setTodos(parsedTodos);
}
} catch (e) {
console.error("로컬스토리지 파싱 오류:", e);
}
}
}, []);
// todos가 변경될 때마다 localStorage에 저장하기
useEffect(() => {
localStorage.setItem(STORAGE_KEY, JSON.stringify(todos));
}, [todos]);
// TODO 추가 함수
const handleAddTodo = () => {
const trimmedTitle = newTitle.trim();
if (trimmedTitle === "") return; // 빈 제목은 추가하지 않음
const newTodo = {
id: Date.now(),
title: trimmedTitle,
description: "설명을 입력하세요.",
tag: "오늘",
done: false,
};
setTodos((prevTodos) => [newTodo, ...prevTodos]);
setNewTitle(""); // 입력 필드 초기화
};
// TODO 삭제 함수
const handleDelete = (id) => {
console.log("삭제할 TODO ID:", id);
setTodos((prevTodos) => prevTodos.filter((todo) => todo.id !== id));
};
// TODO 완료/복구 토글 함수
const handleToggleComplete = (id) => {
console.log("토글할 TODO ID:", id);
setTodos((prevTodos) =>
prevTodos.map((todo) =>
todo.id === id ? { ...todo, done: !todo.done } : todo
)
);
};
return (
<div className="min-h-screen bg-slate-950 text-slate-200 flex items-start justify-center py-10">
<div className="w-full max-w-5xl px-4 space-y-6">
{/* 상단 헤더 영역 */}
<header className="flex flex-col gap-2 sm:flex-row sm:items-end sm:justify-between">
<div>
<h1 className="text-3xl font-bold">공동 TODO 리스트</h1>
<p className="text-sm text-slate-400">
함께 사용하는 할 일 목록입니다.
</p>
</div>
<Button
variant="outline"
className="mt-2 sm:mt-0 bg-transparent"
>
오늘 일정만 보기
</Button>
</header>
{/* 메인 영역: 왼쪽 TODO 리스트 / 오른쪽 상세 or 달력 자리 2fr : 1.2fr 비율로 좌/우 2컬럼 */}
<main className="grid gap-4 md:grid-cols-3">
{/* 왼쪽: TODO 목록 */}
<Card className="bg-slate-900/70 border-slate-800 md:col-span-2">
<CardHeader>
<CardTitle className="text-2xl">
TODO 목록
</CardTitle>
<CardDescription>
오늘은 입력 폼과 TODO 카드 UI만 먼저 만들어 둔
상태입니다.
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{/* 입력 영역 */}
<div className="flex flex-col gap-2 sm:flex-row">
<Input
className="flex-1 px-4 py-2"
placeholder="예: shadcn 버튼 컴포넌트 정리하기"
value={newTitle}
xxonChange={(e) => setNewTitle(e.target.value)}
xxonKeyDown={(e) => {
if (e.key === "Enter") {
handleAddTodo();
}
}}
/>
<Button
variant="outline"
className="text-white sm:w-auto w-full bg-transparent"
xxonClick={handleAddTodo}
>
추가
</Button>
</div>
<p className="text-xs text-slate-500">
아직은 버튼을 눌러도 아무 동작도 하지 않고, 아래
목록은 임시 데이터로만 렌더링됩니다.
</p>
{/* TODO 리스트 (오늘은 목업 데이터 모양만) */}
<div className="space-y-3">
{todos.map((todo) => (
<Card
key={todo.id}
className="bg-slate-900/60 border-slate-700"
>
<CardContent className="flex items-center gap-3 py-3">
{/* 왼쪽: 체크박스 + 텍스트 */}
<div className="flex items-center gap-3 flex-1">
<Checkbox
checked={todo.done}
className="mt-1 border-slate-500 data-[state=checked]:bg-emerald-500 data-[state=checked]:border-emerald-500"
onCheckedChange={() => handleToggleComplete(todo.id)}
/>
<div className="space-y-1">
<div className="flex items-center gap-2">
<span
className={`test-sm font-medium ${
todo.done
? "line-through text-slate-500"
: ""
}`}
>
{todo.title}
</span>
<Badge
variant="outline"
className="text-xs border-slate-600 text-slate-300"
>
{todo.tag}
</Badge>
</div>
<p className="text-xs text-shadow-slate-400">
{todo.description}
</p>
</div>
</div>
{/* 오른쪽: 액션 버튼 영역 (UI만) */}
<div>
<Button
size="sm"
variant="outline"
className="bg-transparent text-xs"
xxonClick={() => handleToggleComplete(todo.id)}
>
{todo.done ? "복구" : "완료"}
</Button>
<Button
size="sm"
variant="outline"
className="
bg-transparent text-xs
border-red-500/60 text-red-400
hover:bg-red-500/10 hover:text-red-200
ml-2
"
xxonClick={() => handleDelete(todo.id)}
>
삭제
</Button>
</div>
</CardContent>
</Card>
))}
</div>
</CardContent>
</Card>
{/* 오른쪽: 나중에 달력/통계 등 들어갈 자리 */}
<Card className="bg-slate-900/70 border-slate-800 md:col-span-1">
<CardHeader>
<CardTitle className="text-2xl">
일정 요약 / 달력 자리
</CardTitle>
<CardDescription>
나중에 달력, 통계, 필터 등을 붙일 영역입니다.
</CardDescription>
</CardHeader>
<CardContent className="space-y-4 text-sm text-slate-300">
<p>지금은 단순한 설명 텍스트만 넣어 둔 상태예요.</p>
<ul className="list-disc list-inside space-y-2">
<li>위쪽은 이번 주 일정 요약</li>
<li>아래쪽은 간단한 캘린더 or 통계 그래프</li>
<li>
다음 단계에서 실제 컴포넌트를 연결할 예정
</li>
</ul>
</CardContent>
</Card>
</main>
</div>
</div>
);
};
export default TodoPage;
