diff --git a/index.html b/index.html index dca73ca..22c74fb 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} @@ -188,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; @@ -467,11 +469,18 @@ .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 — 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;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.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} .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 3efad79..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 ${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"); @@ -1209,7 +1209,18 @@ 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 ``; +} +function pickDueEl(el){ + const inp=el&&el.querySelector("input.duepick"); + if(!inp) return; + if(typeof inp.showPicker==="function"){ try{ inp.showPicker(); return; }catch(_){ /* fall through */ } } + inp.focus(); inp.click(); +} function szSeg(v,onch){ return `${["s","m","l","xl"].map(z=> ``).join("")}`; } function taskCardHTML(tk,i){ tk.subs=tk.subs||[]; @@ -1530,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 a3f9aa0..3fd3adb 100644 --- a/tests/smoke.test.js +++ b/tests/smoke.test.js @@ -19,4 +19,11 @@ 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)"); + expect(main).toContain('class="duelbl'); + expect(main).toContain("pickDueEl"); + }); });