optimize sidebar resizing for performance

This commit is contained in:
jeffvli
2025-11-14 18:36:46 -08:00
parent 1ab9012446
commit f48c26915f
3 changed files with 64 additions and 35 deletions
@@ -9,7 +9,7 @@ import { useSidebarStore } from '/@/renderer/store';
interface LeftSidebarProps { interface LeftSidebarProps {
isResizing: boolean; isResizing: boolean;
startResizing: (direction: 'left' | 'right') => void; startResizing: (direction: 'left' | 'right', mouseEvent?: MouseEvent) => void;
} }
export const LeftSidebar = ({ isResizing, startResizing }: LeftSidebarProps) => { export const LeftSidebar = ({ isResizing, startResizing }: LeftSidebarProps) => {
@@ -1,16 +1,7 @@
import clsx from 'clsx'; import clsx from 'clsx';
import throttle from 'lodash/throttle'; import throttle from 'lodash/throttle';
import { motion } from 'motion/react'; import { motion } from 'motion/react';
import { import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from 'react';
CSSProperties,
lazy,
Suspense,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import { Outlet, useLocation } from 'react-router'; import { Outlet, useLocation } from 'react-router';
import styles from './main-content.module.css'; import styles from './main-content.module.css';
@@ -42,19 +33,62 @@ export const MainContent = ({ shell }: { shell?: boolean }) => {
const showSideQueue = rightExpanded && location.pathname !== AppRoute.NOW_PLAYING; const showSideQueue = rightExpanded && location.pathname !== AppRoute.NOW_PLAYING;
const rightSidebarRef = useRef<HTMLDivElement | null>(null); const rightSidebarRef = useRef<HTMLDivElement | null>(null);
const mainContentRef = useRef<HTMLDivElement | null>(null);
const initialRightWidthRef = useRef<string>(rightWidth);
const initialMouseXRef = useRef<number>(0);
const startResizing = useCallback((position: 'left' | 'right') => { useEffect(() => {
if (position === 'left') return setIsResizing(true); if (mainContentRef.current && !isResizing && !isResizingRight) {
return setIsResizingRight(true); mainContentRef.current.style.setProperty('--sidebar-width', leftWidth);
}, []); mainContentRef.current.style.setProperty('--right-sidebar-width', rightWidth);
initialRightWidthRef.current = rightWidth;
}
}, [leftWidth, rightWidth, isResizing, isResizingRight]);
const startResizing = useCallback(
(position: 'left' | 'right', mouseEvent?: MouseEvent) => {
if (position === 'left') {
setIsResizing(true);
} else {
setIsResizingRight(true);
if (mainContentRef.current && rightSidebarRef.current && mouseEvent) {
const currentWidth =
mainContentRef.current.style.getPropertyValue('--right-sidebar-width');
if (currentWidth) {
initialRightWidthRef.current = currentWidth;
} else {
initialRightWidthRef.current = rightWidth;
}
initialMouseXRef.current = mouseEvent.clientX;
} else {
initialRightWidthRef.current = rightWidth;
}
}
},
[rightWidth],
);
const stopResizing = useCallback(() => { const stopResizing = useCallback(() => {
setIsResizing(false); if (isResizing && mainContentRef.current) {
setIsResizingRight(false); const finalWidth = mainContentRef.current.style.getPropertyValue('--sidebar-width');
}, []); if (finalWidth) {
setSideBar({ collapsed: false, leftWidth: finalWidth });
}
setIsResizing(false);
} else if (isResizingRight && mainContentRef.current) {
const finalWidth =
mainContentRef.current.style.getPropertyValue('--right-sidebar-width');
if (finalWidth) {
setSideBar({ rightWidth: finalWidth });
}
setIsResizingRight(false);
}
}, [isResizing, isResizingRight, setSideBar]);
const resize = useCallback( const resize = useCallback(
(mouseMoveEvent: any) => { (mouseMoveEvent: any) => {
if (!mainContentRef.current) return;
if (isResizing) { if (isResizing) {
const width = mouseMoveEvent.clientX; const width = mouseMoveEvent.clientX;
const constrainedWidth = `${constrainSidebarWidth(width)}px`; const constrainedWidth = `${constrainSidebarWidth(width)}px`;
@@ -62,21 +96,21 @@ export const MainContent = ({ shell }: { shell?: boolean }) => {
if (width < MINIMUM_SIDEBAR_WIDTH - 100) { if (width < MINIMUM_SIDEBAR_WIDTH - 100) {
setSideBar({ collapsed: true }); setSideBar({ collapsed: true });
} else { } else {
setSideBar({ collapsed: false, leftWidth: constrainedWidth }); mainContentRef.current.style.setProperty('--sidebar-width', constrainedWidth);
} }
} else if (isResizingRight) { } else if (isResizingRight) {
const start = Number(rightWidth.split('px')[0]); const initialWidth = Number(initialRightWidthRef.current.split('px')[0]);
const { left } = rightSidebarRef!.current!.getBoundingClientRect(); const initialMouseX = initialMouseXRef.current;
const width = `${constrainRightSidebarWidth( const deltaX = mouseMoveEvent.clientX - initialMouseX;
start + left - mouseMoveEvent.clientX, const newWidth = initialWidth - deltaX;
)}px`; const width = `${constrainRightSidebarWidth(newWidth)}px`;
setSideBar({ rightWidth: width }); mainContentRef.current.style.setProperty('--right-sidebar-width', width);
} }
}, },
[isResizing, isResizingRight, setSideBar, rightWidth], [isResizing, isResizingRight, setSideBar],
); );
const throttledResize = useMemo(() => throttle(resize, 50), [resize]); const throttledResize = useMemo(() => throttle(resize, 10), [resize]);
useEffect(() => { useEffect(() => {
window.addEventListener('mousemove', throttledResize); window.addEventListener('mousemove', throttledResize);
@@ -96,12 +130,7 @@ export const MainContent = ({ shell }: { shell?: boolean }) => {
[styles.sidebarExpanded]: !collapsed, [styles.sidebarExpanded]: !collapsed,
})} })}
id="main-content" id="main-content"
style={ ref={mainContentRef}
{
'--right-sidebar-width': rightWidth,
'--sidebar-width': leftWidth,
} as CSSProperties
}
> >
{!shell && ( {!shell && (
<> <>
@@ -69,7 +69,7 @@ const queueDrawerVariants: Variants = {
interface RightSidebarProps { interface RightSidebarProps {
isResizing: boolean; isResizing: boolean;
startResizing: (direction: 'left' | 'right') => void; startResizing: (direction: 'left' | 'right', mouseEvent?: MouseEvent) => void;
} }
export const RightSidebar = forwardRef( export const RightSidebar = forwardRef(
@@ -102,7 +102,7 @@ export const RightSidebar = forwardRef(
isResizing={isResizingRight} isResizing={isResizingRight}
onMouseDown={(e) => { onMouseDown={(e) => {
e.preventDefault(); e.preventDefault();
startResizing('right'); startResizing('right', e.nativeEvent);
}} }}
placement="left" placement="left"
ref={ref} ref={ref}