Highlight the selected day in the per-day charts
A soft accent band behind the selected day's bars/cells (sleep, counts, food, training heatmap) — visible even when the day's values are zero — plus an accent-colored day label, and an accent ring on the selected row of the sleep timeline. The band tracks the day picker, so tapping into a chart immediately shows which slice you landed on.
This commit is contained in:
+34
-8
@@ -989,20 +989,27 @@
|
|||||||
parts.push(`<text x="${ML - 4}" y="${y + 3}" text-anchor="end">${vText}h</text>`);
|
parts.push(`<text x="${ML - 4}" y="${y + 3}" text-anchor="end">${vText}h</text>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selYmd = ymd(selectedDay());
|
||||||
days.forEach((d, i) => {
|
days.forEach((d, i) => {
|
||||||
const isToday = i === days.length - 1;
|
const isToday = i === days.length - 1;
|
||||||
|
const isSel = d.ymd === selYmd;
|
||||||
const x = ML + i * (barW + gap);
|
const x = ML + i * (barW + gap);
|
||||||
const h = (d.sleepHours / yMax) * innerH;
|
const h = (d.sleepHours / yMax) * innerH;
|
||||||
const y = MT + innerH - h;
|
const y = MT + innerH - h;
|
||||||
const title = `${d.date.toLocaleDateString(undefined, { weekday: "long", month: "short", day: "numeric" })} — ${d.sleepHours.toFixed(1)}h`;
|
const title = `${d.date.toLocaleDateString(undefined, { weekday: "long", month: "short", day: "numeric" })} — ${d.sleepHours.toFixed(1)}h`;
|
||||||
|
if (isSel) {
|
||||||
|
parts.push(`<rect class="day-highlight" x="${(x - gap / 2).toFixed(1)}" y="${MT}" width="${(barW + gap).toFixed(1)}" height="${innerH}" rx="3"/>`);
|
||||||
|
}
|
||||||
parts.push(
|
parts.push(
|
||||||
`<rect class="bar bar-sleep ${isToday ? "" : "bar-faded"}" data-day="${d.ymd}" ` +
|
`<rect class="bar bar-sleep ${isToday ? "" : "bar-faded"}" data-day="${d.ymd}" ` +
|
||||||
`x="${x}" y="${y}" width="${barW}" height="${Math.max(0, h)}" rx="3">` +
|
`x="${x}" y="${y}" width="${barW}" height="${Math.max(0, h)}" rx="3">` +
|
||||||
`<title>${escapeText(title)}</title></rect>`
|
`<title>${escapeText(title)}</title></rect>`
|
||||||
);
|
);
|
||||||
if (showDayLabel(i, days.length)) {
|
// The selected day always gets a label (accent-colored), even on wide
|
||||||
|
// windows that would otherwise skip it.
|
||||||
|
if (showDayLabel(i, days.length) || isSel) {
|
||||||
parts.push(
|
parts.push(
|
||||||
`<text x="${x + barW / 2}" y="${H - MB + 14}" text-anchor="middle">` +
|
`<text class="${isSel ? "day-label-sel" : ""}" x="${x + barW / 2}" y="${H - MB + 14}" text-anchor="middle">` +
|
||||||
`${escapeText(dayLabel(d.date, isToday))}</text>`
|
`${escapeText(dayLabel(d.date, isToday))}</text>`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1040,10 +1047,15 @@
|
|||||||
{ key: "meals", label: "Meals", cls: "bar-eat" },
|
{ key: "meals", label: "Meals", cls: "bar-eat" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const selYmd = ymd(selectedDay());
|
||||||
days.forEach((d, i) => {
|
days.forEach((d, i) => {
|
||||||
const isToday = i === days.length - 1;
|
const isToday = i === days.length - 1;
|
||||||
|
const isSel = d.ymd === selYmd;
|
||||||
const groupX = ML + i * (groupW + groupGap);
|
const groupX = ML + i * (groupW + groupGap);
|
||||||
|
|
||||||
|
if (isSel) {
|
||||||
|
parts.push(`<rect class="day-highlight" x="${(groupX - groupGap / 2).toFixed(1)}" y="${MT}" width="${(groupW + groupGap).toFixed(1)}" height="${innerH}" rx="3"/>`);
|
||||||
|
}
|
||||||
series.forEach((s, j) => {
|
series.forEach((s, j) => {
|
||||||
const val = d[s.key];
|
const val = d[s.key];
|
||||||
const x = groupX + j * (barW + innerBarGap);
|
const x = groupX + j * (barW + innerBarGap);
|
||||||
@@ -1057,9 +1069,9 @@
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (showDayLabel(i, days.length)) {
|
if (showDayLabel(i, days.length) || isSel) {
|
||||||
parts.push(
|
parts.push(
|
||||||
`<text x="${groupX + groupW / 2}" y="${H - MB + 14}" text-anchor="middle">` +
|
`<text class="${isSel ? "day-label-sel" : ""}" x="${groupX + groupW / 2}" y="${H - MB + 14}" text-anchor="middle">` +
|
||||||
`${escapeText(dayLabel(d.date, isToday))}</text>`
|
`${escapeText(dayLabel(d.date, isToday))}</text>`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1095,20 +1107,25 @@
|
|||||||
parts.push(`<text x="${ML - 4}" y="${y + 3}" text-anchor="end">${vText}</text>`);
|
parts.push(`<text x="${ML - 4}" y="${y + 3}" text-anchor="end">${vText}</text>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selYmd = ymd(selectedDay());
|
||||||
days.forEach((d, i) => {
|
days.forEach((d, i) => {
|
||||||
const isToday = i === days.length - 1;
|
const isToday = i === days.length - 1;
|
||||||
|
const isSel = d.ymd === selYmd;
|
||||||
const x = ML + i * (barW + gap);
|
const x = ML + i * (barW + gap);
|
||||||
const h = (d.grams / yMax) * innerH;
|
const h = (d.grams / yMax) * innerH;
|
||||||
const y = MT + innerH - h;
|
const y = MT + innerH - h;
|
||||||
const title = `${d.date.toLocaleDateString(undefined, { weekday: "long", month: "short", day: "numeric" })} — ${Math.round(d.grams)} g`;
|
const title = `${d.date.toLocaleDateString(undefined, { weekday: "long", month: "short", day: "numeric" })} — ${Math.round(d.grams)} g`;
|
||||||
|
if (isSel) {
|
||||||
|
parts.push(`<rect class="day-highlight" x="${(x - gap / 2).toFixed(1)}" y="${MT}" width="${(barW + gap).toFixed(1)}" height="${innerH}" rx="3"/>`);
|
||||||
|
}
|
||||||
parts.push(
|
parts.push(
|
||||||
`<rect class="bar bar-eat ${isToday ? "" : "bar-faded"}" data-day="${d.ymd}" ` +
|
`<rect class="bar bar-eat ${isToday ? "" : "bar-faded"}" data-day="${d.ymd}" ` +
|
||||||
`x="${x}" y="${y}" width="${barW}" height="${Math.max(0, h)}" rx="3">` +
|
`x="${x}" y="${y}" width="${barW}" height="${Math.max(0, h)}" rx="3">` +
|
||||||
`<title>${escapeText(title)}</title></rect>`
|
`<title>${escapeText(title)}</title></rect>`
|
||||||
);
|
);
|
||||||
if (showDayLabel(i, days.length)) {
|
if (showDayLabel(i, days.length) || isSel) {
|
||||||
parts.push(
|
parts.push(
|
||||||
`<text x="${x + barW / 2}" y="${H - MB + 14}" text-anchor="middle">` +
|
`<text class="${isSel ? "day-label-sel" : ""}" x="${x + barW / 2}" y="${H - MB + 14}" text-anchor="middle">` +
|
||||||
`${escapeText(dayLabel(d.date, isToday))}</text>`
|
`${escapeText(dayLabel(d.date, isToday))}</text>`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1157,15 +1174,17 @@
|
|||||||
parts.push(`<text x="${x.toFixed(1)}" y="${MT - 5}" text-anchor="${anchor}">${hr}h</text>`);
|
parts.push(`<text x="${x.toFixed(1)}" y="${MT - 5}" text-anchor="${anchor}">${hr}h</text>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selYmd = ymd(selectedDay());
|
||||||
for (let i = 0; i < N; i++) {
|
for (let i = 0; i < N; i++) {
|
||||||
const day = new Date(today);
|
const day = new Date(today);
|
||||||
day.setDate(day.getDate() - (N - 1 - i)); // oldest at top, today at bottom
|
day.setDate(day.getDate() - (N - 1 - i)); // oldest at top, today at bottom
|
||||||
const dayStart = startOfDay(day).getTime();
|
const dayStart = startOfDay(day).getTime();
|
||||||
const dayEnd = dayStart + dayMs;
|
const dayEnd = dayStart + dayMs;
|
||||||
const isToday = ymd(day) === ymd(new Date());
|
const isToday = ymd(day) === ymd(new Date());
|
||||||
|
const isSel = ymd(day) === selYmd;
|
||||||
const y = MT + i * (rowH + rowGap);
|
const y = MT + i * (rowH + rowGap);
|
||||||
|
|
||||||
parts.push(`<rect class="stl-track" x="${ML}" y="${y.toFixed(1)}" width="${innerW}" height="${rowH.toFixed(1)}" rx="2"/>`);
|
parts.push(`<rect class="stl-track${isSel ? " stl-selected" : ""}" x="${ML}" y="${y.toFixed(1)}" width="${innerW}" height="${rowH.toFixed(1)}" rx="2"/>`);
|
||||||
|
|
||||||
for (const wdw of windows) {
|
for (const wdw of windows) {
|
||||||
const s = Math.max(wdw.start, dayStart);
|
const s = Math.max(wdw.start, dayStart);
|
||||||
@@ -1177,7 +1196,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const label = isToday ? "Today" : `${day.toLocaleDateString(undefined, { weekday: "short" })} ${day.getDate()}`;
|
const label = isToday ? "Today" : `${day.toLocaleDateString(undefined, { weekday: "short" })} ${day.getDate()}`;
|
||||||
parts.push(`<text class="stl-day ${isToday ? "stl-today" : ""}" x="${ML - 6}" y="${(y + rowH / 2 + 3).toFixed(1)}" text-anchor="end">${escapeText(label)}</text>`);
|
parts.push(`<text class="stl-day ${isToday ? "stl-today" : ""}${isSel ? " stl-sel" : ""}" x="${ML - 6}" y="${(y + rowH / 2 + 3).toFixed(1)}" text-anchor="end">${escapeText(label)}</text>`);
|
||||||
|
|
||||||
const title = day.toLocaleDateString(undefined, { weekday: "long", month: "short", day: "numeric" });
|
const title = day.toLocaleDateString(undefined, { weekday: "long", month: "short", day: "numeric" });
|
||||||
parts.push(`<rect class="bar stl-hit" data-day="${ymd(day)}" x="${ML}" y="${y.toFixed(1)}" width="${innerW}" height="${rowH.toFixed(1)}"><title>${escapeText(title)}</title></rect>`);
|
parts.push(`<rect class="bar stl-hit" data-day="${ymd(day)}" x="${ML}" y="${y.toFixed(1)}" width="${innerW}" height="${rowH.toFixed(1)}"><title>${escapeText(title)}</title></rect>`);
|
||||||
@@ -1584,6 +1603,13 @@
|
|||||||
const cellW = innerW / N;
|
const cellW = innerW / N;
|
||||||
|
|
||||||
const parts = [];
|
const parts = [];
|
||||||
|
const selCol = dayIndex.get(ymd(selectedDay()));
|
||||||
|
if (selCol !== undefined) {
|
||||||
|
parts.push(
|
||||||
|
`<rect class="day-highlight" x="${(ML + selCol * cellW - 0.75).toFixed(1)}" y="${MT - 2}" ` +
|
||||||
|
`width="${cellW.toFixed(1)}" height="${(H - MT - MB + 4).toFixed(1)}" rx="3"/>`
|
||||||
|
);
|
||||||
|
}
|
||||||
exercises.forEach((x, r) => {
|
exercises.forEach((x, r) => {
|
||||||
const y = MT + r * (rowH + rowGap);
|
const y = MT + r * (rowH + rowGap);
|
||||||
const max = Math.max(1, ...counts[r]);
|
const max = Math.max(1, ...counts[r]);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
[
|
[
|
||||||
|
{ "date": "2026-07-15", "text": "The charts highlight the selected day, so it's easy to spot which bars, rows and cells you're looking at" },
|
||||||
{ "date": "2026-07-15", "text": "New Sleep trend chart: today's running sleep total through the day, against yesterday and the average over your chart window (7/14/30 days)" },
|
{ "date": "2026-07-15", "text": "New Sleep trend chart: today's running sleep total through the day, against yesterday and the average over your chart window (7/14/30 days)" },
|
||||||
{ "date": "2026-07-15", "text": "Quick actions that don't fit right now are dimmed (asleep → everything but Sleep end; awake → Sleep end) — still tappable for corrections" },
|
{ "date": "2026-07-15", "text": "Quick actions that don't fit right now are dimmed (asleep → everything but Sleep end; awake → Sleep end) — still tappable for corrections" },
|
||||||
{ "date": "2026-07-15", "text": "Editing an event no longer pops the date picker over the whole screen on iPhone" },
|
{ "date": "2026-07-15", "text": "Editing an event no longer pops the date picker over the whole screen on iPhone" },
|
||||||
|
|||||||
@@ -603,6 +603,16 @@ dialog menu {
|
|||||||
}
|
}
|
||||||
.chart-svg .bar { cursor: pointer; }
|
.chart-svg .bar { cursor: pointer; }
|
||||||
.chart-svg .bar-faded { opacity: 0.7; }
|
.chart-svg .bar-faded { opacity: 0.7; }
|
||||||
|
/* The selected day's slice in every per-day chart: a soft accent band behind
|
||||||
|
the bars/cells (visible even when the day's values are all zero) plus an
|
||||||
|
accent-colored day label. */
|
||||||
|
.chart-svg .day-highlight {
|
||||||
|
fill: var(--accent);
|
||||||
|
fill-opacity: 0.08;
|
||||||
|
stroke: var(--accent);
|
||||||
|
stroke-opacity: 0.45;
|
||||||
|
}
|
||||||
|
.chart-svg text.day-label-sel { fill: var(--accent); font-weight: 600; }
|
||||||
.chart-svg .bar-sleep { fill: var(--sleep); }
|
.chart-svg .bar-sleep { fill: var(--sleep); }
|
||||||
.chart-svg .bar-pee { fill: var(--pee); }
|
.chart-svg .bar-pee { fill: var(--pee); }
|
||||||
.chart-svg .bar-poo { fill: var(--poo); }
|
.chart-svg .bar-poo { fill: var(--poo); }
|
||||||
@@ -897,6 +907,13 @@ input.switch:checked::after { transform: translateX(18px); }
|
|||||||
}
|
}
|
||||||
.chart-svg .stl-sleep { fill: var(--sleep); }
|
.chart-svg .stl-sleep { fill: var(--sleep); }
|
||||||
.chart-svg .stl-today { fill: var(--accent); font-weight: 600; }
|
.chart-svg .stl-today { fill: var(--accent); font-weight: 600; }
|
||||||
|
/* Selected day: accent ring on the row's track + accent label. */
|
||||||
|
.chart-svg .stl-track.stl-selected {
|
||||||
|
stroke: var(--accent);
|
||||||
|
stroke-width: 1.2;
|
||||||
|
stroke-opacity: 0.8;
|
||||||
|
}
|
||||||
|
.chart-svg .stl-sel { fill: var(--accent); }
|
||||||
.chart-svg .stl-hit { fill: transparent; cursor: pointer; }
|
.chart-svg .stl-hit { fill: transparent; cursor: pointer; }
|
||||||
.chart-svg .stl-hit:hover { fill: var(--accent); fill-opacity: 0.08; }
|
.chart-svg .stl-hit:hover { fill: var(--accent); fill-opacity: 0.08; }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user