Skip to content

feat(ask): resizable, persisted thread sidebar (Part A of #8)#14

Open
mvanhorn wants to merge 1 commit into
jstuart0:mainfrom
mvanhorn:feat/ask-sidebar-resize
Open

feat(ask): resizable, persisted thread sidebar (Part A of #8)#14
mvanhorn wants to merge 1 commit into
jstuart0:mainfrom
mvanhorn:feat/ask-sidebar-resize

Conversation

@mvanhorn
Copy link
Copy Markdown
Contributor

Summary

Implements Part A of #8: a resizable, persisted thread sidebar
on /ask. The fixed w-60 (240px) is now a drag-resizable column
between 180px and 480px, persisted in useUiPrefsStore so the
chosen width survives reloads.

Changes

src/web/stores/ui-prefs-store.ts (~30 lines)

  • New askSidebarWidth: number field (default 240).
  • Exported ASK_SIDEBAR_MIN_WIDTH=180, ASK_SIDEBAR_MAX_WIDTH=480,
    ASK_SIDEBAR_DEFAULT_WIDTH=240 so the page can render aria-valuemin
    / max without re-deriving them.
  • New setAskSidebarWidth(width) setter clamps to the bounds and
    persists; load() re-clamps on read so a stale localStorage value
    can 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)

  • Sidebar <aside> drops w-60 and uses inline style={{ width }}
    driven by the store value; flex-shrink-0 is preserved.
  • New 1px-wide drag handle (with 4px hover hitbox) at the sidebar's
    right edge, rendered only at md+ breakpoints (matching the sidebar
    itself).
  • During drag the mouse listeners attach to document so a fast
    movement that leaves the handle's hitbox keeps tracking; global
    cursor: col-resize and userSelect: none are applied for the
    drag duration 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 role="separator" with
    aria-valuemin / valuemax / valuenow reflect the live width.

Acceptance criteria from #8

  • Sidebar resizes smoothly, width persists across reloads.
    Width is read from localStorage on store init, clamped on
    both 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

bun install
bun run typecheck   # clean

Manual checks I ran in bun run dev:

  • Drag the handle: sidebar grows / shrinks smoothly to the cursor
    position. Stops at 180px (handle disappears under the "New
    conversation" button if you keep dragging left) and 480px.
  • Reload the page: width is restored.
  • Tab to the handle, press Right several times: width grows in 16px
    steps; ARIA aria-valuenow updates accordingly.
  • Tab to the handle, press End: width snaps to 480; Home: 180.
  • Resize while text is selected in the conversation column: drag
    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.

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant