Add event span bars to timeline and anchor view near current time
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) <noreply@anthropic.com>
This commit is contained in:
parent
32e9b85857
commit
623d03e843
1 changed files with 43 additions and 6 deletions
|
|
@ -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 (
|
||||
<section style={{ padding: '10px 14px 10px 18px', display: 'flex', flexDirection: 'column', minHeight: 0 }}>
|
||||
<SectionTitle
|
||||
|
|
@ -317,6 +338,22 @@ const Agenda = ({ events, weather }: { events: AgendaEvent[]; weather?: WeatherD
|
|||
<div style={{ display: 'flex', gap: 10, flex: 1, minHeight: 0 }}>
|
||||
{/* Timeline rail */}
|
||||
<div style={{ width: 14, position: 'relative', borderRight: '1px dashed var(--rule)', flex: '0 0 14px' }}>
|
||||
{/* Event span bars */}
|
||||
{eventSpans.map((span, i) => (
|
||||
<div
|
||||
key={`span-${i}`}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: `${span.top * 100}%`,
|
||||
height: `${(span.bottom - span.top) * 100}%`,
|
||||
right: -1,
|
||||
width: 3,
|
||||
background: 'var(--ink)',
|
||||
opacity: span.past ? 0.25 : 1,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{/* Hour ticks */}
|
||||
{ticks.map((h) => {
|
||||
const p = (h * 60 - startMin) / rangeMin;
|
||||
return (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue