← Commit history

Publish 0.64.2

Drew Owens ·6cf766aed2 · ·parent e36230e
5 files changed +32−7
docs/BUILD-NOTES.md+10
@@ -3,6 +3,16 @@ Decisions taken while building, and the places where the plan and the code disagreed. Newest first. +## Build notes, 2026-10-05 (0.64.2, the version on every page)++Drew: "show version number on all pages". The version rode beside the Duration and+Remaining readouts, and it was the FIRST thing the measured header fit shed, so on the+Gantt lens it was missing at most widths. It now sits under the app name at the far left,+small and dim, on all four lenses at every width; stacked under the name it costs no+width, so the fit never has a reason to drop it. The `shed-ver` step is kept and simply+hides nothing now. The viewport flow checks the version on every lens at 393, 1440 and+1920.+ ## Build notes, 2026-10-05 (0.64.1, effort for a whole selection)  The batch panel gains an effort row under its tags: type an estimate and press Enter or
gantt.html+11−5
@@ -217,7 +217,12 @@ header .span-stat[data-state="ended"] .span-v, header .span-stat[data-state="empty"] .span-v { color: var(--text3); } header .span-stat .span-n { font-family: 'Satoshi', sans-serif; font-size: 10px; color: var(--text3); } header .span-stat .span-n:empty { display: none; }-header .subject .app-ver { font-family: 'JetBrains Mono', monospace; font-size: 11px; white-space: nowrap; flex-shrink: 0; }+/* The version sits UNDER the app name (0.64.2), small and dim, on every lens at every+   width. It used to ride beside the readouts, where it was the first thing the measured+   header fit shed, so on the Gantt lens at most widths it was not there at all. Stacked+   under the name it costs no width, so it is never shed. */+header .brand .brand-txt { display: flex; flex-direction: column; line-height: 1.1; min-width: 0; }+header .brand .app-ver { font-family: 'JetBrains Mono', monospace; font-size: 9.5px; font-weight: 400; color: var(--text3); white-space: nowrap; letter-spacing: 0.02em; } header .start-ctl { display: flex; align-items: center; gap: 8px; flex-shrink: 0; font-family: 'Satoshi', sans-serif; } header .start-ctl label { color: var(--text2); font-size: 11px; } header .date-btn { background: var(--bg); border: 1px solid var(--border); border-radius: 6px; color: var(--text-body); font-family: 'JetBrains Mono', monospace; font-size: 11px; padding: 4px 10px; cursor: pointer; transition: border-color 0.15s, color 0.15s; }@@ -390,7 +395,8 @@ header #btnTheme { min-width: 56px; justify-content: center; }    labels ("Duration", "Remaining"), and last it wraps onto a second row, with the words    back whenever they cost no extra row. The readouts never shrink (.subject is flex: 1 0 auto), so they are never the    thing that gives. The classes below are the only switches; no rule here names a width. */-header.shed-ver .subject .app-ver { display: none; }+/* shed-ver no longer hides anything: the version moved under the app name (0.64.2). The+   step is kept so the fit's state names do not change under anything that reads them. */ header.shed-labels .who-name, header.shed-labels .start-ctl label, header.shed-labels .act-btn .btn-label,@@ -969,7 +975,7 @@ body.ed-dragging { user-select: none; -webkit-user-select: none; } :root[data-save="blocked"] .save-indicator, :root[data-save="blocked"] .data-warn { bottom: 74px; } /* The version is chrome: present for orientation, never competing with the plan. */-header .subject .app-ver { color: var(--text3); }+header .brand .app-ver { color: var(--text3); } .sel-count { position: fixed; bottom: 16px; left: 16px; font-family: 'JetBrains Mono', monospace; font-size: 10px; color: var(--accent); background: var(--elevated); border: 1px solid var(--border); border-left: 3px solid var(--accent); border-radius: 7px; padding: 6px 11px; box-shadow: 0 6px 18px rgba(0,0,0,0.42); z-index: 99998; opacity: 0; transform: translateY(8px); transition: opacity 0.18s ease-out, transform 0.18s ease-out; pointer-events: none; cursor: pointer; } .sel-count.show { opacity: 1; transform: translateY(0); pointer-events: auto; } .sel-count:hover { border-color: var(--accent); color: var(--accent-bright); }@@ -2622,7 +2628,7 @@ function buildHeader(){ $('printTitle').innerHTML = `<div class="pt-name">${esc(project.title||project.appName||'')}</div>${project.subtitle?`<div class="pt-sub">${esc(project.subtitle)}</div>`:''}`; $('hdr').innerHTML = `   <div class="brand" title="${esc(brandTip())}"><svg class="logo" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><rect x="3" y="4" width="18" height="2" rx="1" opacity="0.5"/><rect x="5" y="9" width="12" height="2" rx="1"/><rect x="3" y="14" width="16" height="2" rx="1" opacity="0.7"/><rect x="7" y="19" width="10" height="2" rx="1" opacity="0.5"/></svg>-    <span class="app-name">${esc(brandName())}</span></div>+    <span class="brand-txt"><span class="app-name">${esc(brandName())}</span>${APP_VERSION?`<span class="app-ver" title="adom-gantt ${esc(APP_VERSION)}">v${esc(APP_VERSION)}</span>`:''}</span></div>   <div class="vsep"></div>   <!-- The lens switch is the primary control, so it sits first in the row, anchored        to the brand block, which never changes width. It used to live inside .actions,@@ -2650,7 +2656,7 @@ $('hdr').innerHTML = `   <div class="subject"><div class="span-block">     <span class="span-stat" id="spanDur"><span class="span-k"><span class="k-long">Project </span>Duration:</span><span class="span-v" id="spanDurV"></span></span>     <span class="span-stat" id="spanLeft"><span class="span-k"><span class="k-long">Time </span>Remaining:</span><span class="span-v" id="spanLeftV"></span><span class="span-n" id="spanLeftN"></span></span>-  </div>${APP_VERSION?`<span class="app-ver" title="adom-gantt ${esc(APP_VERSION)}">v${esc(APP_VERSION)}</span>`:''}</div>+  </div></div>   <div class="start-ctl" title="Project start. Changing it moves the whole plan.">     <label>starts</label>     <button class="date-btn" id="startBtn"></button>
package.json+1−1
@@ -2,7 +2,7 @@   "slug": "adom-gantt",   "title": "Adom Gantt",   "type": "app",-  "version": "0.64.1",+  "version": "0.64.2",   "description": "Interactive Gantt chart viewer for project timelines, with a table view and an analytics page over the same data. Data-driven, dark by default with a print-friendly light mode, and fully editable in the browser: drag bars to move or resize, multi-select and batch-shift dates, manage dependency arrows inline, reorder rows, filter by phase, and undo. One click auto-schedules the whole plan so every dependency lines up finish-to-start on working days, skipping weekends and US federal holidays, pushing work LATER only so a lead-time gap you set on purpose is never closed, and one more lights up the critical path, meaning the longest run of work inside every section at once. Cancelled work is left out of both: it never moves, it constrains nothing and it can never glow. Dependency arrows are coloured by the phase of the task they come out of, so where a chain starts reads at a glance. Toggle to the table for every task and milestone as a row with owner, deadline and status, filtered per owner and edited in place, or to analytics for total, remaining and average hours, one row per person carrying both their hours and their status counts, per-section totals, milestones, dependency stats and what is overdue. Copy and paste rows: Ctrl+C the selected tasks and milestones, Ctrl+V to drop clones directly below a selected row or at the end of the lane you are looking at, with dependencies AMONG the copied rows remapped onto the copies so a duplicated chain is still a chain, links pointing outside it left naming the originals, and the whole paste one undo and one changelog line. Five statuses in lifecycle order, not started, in progress, complete, blocked, cancelled, with cancelled keeping the row and its history on the plan while taking its hours out of every total. Every edit is recorded in an append-only changelog so an AI can read what a human changed and build on it. Imports JSON, CSV, MS Project XML and Jira CSV; exports JSON, CSV, SVG and a self-contained HTML snapshot.",   "main": "server.js",   "bin": {
page.json+1−1
@@ -2,7 +2,7 @@   "slug": "adom-gantt",   "title": "Adom Gantt",   "type": "app",-  "version": "0.64.1",+  "version": "0.64.2",   "description": "Interactive Gantt chart viewer for project timelines, with a table view and an analytics page over the same data. Data-driven, dark by default with a print-friendly light mode, and fully editable in the browser: drag bars to move or resize, multi-select and batch-shift dates, manage dependency arrows inline, reorder rows, filter by phase, and undo. One click auto-schedules the whole plan so every dependency lines up finish-to-start on working days, skipping weekends and US federal holidays, pushing work LATER only so a lead-time gap you set on purpose is never closed, and one more lights up the critical path, meaning the longest run of work inside every section at once. Cancelled work is left out of both: it never moves, it constrains nothing and it can never glow. Dependency arrows are coloured by the phase of the task they come out of, so where a chain starts reads at a glance. Toggle to the table for every task and milestone as a row with owner, deadline and status, filtered per owner and edited in place, or to analytics for total, remaining and average hours, one row per person carrying both their hours and their status counts, per-section totals, milestones, dependency stats and what is overdue. Copy and paste rows: Ctrl+C the selected tasks and milestones, Ctrl+V to drop clones directly below a selected row or at the end of the lane you are looking at, with dependencies AMONG the copied rows remapped onto the copies so a duplicated chain is still a chain, links pointing outside it left naming the originals, and the whole paste one undo and one changelog line. Five statuses in lifecycle order, not started, in progress, complete, blocked, cancelled, with cancelled keeping the row and its history on the plan while taking its hours out of every total. Every edit is recorded in an append-only changelog so an AI can read what a human changed and build on it. Imports JSON, CSV, MS Project XML and Jira CSV; exports JSON, CSV, SVG and a self-contained HTML snapshot.",   "main": "server.js",   "bin": {
test/ui_test.mjs+9
@@ -849,6 +849,15 @@ async function main() {         const readoutVisible = await page.evaluate(() => { const e = document.getElementById('spanLeftV'); const x = e.getBoundingClientRect(); const s = document.querySelector('#hdr .subject').getBoundingClientRect();           return window.__uiVis(e) && x.width > 0 && x.right <= innerWidth && x.right <= s.right + 0.5; });         check('Time Remaining is on screen and not clipped', readoutVisible);+        // The version is on every lens at every width (0.64.2): under the app name, never shed.+        const verOn = [];+        for (const lens of ['gantt', 'table', 'analytics', 'setup']) {+          await view(page, lens);+          verOn.push(lens + ':' + await page.evaluate(() => { const e = document.querySelector('#hdr .brand .app-ver'); if (!e) return 'none';+            const x = e.getBoundingClientRect(); return window.__uiVis(e) && x.width > 0 && x.left >= 0 && x.right <= innerWidth ? e.textContent : 'hidden'; }));+        }+        await view(page, 'gantt');+        check('the version shows on all four pages', verOn.every(v => /:v\d+\.\d+\.\d+$/.test(v)), verOn.join(' '));         await page.click('#btnCollapseAll'); await settle(page);         check('Collapse all works here', await page.evaluate(() => document.querySelectorAll('.lane-toggle.collapsed').length) === 20);         await page.click('#btnCollapseAll'); await settle(page);