diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-02-01 10:52:28 -1000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-02-01 10:52:28 -1000 |
| commit | 1c6552117038cb7c01e016dbf1ac062e1d9f9c73 (patch) | |
| tree | ff65c67a40e08a14f89fe3057a8ac4886d94b75b /internal/handlers/timeline.go | |
| parent | e0e0dc11195c0e0516b45975de51df1dc98f83de (diff) | |
Improve timeline view with dynamic bounds, now line, and overlap handling
- Add dynamic calendar clipping: show 1 hour before/after events instead of hardcoded 6am-10pm
- Add "NOW" line indicator showing current time position
- Improve time label readability with larger font and better contrast
- Add overlap detection with column-based indentation for concurrent events
- Apply calendar view to Tomorrow section (matching Today's layout)
- Fix auto-refresh switching to tasks tab (default was 'tasks' instead of 'timeline')
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'internal/handlers/timeline.go')
| -rw-r--r-- | internal/handlers/timeline.go | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/internal/handlers/timeline.go b/internal/handlers/timeline.go index 5e583d6..fa5bcec 100644 --- a/internal/handlers/timeline.go +++ b/internal/handlers/timeline.go @@ -21,6 +21,19 @@ type TimelineData struct { TodayLabel string // e.g., "Today - Monday" TomorrowLabel string // e.g., "Tomorrow - Tuesday" LaterLabel string // e.g., "Wednesday, Jan 29" + + // Calendar view bounds (1 hour before first event, 1 hour after last) + TodayStartHour int + TodayEndHour int + TodayHours []int // Slice of hours to render + + TomorrowStartHour int + TomorrowEndHour int + TomorrowHours []int + + // Current time for "now" line + NowHour int + NowMinute int } // HandleTimeline renders the timeline view @@ -70,6 +83,8 @@ func (h *Handler) HandleTimeline(w http.ResponseWriter, r *http.Request) { TodayLabel: "Today - " + now.Format("Monday"), TomorrowLabel: "Tomorrow - " + tomorrow.Format("Monday"), LaterLabel: dayAfterTomorrow.Format("Monday, Jan 2") + "+", + NowHour: now.Hour(), + NowMinute: now.Minute(), } for _, item := range items { switch item.DaySection { @@ -82,5 +97,77 @@ func (h *Handler) HandleTimeline(w http.ResponseWriter, r *http.Request) { } } + // Calculate calendar bounds for Today (1 hour buffer before/after timed events) + data.TodayStartHour, data.TodayEndHour = calcCalendarBounds(data.TodayItems, now.Hour()) + for h := data.TodayStartHour; h <= data.TodayEndHour; h++ { + data.TodayHours = append(data.TodayHours, h) + } + + // Calculate calendar bounds for Tomorrow + data.TomorrowStartHour, data.TomorrowEndHour = calcCalendarBounds(data.TomorrowItems, -1) + for h := data.TomorrowStartHour; h <= data.TomorrowEndHour; h++ { + data.TomorrowHours = append(data.TomorrowHours, h) + } + HTMLResponse(w, h.templates, "timeline-tab", data) } + +// calcCalendarBounds returns start/end hours for calendar view based on timed events. +// If currentHour >= 0, it's included in the range (for "now" line visibility). +// Returns hours clamped to 0-23 with 1-hour buffer before/after events. +func calcCalendarBounds(items []models.TimelineItem, currentHour int) (startHour, endHour int) { + minHour := 23 + maxHour := 0 + hasTimedEvents := false + + for _, item := range items { + // Skip all-day/overdue items (midnight with no real time) + if item.IsAllDay || item.IsOverdue { + continue + } + h := item.Time.Hour() + // Skip midnight items unless they have an end time + if h == 0 && item.Time.Minute() == 0 && item.EndTime == nil { + continue + } + hasTimedEvents = true + if h < minHour { + minHour = h + } + endH := h + if item.EndTime != nil { + endH = item.EndTime.Hour() + } + if endH > maxHour { + maxHour = endH + } + } + + // Include current hour if provided + if currentHour >= 0 { + hasTimedEvents = true + if currentHour < minHour { + minHour = currentHour + } + if currentHour > maxHour { + maxHour = currentHour + } + } + + if !hasTimedEvents { + // Default: show 8am-6pm + return 8, 18 + } + + // Add 1 hour buffer, clamp to valid range + startHour = minHour - 1 + if startHour < 0 { + startHour = 0 + } + endHour = maxHour + 1 + if endHour > 23 { + endHour = 23 + } + + return startHour, endHour +} |
