diff --git a/src/components/GlassHeader.tsx b/src/components/GlassHeader.tsx index 3ba99ed..f99dfc1 100644 --- a/src/components/GlassHeader.tsx +++ b/src/components/GlassHeader.tsx @@ -14,13 +14,53 @@ import { cn } from "@/lib/utils"; export default function GlassHeader({ lang: propLang }: GlassHeaderProps) { const [lang, setLang] = useState(propLang || defaultLang); const [currentPath, setCurrentPath] = useState(""); + + const normalizePath = (path: string) => { + const clean = path.split("#")[0].split("?")[0]; + if (!clean) return "/"; + if (clean === "/") return "/"; + return clean.endsWith("/") ? clean.slice(0, -1) : clean; + }; useEffect(() => { - setCurrentPath(window.location.pathname); - const htmlLang = document.documentElement.lang as Lang; - if (htmlLang && (!propLang || htmlLang !== lang)) { - setLang(htmlLang); - } + const updatePath = () => setCurrentPath(normalizePath(window.location.pathname)); + updatePath(); + + const syncLang = () => { + const htmlLang = document.documentElement.lang as Lang; + if (htmlLang && (!propLang || htmlLang !== lang)) { + setLang(htmlLang); + } + }; + syncLang(); + + const originalPushState = history.pushState.bind(history); + const originalReplaceState = history.replaceState.bind(history); + + history.pushState = function (...args) { + originalPushState(...args); + window.dispatchEvent(new Event("locationchange")); + }; + history.replaceState = function (...args) { + originalReplaceState(...args); + window.dispatchEvent(new Event("locationchange")); + }; + + window.addEventListener("popstate", updatePath); + window.addEventListener("locationchange", updatePath); + document.addEventListener("astro:after-swap", updatePath as EventListener); + document.addEventListener("astro:page-load", updatePath as EventListener); + document.addEventListener("astro:page-load", syncLang as EventListener); + + return () => { + history.pushState = originalPushState; + history.replaceState = originalReplaceState; + window.removeEventListener("popstate", updatePath); + window.removeEventListener("locationchange", updatePath); + document.removeEventListener("astro:after-swap", updatePath as EventListener); + document.removeEventListener("astro:page-load", updatePath as EventListener); + document.removeEventListener("astro:page-load", syncLang as EventListener); + }; }, [propLang, lang]); const t = useTranslations(lang); @@ -48,10 +88,13 @@ export default function GlassHeader({ lang: propLang }: GlassHeaderProps) { ]; const isActive = (path: string) => { - if (path === '/' || path === '/zh' || path === '/zh/') { - return currentPath === path; + const normalizedPath = normalizePath(path); + + if (normalizedPath === '/' || normalizedPath === '/zh') { + return currentPath === normalizedPath; } - return currentPath.startsWith(path); + + return currentPath === normalizedPath || currentPath.startsWith(`${normalizedPath}/`); }; return (