banatie-service/apps/landing/src/components/layout/lab/LabLayout.tsx

77 lines
2.5 KiB
TypeScript

'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<HTMLDivElement>(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 (
<ThreeColumnLayout
left={
<div className={`border-r border-zinc-800 bg-zinc-950/50 backdrop-blur-sm ${containerHeight} overflow-y-auto transition-all duration-300`}>
<LabSidebar />
</div>
}
center={
<div className={`flex flex-col ${containerHeight} transition-all duration-300`}>
<div ref={contentRef} className="flex-1 overflow-y-auto min-h-0">{children}</div>
<LabFooter />
</div>
}
/>
);
};