'use client'; import { useState, useCallback } from 'react'; import { usePathname } from 'next/navigation'; import Styles from '../styles/layout.module.scss'; import Header from './Header'; import Footer from './Footer' import ChannelSidebar from '@/app/component/channel/ChannelSidebar'; import MarketSidebar from '@/app/component/MarketSidebar'; import ChatDock from '@/app/component/ChatDock'; import { ChannelListItem } from '@/types/channel'; import { FEATURE_CHANNEL } from '@/constants/features'; type Props = { children: React.ReactNode; initialChannels?: ChannelListItem[]; // 우측 유틸 슬롯 (D6 3열 그리드) — 제공 페이지만 desktop 이상에서 3열 렌더 utility?: React.ReactNode; }; export default function Layout({ children, initialChannels, utility }: Props) { const [sidebarOpen, setSidebarOpen] = useState(false); const pathname = usePathname(); const toggleSidebar = useCallback(() => { setSidebarOpen((prev) => !prev); }, []); const closeOverlay = useCallback(() => { setSidebarOpen(false); }, []); // 좌측 사이드바 노출 규칙: // - 채널 기능 ON → 항상(채널 목록은 전역 내비) // - 채널 기능 OFF → 종목(/stock) 계열에서만(관심종목). 그 외 페이지는 no-aside 로 본문 확장 const isStockRoute = pathname === '/stock' || pathname.startsWith('/stock/'); const showAside = FEATURE_CHANNEL || isStockRoute; return ( <> {/* 접근성: 스킵 링크 — Tab 첫 포커스 시 노출 */} 본문 바로가기
{/* 모바일 오버레이 */}
{/* 좌측 사이드바 — 채널 기능 ON: 채널 목록 / OFF: 관심종목(종목 메뉴에서만) */} {showAside && ( )} {/* 메인 내용 */}
{children}
{/* 우측 유틸 슬롯 (desktop 이상 전용) */} {utility && ( )} {/* 우측 고정 채팅 도크 — 페이지 전환에도 유지(상시 마운트). desktop=컬럼(접기), mobile=드로어 */} {/* 하단 */}
); }