From 330d6fddc60b8d80057beda862b14655cf94b37e Mon Sep 17 00:00:00 2001 From: mARTin Date: Mon, 2 Mar 2026 08:18:35 +0100 Subject: [PATCH] feat: support linebreaks in task titles with Shift+Enter Replace input elements with textarea for task editing and creation. Shift+Enter inserts a newline, Enter saves. Display uses pre-wrap. v1.10.0 Co-Authored-By: Claude Opus 4.6 --- package.json | 2 +- src/components/GridTaskBlock.tsx | 11 ++++--- src/components/WeeklyView.tsx | 56 ++++++++++++++++++++++++-------- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index 17140b1..47424d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "my-weekly-todo-list", - "version": "1.9.0", + "version": "1.10.0", "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/components/GridTaskBlock.tsx b/src/components/GridTaskBlock.tsx index c9b7f89..a066a62 100644 --- a/src/components/GridTaskBlock.tsx +++ b/src/components/GridTaskBlock.tsx @@ -195,23 +195,24 @@ export function GridTaskBlock({
{ e.preventDefault(); - const input = e.currentTarget.elements.namedItem("title") as HTMLInputElement; + const input = e.currentTarget.elements.namedItem("title") as HTMLTextAreaElement; updateTask(task.id, input.value || ""); }} onClick={(e) => e.stopPropagation()} style={{ width: "100%", paddingRight: "20px" }} > - updateTask(task.id, e.target.value)} onKeyDown={(e) => { if (e.key === "Escape") setEditingTaskId(null); - if (e.key === "Enter") e.currentTarget.blur(); + if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); e.currentTarget.blur(); } }} + rows={(task.title?.split("\n").length) || 1} className="weekly-task-text" - style={{ width: "100%", background: "transparent", border: "none", borderBottom: "1px solid var(--weekly-border)", outline: "none" }} + style={{ width: "100%", background: "transparent", border: "none", borderBottom: "1px solid var(--weekly-border)", outline: "none", resize: "none", overflow: "hidden", fontFamily: "inherit", lineHeight: "inherit" }} />
) : ( @@ -221,7 +222,7 @@ export function GridTaskBlock({ alignItems: "flex-start", gap: "3px", overflow: "visible", - whiteSpace: "normal", + whiteSpace: "pre-wrap", wordBreak: "break-word", flex: 1, }} diff --git a/src/components/WeeklyView.tsx b/src/components/WeeklyView.tsx index f8c79a8..040af51 100644 --- a/src/components/WeeklyView.tsx +++ b/src/components/WeeklyView.tsx @@ -5679,8 +5679,7 @@ interface TaskInputProps { function TaskInput({ onAddTask, onDragOver, onDrop }: TaskInputProps) { const [newTaskTitle, setNewTaskTitle] = useState(""); - const handleAddTask = (e: React.FormEvent) => { - e.preventDefault(); + const handleAddTask = () => { if (newTaskTitle.trim()) { onAddTask(newTaskTitle); setNewTaskTitle(""); @@ -5688,19 +5687,36 @@ function TaskInput({ onAddTask, onDragOver, onDrop }: TaskInputProps) { }; return ( -
- setNewTaskTitle(e.target.value)} + onKeyDown={(e) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + handleAddTask(); + } + }} placeholder="Type a to-do..." + rows={newTaskTitle.split("\n").length || 1} + style={{ + resize: "none", + overflow: "hidden", + fontFamily: "inherit", + lineHeight: "inherit", + width: "100%", + border: "none", + background: "transparent", + outline: "none", + padding: "inherit", + fontSize: "inherit", + }} /> -
+ ); } @@ -5820,7 +5836,7 @@ function TaskItem({ const [isSubTaskInputOpen, setIsSubTaskInputOpen] = useState(false); const [isSubTasksOpen, setIsSubTasksOpen] = useState(false); const [newSubTaskTitle, setNewSubTaskTitle] = useState(""); - const inputRef = useRef(null); + const inputRef = useRef(null); const notesRef = useRef(null); const subTaskInputRef = useRef(null); @@ -5850,6 +5866,10 @@ function TaskItem({ }; const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + (e.target as HTMLElement).blur(); + } if (e.key === "Escape") { setEditValue(task.title); onUpdate(task.title); @@ -5936,14 +5956,14 @@ function TaskItem({ {isEditing ? (
{variant === "minimal" ? ( - setEditValue(e.target.value)} onKeyDown={handleKeyDown} onBlur={() => onUpdate(editValue)} + rows={editValue.split("\n").length || 1} style={{ border: "none", background: "transparent", @@ -5952,17 +5972,27 @@ function TaskItem({ padding: "0", fontSize: "0.9375rem", fontWeight: 500, + resize: "none", + overflow: "hidden", + fontFamily: "inherit", + lineHeight: "inherit", }} /> ) : ( - setEditValue(e.target.value)} onKeyDown={handleKeyDown} onBlur={() => onUpdate(editValue)} + rows={editValue.split("\n").length || 1} + style={{ + resize: "none", + overflow: "hidden", + fontFamily: "inherit", + lineHeight: "inherit", + }} /> )}
@@ -6024,7 +6054,7 @@ function TaskItem({ )}