Bracket sleep and walk pairs in the history log

A pair reads as two unrelated rows in the day's log: "Walk start 08:00" and
"Walk end 08:30" sit apart from each other and, with a pee logged in between,
apart from anything that happened while the puppy was out.

A dotted rail down the margin ties the pair together, in that pair's colour.
It runs the full span rather than only touching the two boundary rows, so
whatever was logged in between falls inside the bracket — a pee taken on a
walk now reads as having happened during it, which is the more useful claim
and comes for free once the rail spans rows at all.

Which rows a span covers comes from the same sleepWindowsForDay /
walkWindowsForDay the Sleep and Walks panels draw, so a pair crossing midnight
is treated identically in both places. Where a span's boundary isn't a row in
this day — an ongoing walk, or one that ran over from yesterday — that end of
the rail is left open and runs off the edge of the list, rather than anchoring
on a row that didn't start or end anything. A boundary with no partner in the
day draws nothing: a rail needs two rows to tie.

The roles are named for the rendered list, which runs newest-first, so a span's
last event is its top row and the rail is built downward from there.

It costs no layout. The rail is drawn in the padding the section already has,
left of the cards, so no row indents or moves; the anchored end stops level
with the row's dot and the open ends overshoot the list gap so consecutive
segments join into one line.
This commit is contained in:
Alexander Heldt
2026-08-31 21:32:06 +00:00
parent f162ac5732
commit d551bb96eb
3 changed files with 62 additions and 1 deletions
+19
View File
@@ -496,6 +496,25 @@ textarea { resize: vertical; }
border-radius: 50%;
flex-shrink: 0;
}
/* Rail bracketing a sleep or walk pair in the history log (see historyRails).
It is drawn in the section's own padding, left of the cards, so tying rows
together costs no layout: nothing indents and no row moves. The anchored end
stops at the row's middle, level with its dot; the other ends overshoot the
6px list gap by 4px each so consecutive segments overlap into one line. */
.event.rail { position: relative; }
.event.rail::before {
content: "";
position: absolute;
left: -10px;
width: 0;
border-left: 2px dotted var(--rail, var(--border));
}
.event.rail-top::before { top: 50%; bottom: -4px; }
.event.rail-mid::before { top: -4px; bottom: -4px; }
.event.rail-bottom::before { top: -4px; bottom: 50%; }
.event.rail-sleep { --rail: color-mix(in srgb, var(--sleep) 70%, transparent); }
.event.rail-walk { --rail: color-mix(in srgb, var(--walk) 70%, transparent); }
.event[data-type="sleep-start"] .dot,
.event[data-type="sleep-end"] .dot { background: var(--sleep); }
.event[data-type="eat"] .dot { background: var(--eat); }