diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx index 9622f08..a351b38 100644 --- a/src/components/SideBar.tsx +++ b/src/components/SideBar.tsx @@ -126,6 +126,7 @@ export function SideBar() { })} baseSize={baseSize} onLeave={sidebarToggleMode === 'float' ? () => setShowSideBar(false) : undefined} + sizeVariableMountPoint={sidebarToggleMode === 'persistent' ? document.body : undefined} >
['onMouseLeave'] + sizeVariableMountPoint?: HTMLElement } const MINIMAL_CONTENT_VIEWPORT_WIDTH = 100 const MINIMAL_WIDTH = 240 +function getSafeSize(size: number, width: number) { + if (size > width - MINIMAL_CONTENT_VIEWPORT_WIDTH) return width - MINIMAL_CONTENT_VIEWPORT_WIDTH + if (size < MINIMAL_WIDTH) return MINIMAL_WIDTH + return size +} + export function SideBarBodyWrapper({ baseSize, className, children, onLeave, + sizeVariableMountPoint, }: React.PropsWithChildren) { const [size, setSize] = React.useState(baseSize) const configContext = useConfigs() @@ -34,27 +41,50 @@ export function SideBarBodyWrapper({ const { width } = useWindowSize() React.useEffect(() => { - if (size > width - MINIMAL_CONTENT_VIEWPORT_WIDTH) - setSize(width - MINIMAL_CONTENT_VIEWPORT_WIDTH) - else if (size < MINIMAL_WIDTH) setSize(MINIMAL_WIDTH) + const safeSize = getSafeSize(size, width) + if (safeSize !== size) setSize(safeSize) }, [width, size]) - - React.useEffect(() => { - setResizingState(true) - const timer = setTimeout(() => setResizingState(false), 100) - return () => clearTimeout(timer) - }, [width, size]) - - useCSSVariable('--gitako-width', `${size}px`) + const bodyWrapperRef = React.useRef(null) useDebounce(() => configContext.onChange({ sideBarWidth: size }), 100, [size]) - const onResize = React.useCallback((size: number) => { - // do NOT merge this with the above similar effect, side bar will jump otherwise - if (size > width - MINIMAL_CONTENT_VIEWPORT_WIDTH) - setSize(width - MINIMAL_CONTENT_VIEWPORT_WIDTH) - else if (size < MINIMAL_WIDTH) setSize(MINIMAL_WIDTH) - else setSize(size) - }, []) + function apply(sizeVariableMountPoint: HTMLElement | undefined, size: number) { + if (sizeVariableMountPoint) + setCSSVariable( + '--gitako-width', + sizeVariableMountPoint ? `${size}px` : undefined, + sizeVariableMountPoint, + ) + + if (bodyWrapperRef.current) + setCSSVariable( + '--gitako-width', + sizeVariableMountPoint ? undefined : `${size}px`, + bodyWrapperRef.current, + ) + } + + // Update size using useEffect would cause delay + const onResize = React.useMemo(() => { + let sizeToApply: number, + applied = true + return (size: number) => { + // do NOT merge this with the above similar effect, side bar will jump otherwise + sizeToApply = getSafeSize(size, width) + setSize(sizeToApply) + + if (applied) { + applied = false + requestAnimationFrame(() => { + applied = true + apply(sizeVariableMountPoint, sizeToApply) + }) + } + } + }, [width, sizeVariableMountPoint]) + + React.useEffect(() => { + apply(sizeVariableMountPoint, size) + }, [sizeVariableMountPoint]) const onMouseLeave = React.useCallback( e => { @@ -65,7 +95,11 @@ export function SideBarBodyWrapper({ ) return ( -
+
{children}
{features.resize && (