'use client'; /** * Lab Layout Component * * Main layout wrapper for the Lab section combining sidebar and content. * Uses ThreeColumnLayout for consistent column structure across the app. * * Structure: * - Left: LabSidebar (w-64, hidden lg:block, scrollable) * - Center: Scrollable content area + fixed LabFooter at bottom * - Right: Reserved for future use (TOC, preview panels, etc.) * * The center column uses a fixed height container with: * - Scrollable content area (flex-1 overflow-y-auto) * - Sticky footer always visible at bottom * * This layout is rendered inside PageProvider context which provides: * - SubsectionNav at the top * - ApiKeyWidget in the right slot * - AnimatedBackground * * Scroll Detection: * - Detects scroll in the main content area * - After 50px threshold, collapses the main header via LabScrollContext * - Height adjusts dynamically: 100vh-7rem (header visible) → 100vh-3rem (header hidden) */ import { ReactNode, useRef, useEffect, useCallback } from 'react'; import { ThreeColumnLayout } from '@/components/layout/ThreeColumnLayout'; import { LabSidebar } from './LabSidebar'; import { LabFooter } from './LabFooter'; import { useLabScroll } from '@/contexts/lab-scroll-context'; type LabLayoutProps = { children: ReactNode; }; const SCROLL_THRESHOLD = 50; export const LabLayout = ({ children }: LabLayoutProps) => { const { isScrolled, setIsScrolled } = useLabScroll(); const contentRef = useRef(null); const handleScroll = useCallback(() => { if (!contentRef.current) return; const scrollTop = contentRef.current.scrollTop; setIsScrolled(scrollTop > SCROLL_THRESHOLD); }, [setIsScrolled]); useEffect(() => { const contentElement = contentRef.current; if (!contentElement) return; contentElement.addEventListener('scroll', handleScroll); return () => contentElement.removeEventListener('scroll', handleScroll); }, [handleScroll]); const containerHeight = isScrolled ? 'h-[calc(100vh-3rem)]' : 'h-[calc(100vh-7rem)]'; return ( } center={
{children}
} /> ); };