Draw each timing row as a range chart

A pair of numbers per type says how long the gaps are but not where the puppy
currently sits between them, which is the thing you actually want when
deciding whether to go out now. Each row becomes a small chart instead: a band
from the shortest to the typical gap, a marker for time since the last one,
and a scale of [min(shortest, since), max(typical, since)] so the marker is
free to land inside the band, off its left end (just went) or off its right
end (due).

Three cases the layout has to survive. A gap in tracking can leave "since" at
days against a typical gap of hours, so past twice the typical the marker
parks at the right edge behind a chevron and its label keeps the real number —
squashing the band to a sliver would be worse, and clamping silently would
read as being in range. A band too narrow to hang a label off each end carries
both values centred over its middle rather than pinned to the track ends,
where they would imply a spread the band does not have. Under two events there
is no gap at all, so the row falls back to a sentence instead of an axis with
nothing on it.

The marker is ink over a surface-coloured ring so it stays legible on any band
colour in either theme, and the gap between a label's word and its value is an
explicit dx: a trailing space inside a tspan does not survive XML whitespace
normalisation.
This commit is contained in:
Alexander Heldt
2026-08-24 13:14:45 +00:00
parent 29b961c1b0
commit b42ea2e309
4 changed files with 187 additions and 18 deletions
+28
View File
@@ -352,6 +352,34 @@ button.danger { background: var(--danger); }
font-weight: normal;
}
.timing-hint { margin: 10px 4px 0; line-height: 1.4; }
/* ---------- timing range charts ---------- */
.timing-charts {
display: flex;
flex-direction: column;
gap: 12px;
}
.timing-name {
color: var(--muted);
font-size: 0.95rem;
padding: 0 4px;
}
.timing-chart { display: block; width: 100%; height: auto; }
/* Values wear ink, the words beside them are muted — the band alone carries
which type a chart is about (its heading says it too). */
.timing-chart text { fill: var(--text); font-size: 9px; font-variant-numeric: tabular-nums; }
.timing-chart .tm-word { fill: var(--muted); }
.timing-chart .tm-track { fill: var(--border); }
.timing-chart .tm-tick { stroke: var(--muted); stroke-width: 1; opacity: 0.45; }
.timing-chart .tm-pee { fill: var(--pee); }
.timing-chart .tm-poo { fill: var(--poo); }
.timing-chart .tm-eat { fill: var(--eat); }
/* "Since the last one" marker: ink over a surface-coloured ring, so it stays
readable on top of any band colour in either theme. */
.timing-chart .tm-now-ring { stroke: var(--surface); stroke-width: 7; stroke-linecap: round; }
.timing-chart .tm-now { stroke: var(--text); stroke-width: 3; stroke-linecap: round; }
.timing-chart .tm-over { fill: var(--text); }
.timing-note { margin: 2px 4px 0; }
.settings-hint { color: var(--muted); font-size: 0.8rem; margin: -4px 0 4px; line-height: 1.4; }
.history-controls {