From 2e0af4e6bfc97a418aba8cf10d3f27568bacb93b Mon Sep 17 00:00:00 2001 From: Jure <44338+hoornet@users.noreply.github.com> Date: Mon, 15 Jun 2026 21:30:13 +0200 Subject: [PATCH] feat: make the left sidebar width resizable (#6) Adds a drag handle on the right edge of the expanded sidebar; width is clamped to 160-360px, double-click resets to the default, and the chosen width persists to localStorage. Collapsed state is unchanged. Closes #6 --- src/components/sidebar/Sidebar.tsx | 59 ++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/src/components/sidebar/Sidebar.tsx b/src/components/sidebar/Sidebar.tsx index 0b7b436..2d00da5 100644 --- a/src/components/sidebar/Sidebar.tsx +++ b/src/components/sidebar/Sidebar.tsx @@ -1,4 +1,4 @@ -import type { ReactNode } from "react"; +import { useState, useRef, useEffect, type ReactNode } from "react"; import { Rss, BookOpen, Image as ImageIcon, Mic2, Search, Bookmark, Mail, Bell, Users, Zap, Radio, Wifi, Settings, Heart, PenLine, @@ -47,11 +47,48 @@ export function Sidebar() { const c = sidebarCollapsed; + // Resizable width when expanded (issue #6), persisted to localStorage. + const SIDEBAR_WIDTH_KEY = "wrystr_sidebar_width"; + const MIN_WIDTH = 160; + const MAX_WIDTH = 360; + const DEFAULT_WIDTH = 192; // matches the old w-48 + const asideRef = useRef(null); + const [width, setWidth] = useState(() => { + const saved = parseInt(localStorage.getItem(SIDEBAR_WIDTH_KEY) ?? "", 10); + return Number.isFinite(saved) && saved >= MIN_WIDTH && saved <= MAX_WIDTH ? saved : DEFAULT_WIDTH; + }); + const [dragging, setDragging] = useState(false); + + useEffect(() => { + if (!dragging) return; + const onMove = (e: MouseEvent) => { + const left = asideRef.current?.getBoundingClientRect().left ?? 0; + setWidth(Math.min(MAX_WIDTH, Math.max(MIN_WIDTH, e.clientX - left))); + }; + const onUp = () => setDragging(false); + document.body.style.userSelect = "none"; + document.body.style.cursor = "col-resize"; + window.addEventListener("mousemove", onMove); + window.addEventListener("mouseup", onUp); + return () => { + document.body.style.userSelect = ""; + document.body.style.cursor = ""; + window.removeEventListener("mousemove", onMove); + window.removeEventListener("mouseup", onUp); + }; + }, [dragging]); + + useEffect(() => { + localStorage.setItem(SIDEBAR_WIDTH_KEY, String(width)); + }, [width]); + return ( ); }