- usePullToRefresh: hand-rolled hook. Records startY only when the
scroll container is at scrollTop=0 to avoid hijacking mid-scroll
pulls. Tracks downward delta on touchmove; fires onRefresh on
touchend if delta >= 80px threshold. Holds the refreshing state for
600ms minimum so the action feels intentional.
- ProjectSidebar: wires usePullToRefresh(() => retry()) on the nav
element, mobile-only. A status indicator above the nav grows with
pullDist (max 80px) and cycles 'Pull to refresh' -> 'Release to
refresh' -> 'Refreshing...'. retry() is from useSidebar and refetches
GET /api/sidebar.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>