diff --git a/apps/landing/src/app/(lab)/layout.tsx b/apps/landing/src/app/(lab)/layout.tsx index 7147cbd..e8b2834 100644 --- a/apps/landing/src/app/(lab)/layout.tsx +++ b/apps/landing/src/app/(lab)/layout.tsx @@ -1,4 +1,40 @@ +'use client'; + import Image from 'next/image'; +import { LabScrollProvider, useLabScroll } from '@/contexts/lab-scroll-context'; + +const LabHeader = () => { + const { isScrolled } = useLabScroll(); + + return ( +
+ +
+ ); +}; export default function LabLayout({ children, @@ -6,29 +42,13 @@ export default function LabLayout({ children: React.ReactNode; }>) { return ( - <> -
- -
- - {children} - + +
+ +
+ {children} +
+
+
); } diff --git a/apps/landing/src/components/layout/lab/LabLayout.tsx b/apps/landing/src/components/layout/lab/LabLayout.tsx index 2441810..4dd48bd 100644 --- a/apps/landing/src/components/layout/lab/LabLayout.tsx +++ b/apps/landing/src/components/layout/lab/LabLayout.tsx @@ -19,28 +19,55 @@ * - 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 } from 'react'; +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}
+
+
{children}
} diff --git a/apps/landing/src/contexts/lab-scroll-context.tsx b/apps/landing/src/contexts/lab-scroll-context.tsx new file mode 100644 index 0000000..c4a529b --- /dev/null +++ b/apps/landing/src/contexts/lab-scroll-context.tsx @@ -0,0 +1,39 @@ +'use client'; + +/** + * Lab Scroll Context + * + * Shares scroll state between the main content area and the header. + * Used to collapse the main header when user scrolls in the lab section. + */ + +import { createContext, useContext, useState, ReactNode } from 'react'; + +type LabScrollContextValue = { + isScrolled: boolean; + setIsScrolled: (value: boolean) => void; +}; + +const LabScrollContext = createContext(null); + +export const useLabScroll = () => { + const context = useContext(LabScrollContext); + if (!context) { + throw new Error('useLabScroll must be used within LabScrollProvider'); + } + return context; +}; + +type LabScrollProviderProps = { + children: ReactNode; +}; + +export const LabScrollProvider = ({ children }: LabScrollProviderProps) => { + const [isScrolled, setIsScrolled] = useState(false); + + return ( + + {children} + + ); +};