feat(ask): resizable, persisted thread sidebar (Part A of #8)#14
Open
mvanhorn wants to merge 1 commit into
Open
feat(ask): resizable, persisted thread sidebar (Part A of #8)#14mvanhorn wants to merge 1 commit into
mvanhorn wants to merge 1 commit into
Conversation
Implements Part A of jstuart0#8. The /ask thread sidebar was a fixed 'w-60' (240px), which is cramped for long thread titles and wasted space when titles are short. This adds a drag handle on its right edge and persists the chosen width. Storage: - New 'askSidebarWidth' field on useUiPrefsStore (default 240px, clamped to [180, 480]). - The clamp also applies on load — a stale localStorage value can't push the sidebar off-screen or below the 'New conversation' button's minimum legible width. UX: - Thin drag handle (1px wide, 4px hover hitbox) renders only at md+, matching the sidebar's own breakpoint. - During the drag, mouse listeners attach to document so a fast movement that leaves the handle's hitbox keeps tracking; the global cursor switches to col-resize and userSelect is suspended so the browser doesn't paint text selection across the layout. - Keyboard accessibility: Left/Right arrow keys step by 16px, Home/End jump to the clamp endpoints; ARIA separator semantics with aria-valuemin/max/now reflect the same range. Part B of the issue (shiki-based syntax highlighting in MarkdownContent.tsx) is left for a follow-up PR — it's a new dependency + async-loading concern that's substantial enough to review separately. This PR keeps Part A independently shippable so the sidebar improvement can land without waiting on the highlighter work.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements Part A of #8: a resizable, persisted thread sidebar
on
/ask. The fixedw-60(240px) is now a drag-resizable columnbetween 180px and 480px, persisted in
useUiPrefsStoreso thechosen width survives reloads.
Changes
src/web/stores/ui-prefs-store.ts(~30 lines)askSidebarWidth: numberfield (default 240).ASK_SIDEBAR_MIN_WIDTH=180,ASK_SIDEBAR_MAX_WIDTH=480,ASK_SIDEBAR_DEFAULT_WIDTH=240so the page can render aria-valuemin/ max without re-deriving them.
setAskSidebarWidth(width)setter clamps to the bounds andpersists;
load()re-clamps on read so a stale localStorage valuecan never push the sidebar off-screen or shrink it below the
"New conversation" button's minimum legible width.
src/web/pages/AskPage.tsx(~80 lines)<aside>dropsw-60and uses inlinestyle={{ width }}driven by the store value;
flex-shrink-0is preserved.right edge, rendered only at md+ breakpoints (matching the sidebar
itself).
documentso a fastmovement that leaves the handle's hitbox keeps tracking; global
cursor: col-resizeanduserSelect: noneare applied for thedrag duration so the browser doesn't paint text selection across
the layout.
End jump to the clamp endpoints. ARIA
role="separator"witharia-valuemin/valuemax/valuenowreflect the live width.Acceptance criteria from #8
Width is read from
localStorageon store init, clamped onboth read and set, and rewritten on every drag end.
Part B (shiki-based syntax highlighting in
MarkdownContent.tsx)is left for a follow-up PR — it adds a new dependency and the
"no runtime flash via async load" requirement is substantial enough
to review separately. Keeping Part A independently shippable means
the sidebar improvement can land without waiting on the highlighter
work.
Verification
Manual checks I ran in
bun run dev:position. Stops at 180px (handle disappears under the "New
conversation" button if you keep dragging left) and 480px.
steps; ARIA
aria-valuenowupdates accordingly.starts cleanly without losing the selection mid-drag (userSelect
toggle).
The pre-existing biome warnings on lines 137-141 / 245-265 of
AskPage.tsx are not touched by this PR — keeping the diff scoped to
the sidebar change.