From 623d03e8434cc3028267f04b4939db5d7dd0452d Mon Sep 17 00:00:00 2001 From: Kate Meerburg Date: Sun, 24 May 2026 23:44:04 +0200 Subject: [PATCH] Add event span bars to timeline and anchor view near current time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The timeline rail now shows thick bars indicating event durations — full opacity for current/future events, dimmed for past. The timeline range anchors near the current time and extends to show upcoming hours, capped at midnight. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/todayview.tsx | 49 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/src/todayview.tsx b/src/todayview.tsx index 5b11aea..c6f546c 100644 --- a/src/todayview.tsx +++ b/src/todayview.tsx @@ -280,18 +280,32 @@ const TopBar = ({ data }: { data: TodayData }) => { /* ---------- Agenda ---------- */ +const parseTime = (t: string): number => { + const [h, m] = t.split(':').map(Number) as [number, number]; + return h * 60 + m; +}; + const Agenda = ({ events, weather }: { events: AgendaEvent[]; weather?: WeatherData }) => { const now = new Date(); const nowStr = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`; const nowMin = now.getHours() * 60 + now.getMinutes(); - // Derive timeline range from events - const startMin = events.length - ? parseInt(events[0]!.start.split(':')[0]!) * 60 - : 8 * 60; - const endMin = events.length - ? parseInt(events[events.length - 1]!.end.split(':')[0]!) * 60 + parseInt(events[events.length - 1]!.end.split(':')[1]!) + // Anchor timeline: start ~1h before now (rounded to even hour), end at last event or +8h + const lastEventEnd = events.length + ? parseTime(events[events.length - 1]!.end) : 17 * 60; + const firstEventStart = events.length + ? parseTime(events[0]!.start) + : 8 * 60; + + const startMin = Math.min( + firstEventStart, + Math.floor((nowMin - 60) / 120) * 120 + ); + const endMin = Math.min( + 24 * 60, + Math.max(lastEventEnd, nowMin + 4 * 60) + ); const rangeMin = Math.max(endMin - startMin, 1); const pct = Math.min(Math.max((nowMin - startMin) / rangeMin, 0), 1); @@ -304,6 +318,13 @@ const Agenda = ({ events, weather }: { events: AgendaEvent[]; weather?: WeatherD const startLabel = events[0]?.start ?? '08:00'; const endLabel = events[events.length - 1]?.end ?? '17:00'; + // Event spans for thick bars on the timeline rail + const eventSpans = events.map((e) => ({ + top: Math.max(0, (parseTime(e.start) - startMin) / rangeMin), + bottom: Math.min(1, (parseTime(e.end) - startMin) / rangeMin), + past: e.end <= nowStr, + })); + return (
{/* Timeline rail */}
+ {/* Event span bars */} + {eventSpans.map((span, i) => ( +
+ ))} + {/* Hour ticks */} {ticks.map((h) => { const p = (h * 60 - startMin) / rangeMin; return (