refactor(story): use shared scrollbar module in story overlay#227
refactor(story): use shared scrollbar module in story overlay#227forketyfork merged 2 commits intomainfrom
Conversation
Issue: story_overlay.zig had its own renderScrollbar() on FullscreenOverlay — plain SDL FillRect calls, no animations, no rounded thumb, no interaction. Every other overlay used scrollbar.zig. Solution: Deleted renderScrollbar() from FullscreenOverlay and wired story_overlay.zig to scrollbar.computeLayout() + scrollbar.render() with a scrollbar.State field. Added mouse wheel activity signals, drag and track-click on button-down, drag updates and hover detection on motion, and drag-end on button-up. computeWrapCols now uses scrollbar.reservedWidth() instead of a hardcoded pixel value.
There was a problem hiding this comment.
Pull request overview
Refactors the story overlay to use the shared scrollbar.zig component (matching reader/diff/terminal overlays) and removes the bespoke SDL FillRect scrollbar implementation.
Changes:
- Add
scrollbar.StatetoStoryOverlayComponentand render the shared scrollbar viascrollbar.computeLayout()+scrollbar.render(). - Wire mouse interactions for wheel activity, thumb dragging, track-click jumps, and hover-driven fade behavior.
- Update wrap column computation to reserve width using
scrollbar.reservedWidth()instead of a hardcoded estimate.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/ui/components/story_overlay.zig |
Integrates shared scrollbar state/rendering and hooks up mouse events + wrap-width reservation. |
src/ui/components/fullscreen_overlay.zig |
Removes the old renderScrollbar() implementation now superseded by scrollbar.zig. |
Comments suppressed due to low confidence (1)
src/ui/components/story_overlay.zig:472
- The cursor state transition logic compares
want_pointeragainstwas_pointerderived only from the previous anchor/link hover state. Sincewant_pointernow includes scrollbar hover/drag, moving off the scrollbar can leave the cursor stuck as a pointer (becausewas_pointerdoesn't include prior scrollbar hit/drag state). Track previous scrollbar-hit/hover/drag state as part ofwas_pointer, or set the cursor unconditionally based onwant_pointereach motion event.
const want_pointer = self.hovered_anchor != null or self.hovered_link != null or self.scrollbar_state.dragging or scroll_hit != .none;
const was_pointer = prev_hovered_anchor != null or prev_link != null;
if (want_pointer != was_pointer) {
const cursor = if (want_pointer) self.pointer_cursor else self.arrow_cursor;
if (cursor) |cur| _ = c.SDL_SetCursor(cur);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3d8fdcd535
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Issue: Four gaps found in PR #227 review: keyboard scroll didn't trigger the scrollbar fade-in, mouse-up could leak through the overlay when not dragging, the overlay didn't reset scrollbar state on hide, and the pointer cursor could get stuck when leaving the scrollbar. Solution: noteActivity is now called after handleScrollKey returns true. Mouse-up always consumes the event while the overlay is visible and gates endDrag on the left button. hide() calls scrollbar_state.hideNow(). was_pointer now captures the previous scrollbar hover/drag state so the cursor resets correctly when moving off the scrollbar into plain content.
The story overlay was the last holdout with its own scrollbar drawing code.
FullscreenOverlay.renderScrollbar()did the job with plain SDLFillRectcalls — flat rectangles, fixed alpha, no fade, no rounding, no hover state. Every other overlay (reader, diff, terminal) already usedscrollbar.zig, which gives you a rounded gradient thumb, fade-in/out animations, and full mouse interaction.This removes
renderScrollbar()and brings the story overlay in line with the rest.story_overlay.zignow holds ascrollbar.Statefield and callsscrollbar.computeLayout()+scrollbar.render(). Mouse events are wired: wheel triggers activity, left-click on the thumb starts a drag, left-click on the track jumps the position, motion handles drag updates and hover, and button-up ends the drag.computeWrapColsnow usesscrollbar.reservedWidth()instead of a hardcoded 10px estimate.Closes #226
Test plan
architect story <some-long-story.md>)Cmd+R) — rounded thumb, same visual style