From 1f90526b5becf01fbb6068d391db1647a19b3860 Mon Sep 17 00:00:00 2001 From: mARTin Date: Sun, 22 Mar 2026 08:34:43 +0100 Subject: [PATCH] fix: improved subtask expand/collapse in calendar and kanban views Kanban cards now have inline subtask expand/collapse with progress bar, chevron toggle, and checkbox list. Calendar view subtask badge updated to match with ChevronDown icon, highlight when expanded, and wider progress bar. Consistent UX across both views. v1.55.2 Co-Authored-By: Claude Opus 4.6 --- package.json | 2 +- src/app/globals.css | 67 ++++++++++++++++++++++++++++++++ src/components/WeeklyView.tsx | 73 +++++++++++++++++++++++++++-------- 3 files changed, 124 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 78ea268..0e5c991 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "my-weekly-todo-list", - "version": "1.55.1", + "version": "1.55.2", "description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view", "main": "index.js", "scripts": { diff --git a/src/app/globals.css b/src/app/globals.css index b7e7484..6029a7f 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1952,6 +1952,73 @@ h3 { } /* Kanban stage color indicator on weekly tasks */ +.kanban-card-subtask-toggle { + margin-top: 4px; +} +.kanban-card-subtask-btn { + display: flex; + align-items: center; + gap: 6px; + background: none; + border: none; + cursor: pointer; + padding: 3px 0; + color: var(--weekly-text-muted, #9ca3af); + font-size: 0.7rem; + font-weight: 600; + width: 100%; +} +.kanban-card-subtask-btn:hover { + color: var(--weekly-text, #666); +} +.kanban-card-subtask-bar { + flex: 1; + height: 4px; + border-radius: 2px; + background: var(--weekly-border, #e5e7eb); + position: relative; + overflow: hidden; + max-width: 60px; +} +.kanban-card-subtask-bar-fill { + position: absolute; + left: 0; + top: 0; + height: 100%; + border-radius: 2px; + transition: width 0.3s ease; +} +.kanban-card-subtask-count { + font-size: 0.7rem; + opacity: 0.8; +} +.kanban-card-subtask-list { + display: flex; + flex-direction: column; + gap: 2px; + padding: 4px 0 2px 2px; +} +.kanban-card-subtask-item { + display: flex; + align-items: center; + gap: 6px; + font-size: 0.75rem; + color: var(--weekly-text, #333); + padding: 1px 0; +} +.kanban-card-subtask-item input[type="checkbox"] { + width: 13px; + height: 13px; + cursor: pointer; + flex-shrink: 0; +} +.kanban-card-subtask-item.completed { + opacity: 0.5; +} +.kanban-card-subtask-done { + text-decoration: line-through; +} + .kanban-stage-indicator { width: 4px; border-radius: 2px; diff --git a/src/components/WeeklyView.tsx b/src/components/WeeklyView.tsx index df07317..da371c6 100644 --- a/src/components/WeeklyView.tsx +++ b/src/components/WeeklyView.tsx @@ -2078,6 +2078,7 @@ export default function WeeklyView() { const [kanbanAddingStageId, setKanbanAddingStageId] = useState(null); const [kanbanNewTaskTitle, setKanbanNewTaskTitle] = useState(""); const [kanbanDetailTask, setKanbanDetailTask] = useState(null); + const [kanbanExpandedCards, setKanbanExpandedCards] = useState>(new Set()); const [protectEventTimes, setProtectEventTimes] = useState(false); const [unlockedEvents, setUnlockedEvents] = useState>(new Set()); @@ -6447,7 +6448,15 @@ export default function WeeklyView() { return true; }); - const renderKanbanCard = (task: Task) => ( + const renderKanbanCard = (task: Task) => { + const subTasks = task.subTasks || []; + const subCompleted = subTasks.filter(s => s.completed).length; + const subTotal = subTasks.length; + const subPct = subTotal > 0 ? (subCompleted / subTotal) * 100 : 0; + const allSubDone = subTotal > 0 && subCompleted === subTotal; + const isExpanded = kanbanExpandedCards.has(task.id); + + return (
{ - // Don't open detail if clicking checkbox, contentEditable, or buttons const target = e.target as HTMLElement; - if (target.tagName === "INPUT" || target.contentEditable === "true" || target.closest("button")) return; + if (target.tagName === "INPUT" || target.contentEditable === "true" || target.closest("button") || target.closest(".kanban-card-subtask-list")) return; setKanbanDetailTask(task); }} style={{ cursor: "pointer" }} @@ -6488,9 +6496,42 @@ export default function WeeklyView() { {task.title}
- {task.subTasks && task.subTasks.length > 0 && ( -
- {task.subTasks.filter(st => st.completed).length}/{task.subTasks.length} {language === "de" ? "Unteraufgaben" : "subtasks"} + {subTotal > 0 && ( +
e.stopPropagation()}> + + {isExpanded && ( +
+ {subTasks.map(sub => ( +
+ toggleSubTask(sub.id)} + style={{ accentColor: "var(--weekly-accent, #6366f1)" }} + /> + {sub.title} +
+ ))} +
+ )}
)} {task.markdownContent && ( @@ -6514,7 +6555,8 @@ export default function WeeklyView() { return list ?
{list.title}
: null; })()}
- ); + ); + }; const kanbanColumnDrop = (stageId: string | null) => ({ onDragOver: (e: React.DragEvent) => { @@ -9710,9 +9752,9 @@ function TaskItem({ display: "inline-flex", alignItems: "center", gap: "4px", - padding: "2px 8px 2px 6px", + padding: "2px 8px 2px 4px", borderRadius: "12px", - background: "transparent", + background: expanded ? "rgba(99,102,241,0.08)" : "transparent", color: allDone ? "var(--weekly-teal, #0d9488)" : "var(--weekly-text-light, #9ca3af)", border: "none", cursor: "pointer", @@ -9721,17 +9763,14 @@ function TaskItem({ lineHeight: 1, flexShrink: 0, whiteSpace: "nowrap", - transition: "color 0.15s", + transition: "all 0.15s", }} > - - - - {/* Mini progress bar */} +