app
Adom Gantt
Public Made by Adomby adom
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, push
← Commit history
Publish 0.5.1
5 files changed
+13−31
README.md+1−1@@ -30,7 +30,7 @@ Interactive Gantt chart viewer for project timelines. Data-driven, dark by defau **Light mode.** Dark by default. The Light toggle switches to a print-friendly theme with deepened bar colors, and printing always uses it whatever the screen is set to. -**Brand phase colors.** A phase with no explicit `color` cycles the three Adom hues: teal, purple, blue. Section bands are neutral grey rather than colour tints, so colour on the chart means exactly one thing: which phase a bar belongs to. The hues are theme-aware, so the same plan is on-brand on screen and legible on paper.+**Brand phase colors.** A phase with no explicit `color` cycles the three Adom hues: teal, purple, blue. There is no background band behind a phase: the bar colour and the group header carry the section on their own, so colour on the chart means exactly one thing, which phase a bar belongs to. The hues are theme-aware, so the same plan is on-brand on screen and legible on paper. **Move the whole plan.** The project start sits in the header. Change it and every task, milestone and phase shifts by the same number of days, so durations and the gaps between them survive. Revert puts the plan back to the data file's own start. It is one undo step and one changelog entry, not 26.
SKILL.md+3−2@@ -146,8 +146,9 @@ reads as off-brand. Sections are separated by the neutral grey banding and the g header instead, so a repeat three rows down is not confusing. Adjacent phases are always different. -Phase bands are neutral: alternating sections get a subtle lighter grey, never a-colour tint, so colour on the chart means one thing only, which phase a bar belongs to.+There is no background band behind a phase. The bar colour and the group header row+carry the section on their own, which keeps the chart body clean and means colour on+the chart says one thing only: which phase a bar belongs to. Green, red and yellow are deliberately absent. In the Adom design system those mean success, destructive and warning, so a phase colored red reads as a problem
gantt.html+7−26@@ -28,7 +28,6 @@ /* Phase ramp: teal -> purple -> blue, then a lighter step of each. Used when a phase declares no explicit colour. */ --ph1: #00b8b1; --ph2: #8c6bf7; --ph3: #64abff;- --band: rgba(255,255,255,0.032); --bar-opacity: 0.82; color-scheme: dark; }@@ -43,7 +42,6 @@ --row-hover: rgba(31,35,40,0.04); /* Deepened for paper: each clears 3:1 on white while holding its hue. */ --ph1: #00a49d; --ph2: #8c6bf7; --ph3: #3b95ff;- --band: rgba(31,35,40,0.045); --bar-opacity: 1; color-scheme: light; }@@ -53,7 +51,7 @@ --border:#d0d7de; --border-muted:#d8dee4; --text:#1f2328; --text-body:#24292f; --text2:#59636e; --text3:#8c959f; --accent:#00857f; --today:#00857f; --grid-line:rgba(31,35,40,0.10); --weekend:rgba(31,35,40,0.04);- --ph1:#00a49d; --ph2:#8c6bf7; --ph3:#3b95ff; --band:rgba(31,35,40,0.045);+ --ph1:#00a49d; --ph2:#8c6bf7; --ph3:#3b95ff; color-scheme: light; } html, body { overflow: visible !important; height: auto !important; } .labels-col, .timeline-col { overflow: visible !important; }@@ -184,8 +182,6 @@ header .act-btn svg { width: 14px; height: 14px; } :root[data-ms="line"] .label-row.ms::before { content: '\00a6\00a0'; } .today-line { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--today); z-index: 8; pointer-events: none; box-shadow: 0 0 6px rgba(0,184,176,0.3); } .today-tag { position: absolute; top: 4px; transform: translateX(-50%); font-family: 'JetBrains Mono', monospace; font-size: 9px; color: var(--today); background: var(--bg); padding: 1px 4px; border-radius: 3px; border: 1px solid rgba(0,184,176,0.25); pointer-events: none; z-index: 9; white-space: nowrap; }-.phase-bg { position: absolute; top: 0; bottom: 0; pointer-events: none; background: var(--band); }-.phase-bg.alt { background: transparent; } .dep-svg { position: absolute; top: 0; left: 0; pointer-events: none; z-index: 4; overflow: visible; } .dep-svg path { fill: none; stroke: var(--accent); stroke-width: 1.5; opacity: 0.5; transition: opacity 0.15s; } .dep-svg polygon { fill: var(--accent); opacity: 0.5; transition: opacity 0.15s; }@@ -615,7 +611,7 @@ legendEl.appendChild(Object.assign(document.createElement('div'),{className:'leg // ── Build chart ── fitCOL();-const phaseBgEls=[], gridEls=[], msLineEls=[]; let todayLineEl=null, todayTagEl=null;+const gridEls=[], msLineEls=[]; let todayLineEl=null, todayTagEl=null; labelsEl.appendChild(Object.assign(document.createElement('div'),{className:'label-h-q'})); const qRow=document.createElement('div');qRow.className='q-row'; labelsEl.appendChild(Object.assign(document.createElement('div'),{className:'label-h-m'}));@@ -624,9 +620,9 @@ const mNames=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov', let qs=[]; const bars=document.createElement('div');bars.style.cssText=`position:relative;width:${W}px;`;-// Backgrounds and grid live in their own layers so changing the start date can-// rebuild them without disturbing the rows (and their bound handlers).-const bgLayer=document.createElement('div');bgLayer.style.cssText='position:absolute;inset:0;pointer-events:none;';bars.appendChild(bgLayer);+// The grid lives in its own layer so changing the start date can rebuild it without+// disturbing the rows (and their bound handlers). Phases are carried by the bar colour+// and the group header, so there is no background band. const gridLayer=document.createElement('div');gridLayer.style.cssText='position:absolute;inset:0;pointer-events:none;';bars.appendChild(gridLayer); // Quarter and month header cells, rebuilt whenever START or UNITS changes.@@ -650,20 +646,6 @@ function buildTimeHeaders(){ mRow.appendChild(c); } }-function buildPhaseBands(){- bgLayer.innerHTML='';phaseBgEls.length=0;- phases.forEach((p,i)=>{- const bg=document.createElement('div');bg.className='phase-bg';- const[sy,sm]=p.start.split('-').map(Number),[ey,em]=p.end.split('-').map(Number);- // toX handles every grain, so the band maths no longer branches per unit- const l=toX(`${sy}-${String(sm).padStart(2,'0')}-01`);- const endLast=new Date(ey,em,0);- const r=toX(isoDay(endLast));- bg.style.left=l+'px';bg.style.width=Math.max(2,r-l)+'px';- if(i%2)bg.classList.add('alt');- bgLayer.appendChild(bg);phaseBgEls.push(bg);- });-} function buildGridLines(){ gridLayer.innerHTML='';gridEls.length=0; const g=G();@@ -689,7 +671,7 @@ function buildGridLines(){ gridLayer.appendChild(l);gridEls.push(l); } }-buildTimeHeaders();buildPhaseBands();buildGridLines();+buildTimeHeaders();buildGridLines(); depSvg=document.createElementNS('http://www.w3.org/2000/svg','svg');depSvg.classList.add('dep-svg');depSvg.setAttribute('width',W);depSvg.setAttribute('height','1');bars.appendChild(depSvg); const statusTag={live:'tag-live',planned:'tag-planned','not-started':'tag-not-started'};@@ -747,7 +729,6 @@ timelineEl.addEventListener('scroll',()=>{labelsEl.scrollTop=timelineEl.scrollTo function relayout(){ fitCOL(); buildTimeHeaders();- buildPhaseBands(); buildGridLines(); bars.style.width=W+'px'; if(depSvg)depSvg.setAttribute('width',W);@@ -1271,7 +1252,7 @@ $('btnHelp').addEventListener('click',e=>{ function rebuildTimeline(){ computeRange(); fitCOL();- buildTimeHeaders();buildPhaseBands();buildGridLines();+ buildTimeHeaders();buildGridLines(); syncStartBtn(); relayout(); }
package.json+1−1@@ -2,7 +2,7 @@ "slug": "adom-gantt", "title": "Adom Gantt", "type": "app",- "version": "0.5.0",+ "version": "0.5.1", "description": "Interactive Gantt chart viewer for project timelines. 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. 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.5.0",+ "version": "0.5.1", "description": "Interactive Gantt chart viewer for project timelines. 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. 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": {