import React from 'react'; import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay'; import { isVSCodeRuntime } from '@/lib/desktop'; import { cn } from '@/lib/utils'; interface SettingsSidebarLayoutProps { /** Header content (typically SettingsSidebarHeader) */ header?: React.ReactNode; /** Footer content (e.g., AboutSettings on mobile) */ footer?: React.ReactNode; /** Main scrollable content */ children: React.ReactNode; /** Additional className for the outer container */ className?: string; /** Background style for the sidebar container */ variant?: 'sidebar' | 'background'; } /** * Standard layout wrapper for settings sidebars. * Provides consistent background, scrolling, and header/footer slots. * * @example * } * > * {items.map(item => ( * * ))} * */ export const SettingsSidebarLayout: React.FC = ({ header, footer, children, className, variant = 'sidebar', }) => { const isVSCode = React.useMemo(() => isVSCodeRuntime(), []); const scrollRef = React.useRef(null); const [showTopShadow, setShowTopShadow] = React.useState(false); const [showBottomShadow, setShowBottomShadow] = React.useState(false); const bgClass = variant === 'background' ? 'bg-background' : (isVSCode ? 'bg-background' : 'bg-sidebar'); const bgVar = bgClass === 'bg-background' ? 'var(--surface-background)' : 'var(--surface-muted)'; const updateScrollShadows = React.useCallback(() => { const el = scrollRef.current; if (!el) { setShowTopShadow(false); setShowBottomShadow(false); return; } const canScroll = el.scrollHeight > el.clientHeight + 1; if (!canScroll) { setShowTopShadow(false); setShowBottomShadow(false); return; } setShowTopShadow(el.scrollTop > 1); setShowBottomShadow(el.scrollTop + el.clientHeight < el.scrollHeight - 1); }, []); React.useEffect(() => { updateScrollShadows(); }, [children, updateScrollShadows]); React.useEffect(() => { const el = scrollRef.current; if (!el) return; const onScroll = () => updateScrollShadows(); el.addEventListener('scroll', onScroll, { passive: true }); return () => el.removeEventListener('scroll', onScroll); }, [updateScrollShadows]); return (
{header}
} outerClassName="flex-1 min-h-0" className="space-y-0.5 px-3 py-2 overflow-x-hidden" > {children} {showTopShadow && (
)} {showBottomShadow && (
)}
{footer}
); };