From 00f8e004363554e0eea925078afc8a4aee943faa Mon Sep 17 00:00:00 2001 From: gahusb Date: Thu, 23 Apr 2026 14:55:05 +0900 Subject: [PATCH] =?UTF-8?q?feat(todo):=20=EB=AA=A8=EB=B0=94=EC=9D=BC=20?= =?UTF-8?q?=EB=B0=98=EC=9D=91=ED=98=95=20=E2=80=94=20=EC=8A=A4=EC=99=80?= =?UTF-8?q?=EC=9D=B4=ED=94=84=20=EC=B9=B8=EB=B0=98=20+=20FAB=20+=20?= =?UTF-8?q?=EB=B0=94=ED=85=80=EC=8B=9C=ED=8A=B8=20=EC=9E=85=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- src/pages/todo/Todo.css | 12 +- src/pages/todo/Todo.jsx | 285 ++++++++++++++++++++++++---------------- 2 files changed, 186 insertions(+), 111 deletions(-) diff --git a/src/pages/todo/Todo.css b/src/pages/todo/Todo.css index 54f6f31..d1f7155 100644 --- a/src/pages/todo/Todo.css +++ b/src/pages/todo/Todo.css @@ -370,11 +370,21 @@ text-decoration-color: rgba(244, 114, 182, 0.4); } +/* ── 스와이프 보드 (모바일 전용) ──────────────────────────────────────── */ + +.todo-swipe-board { + display: none; +} + /* ── Responsive ──────────────────────────────────────────────────────── */ @media (max-width: 768px) { .todo-board { - grid-template-columns: 1fr; + display: none; + } + + .todo-swipe-board { + display: block; } .todo-col { diff --git a/src/pages/todo/Todo.jsx b/src/pages/todo/Todo.jsx index 62ba2a8..1a0b65b 100644 --- a/src/pages/todo/Todo.jsx +++ b/src/pages/todo/Todo.jsx @@ -1,5 +1,10 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { getTodos, addTodo, updateTodo, deleteTodo, clearTodos } from '../../api'; +import { useIsMobile } from '../../hooks/useIsMobile'; +import SwipeableView from '../../components/SwipeableView'; +import FAB from '../../components/FAB'; +import MobileSheet from '../../components/MobileSheet'; +import PullToRefresh from '../../components/PullToRefresh'; import './Todo.css'; const ACTIVE_COLUMNS = [ @@ -19,11 +24,13 @@ const toDateStr = (iso) => { }; const Todo = () => { + const isMobile = useIsMobile(); const [todos, setTodos] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); const [form, setForm] = useState(emptyForm); const [formOpen, setFormOpen] = useState(false); + const [addSheetOpen, setAddSheetOpen] = useState(false); const [saving, setSaving] = useState(false); const [dragging, setDragging] = useState(null); const [dragOver, setDragOver] = useState(null); @@ -185,7 +192,66 @@ const Todo = () => { ); + /* ── 칸반 컬럼 렌더러 (재사용) ── */ + const renderColumn = (col) => { + const items = byStatus(col.id); + return ( +
onDragOver(e, col.id)} + onDrop={(e) => onDrop(e, col.id)} + > +
+ {col.label} + {items.length} +
+
+ {items.length === 0 && ( +

드래그하여 이동

+ )} + {items.map((todo) => renderCard(todo, col.id))} +
+
+ ); + }; + + /* ── 추가 폼 (공통) ── */ + const addForm = ( +
{ await handleAdd(e); setAddSheetOpen(false); }}> + +