diff --git a/src/app/components/AppHeader.tsx b/src/app/components/AppHeader.tsx index a46e6df..9fd1f5f 100644 --- a/src/app/components/AppHeader.tsx +++ b/src/app/components/AppHeader.tsx @@ -21,11 +21,16 @@ export function AppHeader() { const panelRef = React.useRef(null); const blockRefs = React.useRef>({}); const navItemRefs = React.useRef>({}); + const navRowRef = React.useRef(null); + const navTextRefs = React.useRef>({}); const [leftPositions, setLeftPositions] = React.useState>({}); const [panelHeight, setPanelHeight] = React.useState(0); const [blockWidths, setBlockWidths] = React.useState>({}); const closeTimer = React.useRef(null); const [navMinWidths, setNavMinWidths] = React.useState>({}); + const [indicatorLeft, setIndicatorLeft] = React.useState(0); + const [indicatorWidth, setIndicatorWidth] = React.useState(0); + const [indicatorVisible, setIndicatorVisible] = React.useState(false); // 모바일 사이드바 열릴 때만 현재 사용자 정보를 가져옵니다(훅은 항상 동일한 순서로 호출) const { data: meData } = useSWR<{ user: { userId: string; nickname: string; profileImage: string | null; points: number; level: number; grade: number } | null }>( mobileOpen ? "/api/me" : null, @@ -80,6 +85,40 @@ export function AppHeader() { return () => window.removeEventListener("categories:reload", onRefresh); }, [reloadCategories]); + // 상단 네비게이션 선택/호버 인디케이터 업데이트 + const updateIndicator = React.useCallback(() => { + const container = navRowRef.current; + if (!container) return; + const targetSlug = (megaOpen && openSlug) ? openSlug : activeCategorySlug; + if (!targetSlug) { + setIndicatorVisible(false); + return; + } + const itemEl = navItemRefs.current[targetSlug]; + if (!itemEl) { + setIndicatorVisible(false); + return; + } + const cr = container.getBoundingClientRect(); + const ir = itemEl.getBoundingClientRect(); + const inset = 0; // 컨테이너(div) 너비 기준 + const nextLeft = Math.max(0, ir.left - cr.left + inset); + const nextWidth = Math.max(0, ir.width - inset * 2); + setIndicatorLeft(nextLeft); + setIndicatorWidth(nextWidth); + setIndicatorVisible(true); + }, [megaOpen, openSlug, activeCategorySlug]); + + React.useEffect(() => { + updateIndicator(); + }, [updateIndicator, categories]); + + React.useEffect(() => { + const onResize = () => updateIndicator(); + window.addEventListener("resize", onResize); + return () => window.removeEventListener("resize", onResize); + }, [updateIndicator]); + // ESC로 메가메뉴 닫기 React.useEffect(() => { if (!megaOpen) return; @@ -302,7 +341,12 @@ export function AppHeader() { }; }, []); return ( -
+