Merge pull request #4 from griffemi/worktree-calendar-status-lines

Calendar totals: compact per-category status lines
This commit is contained in:
Emi Griffith 2026-07-10 18:31:30 -07:00 committed by GitHub
commit cbef45db13
2 changed files with 43 additions and 14 deletions

View file

@ -673,7 +673,7 @@ function renderTotals(visible) {
.map((r) => { const g = metric === "feels" ? feelsPick(r) : r[metric]; return g && g.c; })
.filter(Boolean);
buckets = SCALE_TEMP.map((t) =>
[t.label, TIER_COLORS[t.c], classes.filter((c) => c === t.c).length]);
[t.label, TIER_COLORS[t.c], classes.filter((c) => c === t.c).length, t.c === "normal"]);
title = (TEMP_METRIC_INFO[metric] || {}).label || "value";
}
@ -687,14 +687,26 @@ function renderTotals(visible) {
totEl.hidden = false;
return;
}
const bar = buckets.filter((b) => b[2] > 0).map(([label, color, n]) =>
`<span style="width:${(100 * n / total).toFixed(2)}%;background:${color}" title="${label} · ${pctText(n)} (${n})"></span>`).join("");
const chips = buckets.filter((b) => b[2] > 0).map(([label, color, n]) =>
`<div class="tk-seg"><span class="tk-swatch" style="background:${color}"></span>
<span class="tk-label">${label}</span><span class="ct-pct">${pctText(n)}</span></div>`).join("");
// A compact deviation strip: one thin status-colored line per category, ordered
// low→high like the color scale, with each share printed above it in that
// category's own color. The median tier (the neutral "Normal" center of the
// diverging temperature scale) is the reference — its share is shown but it draws
// no line, just a faint baseline tick. Precip/dry-streak have no median, so every
// category there gets a line. Category names live in the color key below the grid,
// so this stays terse. Line heights scale to the tallest non-median category.
const maxLine = Math.max(1, ...buckets.filter((b) => !b[3]).map((b) => b[2]));
const LINE_MAX = 30; // px — height of the most common (non-median) category
const cols = buckets.map(([label, color, n, isMed]) => {
const h = isMed || !n ? 0 : Math.max(2, Math.round(LINE_MAX * n / maxLine));
const num = n ? pctText(n) : "0";
const line = h ? `<span class="ct-line" style="height:${h}px"></span>` : "";
const mid = isMed ? `<span class="ct-mid" aria-hidden="true"></span>` : "";
return `<div class="ct-col${isMed ? " ct-col-median" : ""}" style="--c:${color}" ` +
`title="${label} · ${pctText(n)} (${n})">` +
`<span class="ct-num${n ? "" : " ct-num-zero"}">${num}</span>${line}${mid}</div>`;
}).join("");
totEl.innerHTML = `<div class="section-title">${head}</div>
<div class="ct-bar">${bar}</div>
<div class="tier-key">${chips}</div>`;
<div class="ct-strip" style="--line-max:${LINE_MAX}px">${cols}</div>`;
totEl.hidden = false;
}

View file

@ -736,14 +736,31 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 24px 60px; }
}
.comfort-row .hint { flex: 1 1 100%; margin: 0; font-size: 12px; color: var(--muted); }
/* Category totals above the grid: stacked share bar + per-category chips. */
/* Category totals above the grid: a compact deviation strip. Each category is a
column with its share printed at the top (in that category's own status color)
and a thin status-colored line rising from a shared baseline (height share).
The median tier draws no line just a faint baseline tick as the neutral anchor. */
.cal-totals { max-width: 560px; margin: 0 0 18px; }
.ct-bar {
display: flex; height: 14px; border-radius: 7px; overflow: hidden;
margin: 6px 0 8px; background: var(--surface-2);
.ct-strip {
display: flex; align-items: flex-end; gap: 6px;
height: calc(var(--line-max, 30px) + 22px); margin: 8px 0 6px;
}
.ct-col { position: relative; flex: 1 1 0; min-width: 0; height: 100%; }
.ct-num {
position: absolute; top: 0; left: 0; right: 0; text-align: center;
font-size: 11.5px; font-weight: 700; line-height: 1;
color: color-mix(in oklab, var(--c, var(--muted)), var(--text) 40%);
}
.ct-num-zero { font-weight: 600; opacity: .38; }
.ct-line {
position: absolute; bottom: 0; left: 50%; transform: translateX(-50%);
width: 3px; border-radius: 2px 2px 0 0; background: var(--c);
}
.ct-col-median .ct-num { color: var(--muted); font-weight: 800; }
.ct-mid {
position: absolute; bottom: 0; left: 50%; transform: translateX(-50%);
width: 7px; height: 3px; border-radius: 2px; background: var(--border);
}
.ct-bar span { display: block; height: 100%; }
.ct-pct { color: var(--muted); font-size: 12px; }
/* Days filtered out by the weather filter fade back so matches pop. */
.cal-cell.dim { opacity: .15; }