diff options
| author | Ben Sima <ben@bensima.com> | 2025-12-01 15:41:19 -0500 |
|---|---|---|
| committer | Ben Sima <ben@bensima.com> | 2025-12-01 15:41:19 -0500 |
| commit | 2151b67836d209645b85bb64d56a96bfbf2859cd (patch) | |
| tree | 25f8b87331a689486405de977c8624cb71df9c16 /Omni | |
| parent | 5b3256b500ebb9a2f953c8b54917626b11988448 (diff) | |
Add autoscroll toggle button for timeline
Adds a toggle button next to the LIVE indicator that controls whether
the timeline auto-scrolls to new events. Default is ON.
- renderAutoscrollToggle button with ⬇ icon
- toggleAutoscroll() JS function tracks state
- htmx:afterSettle checks autoscrollEnabled before scrolling
- Blue styling to differentiate from green LIVE button
Task-Id: t-222
Diffstat (limited to 'Omni')
| -rw-r--r-- | Omni/Jr/Web.hs | 35 | ||||
| -rw-r--r-- | Omni/Jr/Web/Style.hs | 17 |
2 files changed, 50 insertions, 2 deletions
diff --git a/Omni/Jr/Web.hs b/Omni/Jr/Web.hs index a493395..6a2d826 100644 --- a/Omni/Jr/Web.hs +++ b/Omni/Jr/Web.hs @@ -2273,11 +2273,23 @@ renderLiveToggle = ] " LIVE" --- | JavaScript for toggling live updates +-- | Render the autoscroll toggle button +renderAutoscrollToggle :: (Monad m) => Lucid.HtmlT m () +renderAutoscrollToggle = + Lucid.button_ + [ Lucid.class_ "timeline-autoscroll-toggle", + Lucid.id_ "autoscroll-toggle", + Lucid.makeAttribute "onclick" "toggleAutoscroll()", + Lucid.title_ "Toggle automatic scrolling to newest events" + ] + " ⬇ Auto-scroll" + +-- | JavaScript for toggling live updates and autoscroll liveToggleJs :: Text liveToggleJs = Text.unlines [ "var liveUpdatesEnabled = true;", + "var autoscrollEnabled = true;", "", "function toggleLiveUpdates() {", " liveUpdatesEnabled = !liveUpdatesEnabled;", @@ -2287,11 +2299,28 @@ liveToggleJs = " }", "}", "", + "function toggleAutoscroll() {", + " autoscrollEnabled = !autoscrollEnabled;", + " var btn = document.getElementById('autoscroll-toggle');", + " if (btn) {", + " btn.classList.toggle('timeline-autoscroll-disabled', !autoscrollEnabled);", + " }", + "}", + "", "document.body.addEventListener('htmx:beforeRequest', function(evt) {", " var timeline = document.getElementById('unified-timeline');", " if (timeline && timeline.contains(evt.target) && !liveUpdatesEnabled) {", " evt.preventDefault();", " }", + "});", + "", + "document.body.addEventListener('htmx:afterSettle', function(evt) {", + " if (autoscrollEnabled) {", + " var log = document.querySelector('.timeline-events');", + " if (log) {", + " log.scrollTop = log.scrollHeight;", + " }", + " }", "});" ] @@ -2352,7 +2381,9 @@ renderUnifiedTimeline tid legacyComments events status now = do when (totalCents > 0) <| Lucid.toHtml (formatCostHeader totalCents) when (totalCents > 0 && totalTokens > 0) <| metaSep when (totalTokens > 0) <| Lucid.toHtml (formatTokensHeader totalTokens <> " tokens") - when isInProgress <| renderLiveToggle + when isInProgress <| do + renderLiveToggle + renderAutoscrollToggle if null nonCostEvents && null legacyComments then Lucid.p_ [Lucid.class_ "empty-msg"] "No activity yet." diff --git a/Omni/Jr/Web/Style.hs b/Omni/Jr/Web/Style.hs index cf32570..bbf828b 100644 --- a/Omni/Jr/Web/Style.hs +++ b/Omni/Jr/Web/Style.hs @@ -1597,6 +1597,23 @@ unifiedTimelineStyles = do backgroundColor "#f3f4f6" border (px 1) solid "#d1d5db" Stylesheet.key "animation" ("none" :: Text) + ".timeline-autoscroll-toggle" ? do + fontSize (px 10) + fontWeight bold + color "#3b82f6" + backgroundColor "#dbeafe" + padding (px 2) (px 6) (px 2) (px 6) + borderRadius (px 10) (px 10) (px 10) (px 10) + marginLeft (px 4) + border (px 1) solid "#93c5fd" + cursor pointer + Stylesheet.key "transition" ("all 0.2s ease" :: Text) + ".timeline-autoscroll-toggle:hover" ? do + Stylesheet.key "box-shadow" ("0 0 6px rgba(59,130,246,0.3)" :: Text) + ".timeline-autoscroll-toggle.timeline-autoscroll-disabled" ? do + color "#6b7280" + backgroundColor "#f3f4f6" + border (px 1) solid "#d1d5db" ".timeline-live" ? do fontSize (px 10) fontWeight bold |
