HarperFast / HarperFast/studio
Extract a shared resizable-sidebar hook (apis / databases / applications)
- Dominant language
- TypeScript
- Stars
- 5
- Forks
- 4
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 40
Description
## Summary
Three features now implement near-identical drag-to-resize sidebar logic in separate hooks. Consolidate them into one shared primitive so a fix or optimization made once applies everywhere.
## The duplication
- `src/features/instance/applications/components/ApplicationsSidebar/SidebarResizeHandle.tsx` — `useResizableSidebar` (cursor-X based; tray anchored at the viewport left edge)
- `src/features/instance/databases/hooks/useResizableDatabasesSidebar.ts` — `useResizableDatabasesSidebar` (delta based; sidebar in-flow)
- `src/features/instance/apis/explorer/useResizableSidebar.ts` — `useResizableSidebar` (delta based; in-flow; added in #1639)
All three share the same mousedown-arms / window-`mousemove`-tracks / persist-once-on-release lifecycle, the `clampWidth`/`maxSidebarWidth` helpers, viewport re-clamping, and Arrow-key stepping. They differ only in: (a) cursor-X vs delta positioning, (b) the `localStorage` key, (c) `DEFAULT`/`MIN` width constants.
## Why
Three cross-model reviewers (codex, gemini, cursor-grok) independently flagged the duplication on #1639 as a divergence risk: a fix applied to one path won't propagate to the others. Latent improvements worth folding in during the extraction:
- Migrate `mousemove`/`mouseup` → `pointermove`/`pointerup`/`pointercancel` and add a window `blur` handler, so releasing the pointer outside the window can't leave `isResizing` (and `document.body.style.userSelect = 'none'`) stuck.
- Avoid a full React re-render on every `mousemove`: update a container ref / CSS variable during the drag and commit state on release.
## Scope
Design one hook (likely parameterized by `{ storageKey, defaultWidth, minWidth, mode: 'cursorX' | 'delta' }`) that all three consume. Preserve each feature's existing `localStorage` key and default/min widths so persisted user preferences survive. Keep the existing unit tests (clamp math, drag delta/persist, viewport reclamp, keyboard, NaN-guard) and add coverage for the pointercancel/blur termination path. Verify all three sidebars still drag, clamp, and persist in-browser.
## Not doing this in #1639
#1639 deliberately followed the repo's established per-feature convention (applications and databases each keep their own copy) rather than diverge; extracting the shared primitive touches two already-shipped features and is its own change.
Contributor guide
Research direction
Start by reading the three existing hooks in ApplicationsSidebar/SidebarResizeHandle.tsx, databases/hooks/useResizableDatabasesSidebar.ts, and apis/explorer/useResizableSidebar.ts, along with their existing unit tests. Confirm the shared lifecycle and feature-specific constants, storage keys, and positioning modes. Done means all three sidebars use the shared primitive, existing tests pass with pointercancel/blur coverage, and browser drag, clamping, and persistence work.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100