From 9350c467745c3cef2c7313b432caae1b9713618a Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Jan 2026 08:56:44 +0000 Subject: [PATCH] refactor: use react-resizable-panels for GroupListViewer Changes: - Replace custom resizable divider with react-resizable-panels - Uses ResizablePanelGroup, ResizablePanel, and ResizableHandle - Better UX with built-in resizing behavior - Remove all icons from group list items - Hide images and event embeds in last message preview - Pass showImages: false and showEventEmbeds: false to RichText - Cleaner message previews focusing on text content - Remove group list header for cleaner appearance Dependencies: - Add react-resizable-panels package --- package-lock.json | 11 +++ package.json | 1 + src/components/GroupListViewer.tsx | 115 +++++++---------------------- 3 files changed, 39 insertions(+), 88 deletions(-) diff --git a/package-lock.json b/package-lock.json index d33975f..c8e325d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,6 +61,7 @@ "react-markdown": "^10.1.0", "react-medium-image-zoom": "^5.4.0", "react-mosaic-component": "^6.1.1", + "react-resizable-panels": "^4.4.0", "react-router": "^7.1.0", "react-virtuoso": "^4.17.0", "remark-gfm": "^4.0.1", @@ -10346,6 +10347,16 @@ } } }, + "node_modules/react-resizable-panels": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-4.4.0.tgz", + "integrity": "sha512-vGH1rIhyDOL4RSWYTx3eatjDohDFIRxJCAXUOaeL9HyamptUnUezqndjMtBo9hQeaq1CIP0NBbc7ZV3lBtlgxA==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, "node_modules/react-router": { "version": "7.9.6", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.6.tgz", diff --git a/package.json b/package.json index 79ed59a..fafc01e 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "react-markdown": "^10.1.0", "react-medium-image-zoom": "^5.4.0", "react-mosaic-component": "^6.1.1", + "react-resizable-panels": "^4.4.0", "react-router": "^7.1.0", "react-virtuoso": "^4.17.0", "remark-gfm": "^4.0.1", diff --git a/src/components/GroupListViewer.tsx b/src/components/GroupListViewer.tsx index 1f79621..cba0468 100644 --- a/src/components/GroupListViewer.tsx +++ b/src/components/GroupListViewer.tsx @@ -1,7 +1,12 @@ -import { useState, useMemo, useCallback, memo } from "react"; +import { useState, useMemo, memo } from "react"; import { use$ } from "applesauce-react/hooks"; import { map } from "rxjs/operators"; -import { Loader2, MessageSquare, GripVertical } from "lucide-react"; +import { Loader2 } from "lucide-react"; +import { + ResizableHandle, + ResizablePanel, + ResizablePanelGroup, +} from "react-resizable-panels"; import eventStore from "@/services/event-store"; import pool from "@/services/relay-pool"; import accountManager from "@/services/accounts"; @@ -65,26 +70,30 @@ const GroupListItem = memo(function GroupListItem({ onClick={onClick} >
-
- - {groupName} -
+ {groupName} {group.lastMessage && ( )}
- {/* Last message preview */} + {/* Last message preview - hide images and event embeds */} {lastMessageAuthor && lastMessageContent && ( -
+
:{" "} - +
)} @@ -92,55 +101,6 @@ const GroupListItem = memo(function GroupListItem({ ); }); -/** - * ResizableDivider - Draggable divider for resizing panels - */ -function ResizableDivider({ - onResize, -}: { - onResize: (deltaX: number) => void; -}) { - const [isDragging, setIsDragging] = useState(false); - - const handleMouseDown = useCallback( - (e: React.MouseEvent) => { - e.preventDefault(); - setIsDragging(true); - - const startX = e.clientX; - - const handleMouseMove = (moveEvent: MouseEvent) => { - const deltaX = moveEvent.clientX - startX; - onResize(deltaX); - }; - - const handleMouseUp = () => { - setIsDragging(false); - document.removeEventListener("mousemove", handleMouseMove); - document.removeEventListener("mouseup", handleMouseUp); - }; - - document.addEventListener("mousemove", handleMouseMove); - document.addEventListener("mouseup", handleMouseUp); - }, - [onResize], - ); - - return ( -
-
- -
-
- ); -} - /** * MemoizedChatViewer - Memoized chat viewer to prevent unnecessary re-renders */ @@ -186,18 +146,6 @@ export function GroupListViewer() { relayUrl: string; } | null>(null); - // State for sidebar width - const [sidebarWidth, setSidebarWidth] = useState(280); - - // Handle resize - const handleResize = useCallback((deltaX: number) => { - setSidebarWidth((prev) => { - const newWidth = prev + deltaX; - // Clamp between 200px and 500px - return Math.max(200, Math.min(500, newWidth)); - }); - }, []); - // Load user's kind 10009 (group list) event const groupListEvent = use$( () => @@ -411,19 +359,10 @@ export function GroupListViewer() { } return ( -
+ {/* Left panel: Group list */} -
- {/* Header matching ChatViewer style */} -
-
-
Groups
-
- {groupsWithRecency.length} -
-
-
-
+ +
{groupsWithRecency.map((group) => ( ))}
-
+ - {/* Resizable divider */} - + {/* Resizable handle */} + {/* Right panel: Chat view */} -
+ {selectedGroup ? ( )} -
-
+ +
); }