From ebd10d5aef1b363cee1cf69e7d621e1572549393 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 7 Jul 2026 15:00:29 +0000 Subject: [PATCH 1/3] Add inline due-date editing in project and task panels Replace read-only due chips on child rows with date inputs so users can edit task dates from a project panel and subtask dates from a task panel without opening each item. Co-authored-by: Tanops --- index.html | 1 + src/app/main.js | 2 +- tests/smoke.test.js | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index dca73ca..3785a96 100644 --- a/index.html +++ b/index.html @@ -171,6 +171,7 @@ border:none;border-radius:8px;padding:5px 7px;-webkit-appearance:none;appearance:none;cursor:pointer} .ptask .rowsz:hover{background:#e4e7ec;color:var(--ink)} .ptask .rowpts{flex:none;font-size:11px;font-weight:700;color:var(--ink-3);background:#eef0f4;border-radius:8px;padding:5px 8px} + .ptask .duepill{flex:none} /* ---------- detail sheet ---------- */ .scrim{position:fixed;inset:0;background:rgba(20,24,35,.32);z-index:40;opacity:0;pointer-events:none;transition:opacity .22s} diff --git a/src/app/main.js b/src/app/main.js index 3efad79..c227359 100644 --- a/src/app/main.js +++ b/src/app/main.js @@ -869,7 +869,7 @@ function openDetail(id){ ${ownerPill(ch.owner,`updTask(${ch.id},'owner',this.value,true);openDetail(${id})`)} ${szCtl} - ${dueChip(ch.due,lleaf&&ch.done)}`;}).join("")} + ${duePill(ch.due,`updTask(${ch.id},'due',this.value,true);openDetail(${id})`,true)}`;}).join("")} ${path.length>=3?"":`
`} `; document.getElementById("tmodal").classList.add("show"); diff --git a/tests/smoke.test.js b/tests/smoke.test.js index a3f9aa0..98f3e38 100644 --- a/tests/smoke.test.js +++ b/tests/smoke.test.js @@ -19,4 +19,9 @@ describe("project layout", () => { expect(dates.createDateHelpers).toBeTypeOf("function"); expect(capture.mockTranscript).toBeTypeOf("function"); }); + + it("allows inline due-date editing on tasks and subtasks in detail panels", () => { + const main = readFileSync("src/app/main.js", "utf8"); + expect(main).toContain("duePill(ch.due,`updTask(${ch.id},'due',this.value,true);openDetail(${id})`,true)"); + }); }); From fc32dcf22a05b30564c8d218faa9b1c6b54c797e Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 7 Jul 2026 16:03:49 +0000 Subject: [PATCH 2/3] Make entire due-date pill clickable to open the picker Show a formatted date label with a full-size transparent date input overlaid so clicking anywhere on the pill opens the calendar, not just the native icon. Co-authored-by: Tanops --- index.html | 15 ++++++++++----- src/app/main.js | 6 +++++- tests/smoke.test.js | 1 + 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index 3785a96..256ca91 100644 --- a/index.html +++ b/index.html @@ -468,11 +468,16 @@ .opill select{border:none;background:transparent;font:inherit;font-size:12px;font-weight:600;color:var(--ink-2); -webkit-appearance:none;appearance:none;max-width:96px} .opill select:focus{outline:none} - /* due pill */ - .duepill{display:inline-flex;align-items:center;background:#eef0f4;border-radius:999px;padding:3px 11px} - .duepill input{border:none;background:transparent;font:inherit;font-size:12px;font-weight:600;color:var(--ink-2);width:104px} - .duepill input:focus{outline:none} - .duepill.sm input{width:96px;font-size:11.5px} + /* due pill — visible label with a full-size transparent date input over it */ + .duepill{position:relative;display:inline-flex;align-items:center;justify-content:center; + background:#eef0f4;border-radius:999px;padding:3px 11px;min-height:28px;cursor:pointer;user-select:none} + .duepill:hover,.duepill:focus-within{background:#e4e7ec} + .duepill .duelbl{font:inherit;font-size:12px;font-weight:600;color:var(--ink-2);white-space:nowrap; + line-height:1.3;pointer-events:none} + .duepill .duelbl.empty{color:var(--ink-3)} + .duepill input{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer;border:none;margin:0;padding:0} + .duepill.sm{min-height:26px;padding:2px 9px} + .duepill.sm .duelbl{font-size:11.5px} /* segmented t-shirt size */ .szseg{display:inline-flex;background:#eef0f4;border-radius:999px;padding:2px} .szb{padding:3px 10px;border-radius:999px;font-size:11px;font-weight:800;color:var(--ink-3);line-height:1.5} diff --git a/src/app/main.js b/src/app/main.js index c227359..bf2efeb 100644 --- a/src/app/main.js +++ b/src/app/main.js @@ -1209,7 +1209,11 @@ const ownerOpts=v=>``+Object.entries(PEOPLE).m function ownerPill(v,onch){ const col=v?PEOPLE[v].color:"#c2c8d2"; return ` `; } -function duePill(v,onch,sm){ return ``; } +function duePill(v,onch,sm){ + const lbl=v?fmtD(v):"Set date"; + return `${lbl}` + +``; +} function szSeg(v,onch){ return `${["s","m","l","xl"].map(z=> ``).join("")}`; } function taskCardHTML(tk,i){ tk.subs=tk.subs||[]; diff --git a/tests/smoke.test.js b/tests/smoke.test.js index 98f3e38..93aa637 100644 --- a/tests/smoke.test.js +++ b/tests/smoke.test.js @@ -23,5 +23,6 @@ describe("project layout", () => { it("allows inline due-date editing on tasks and subtasks in detail panels", () => { const main = readFileSync("src/app/main.js", "utf8"); expect(main).toContain("duePill(ch.due,`updTask(${ch.id},'due',this.value,true);openDetail(${id})`,true)"); + expect(main).toContain('class="duelbl'); }); }); From d24a037d6604bcbc9094cf7b0983edd2b777cfde Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 7 Jul 2026 16:10:17 +0000 Subject: [PATCH 3/3] Open date picker from the full due-date pill click target Hide the native date input entirely and show only a formatted label pill. Clicking anywhere on the pill calls showPicker(), matching the full-field hit area shown in the task/subtask rows. Co-authored-by: Tanops --- index.html | 11 +++++++---- src/app/main.js | 15 +++++++++++---- tests/smoke.test.js | 1 + 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/index.html b/index.html index 256ca91..22c74fb 100644 --- a/index.html +++ b/index.html @@ -189,6 +189,7 @@ .tbox .frow select,.tbox .frow input{flex:1;font:inherit;font-size:15px;border:none;background:transparent; color:var(--ink);min-height:34px;-webkit-appearance:none;appearance:none} .tbox .frow select:focus,.tbox .frow input:focus{outline:none} + .tbox .frow .duepill{flex:none} /* make the borderless selects (Owner / Size / Move to) read as editable dropdowns: size to their value and show a caret + hover so it's clear you can change them */ .tbox .frow select{flex:0 1 auto;max-width:100%;cursor:pointer;min-height:32px; @@ -468,15 +469,17 @@ .opill select{border:none;background:transparent;font:inherit;font-size:12px;font-weight:600;color:var(--ink-2); -webkit-appearance:none;appearance:none;max-width:96px} .opill select:focus{outline:none} - /* due pill — visible label with a full-size transparent date input over it */ + /* due pill — formatted label; hidden native input opened via pickDueEl */ .duepill{position:relative;display:inline-flex;align-items:center;justify-content:center; - background:#eef0f4;border-radius:999px;padding:3px 11px;min-height:28px;cursor:pointer;user-select:none} + background:#eef0f4;border-radius:999px;padding:3px 11px;min-height:28px;min-width:92px; + cursor:pointer;user-select:none;border:none;font:inherit} .duepill:hover,.duepill:focus-within{background:#e4e7ec} .duepill .duelbl{font:inherit;font-size:12px;font-weight:600;color:var(--ink-2);white-space:nowrap; line-height:1.3;pointer-events:none} .duepill .duelbl.empty{color:var(--ink-3)} - .duepill input{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer;border:none;margin:0;padding:0} - .duepill.sm{min-height:26px;padding:2px 9px} + .duepill input.duepick{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden; + clip:rect(0,0,0,0);white-space:nowrap;border:0} + .duepill.sm{min-height:26px;min-width:86px;padding:2px 9px} .duepill.sm .duelbl{font-size:11.5px} /* segmented t-shirt size */ .szseg{display:inline-flex;background:#eef0f4;border-radius:999px;padding:2px} diff --git a/src/app/main.js b/src/app/main.js index bf2efeb..fd5f9b5 100644 --- a/src/app/main.js +++ b/src/app/main.js @@ -851,7 +851,7 @@ function openDetail(id){ document.getElementById("dBody").innerHTML=`
Owner${av(n.owner)}
-
Due${dueChip(n.due,leaf&&n.done)}
+
Due${duePill(n.due,`updTask(${id},'due',this.value)`)}${dueChip(n.due,leaf&&n.done)}
${sizeFld} ${leaf?`
Status `).join("")}`; } @@ -1534,7 +1541,7 @@ const _globals = { toggleExp, updTask, refreshBarMenu, addChild, addProject, deleteTask, addCapTask, barDown, barContext, pickSearch, uploadPhoto, removePhoto, rvToggle, rvText, rvOwner, rvDue, rvSize, pushApproved, attachTranscript, doSearch, refreshCard, delCapTask, setTask, setTaskOwner, setTaskSize, setSub, setSubOwner, addSub, - delSub, commitCapture, toggleListen, stopListen, renderAll, moveTask, setKeyVal, + delSub, commitCapture, toggleListen, stopListen, renderAll, moveTask, setKeyVal, pickDueEl, }; Object.assign(window, _globals); diff --git a/tests/smoke.test.js b/tests/smoke.test.js index 93aa637..3fd3adb 100644 --- a/tests/smoke.test.js +++ b/tests/smoke.test.js @@ -24,5 +24,6 @@ describe("project layout", () => { const main = readFileSync("src/app/main.js", "utf8"); expect(main).toContain("duePill(ch.due,`updTask(${ch.id},'due',this.value,true);openDetail(${id})`,true)"); expect(main).toContain('class="duelbl'); + expect(main).toContain("pickDueEl"); }); });