import { detectLanguage, translations } from "./i18n.js"; import { getRouteConfig, getRouteFromHash, loadPartial, navigateTo } from "./router.js"; import { TerminalConsole } from "./terminal-console.js"; const pageTitleEl = document.getElementById("pageTitle"); const pageOutletEl = document.getElementById("pageOutlet"); const navLinks = Array.from(document.querySelectorAll(".nav-link")); const navGroups = Array.from(document.querySelectorAll(".nav-group.has-flyout")); const navGroupToggles = Array.from(document.querySelectorAll("[data-group-toggle]")); const sidebarToggleEl = document.getElementById("sidebarToggle"); const sidebarBackdropEl = document.getElementById("sidebarBackdrop"); const langKoEl = document.getElementById("langKo"); const langEnEl = document.getElementById("langEn"); let currentLanguage = detectLanguage(); let activeRoute = getRouteFromHash(); let activeController = null; function t(key) { return translations[currentLanguage]?.[key] ?? translations.en[key] ?? key; } function applyTranslations(root = document) { document.documentElement.lang = currentLanguage; document.title = currentLanguage === "ko" ? "TeraClone 콘솔 서버" : "TeraClone Console Server"; root.querySelectorAll("[data-i18n]").forEach((element) => { element.textContent = t(element.dataset.i18n); }); updatePageTitle(); updateLanguageButtons(); activeController?.updateTranslations?.(t); } function updateLanguageButtons() { langKoEl?.classList.toggle("active", currentLanguage === "ko"); langEnEl?.classList.toggle("active", currentLanguage === "en"); } function updatePageTitle() { pageTitleEl.textContent = t(getRouteConfig(activeRoute).titleKey); } function setSidebarOpen(open) { document.body.classList.toggle("sidebar-open", open); if (sidebarBackdropEl) { sidebarBackdropEl.hidden = !open; } } function setActiveNav(routeName) { navLinks.forEach((item) => { item.classList.toggle("active", item.dataset.route === routeName); }); } function bindNav() { navLinks.forEach((item) => { item.addEventListener("click", () => { navigateTo(item.dataset.route); navGroups.forEach((group) => group.classList.remove("open")); const parentGroup = item.closest(".nav-group"); if (parentGroup && window.innerWidth > 920) { parentGroup.classList.add("suppress-hover"); } item.blur(); }); }); navGroups.forEach((group) => { group.addEventListener("mouseleave", () => { group.classList.remove("suppress-hover"); }); }); navGroupToggles.forEach((toggle) => { toggle.addEventListener("click", () => { if (window.innerWidth > 920) { return; } const group = toggle.closest(".nav-group"); if (!group) { return; } const willOpen = !group.classList.contains("open"); navGroups.forEach((item) => item.classList.remove("open")); group.classList.toggle("open", willOpen); }); }); } function bindChrome() { sidebarToggleEl?.addEventListener("click", () => { setSidebarOpen(!document.body.classList.contains("sidebar-open")); }); sidebarBackdropEl?.addEventListener("click", () => { setSidebarOpen(false); }); langKoEl?.addEventListener("click", () => { currentLanguage = "ko"; localStorage.setItem("teraclone-language", currentLanguage); applyTranslations(document); }); langEnEl?.addEventListener("click", () => { currentLanguage = "en"; localStorage.setItem("teraclone-language", currentLanguage); applyTranslations(document); }); window.addEventListener("resize", () => { if (window.innerWidth > 920) { setSidebarOpen(false); navGroups.forEach((group) => group.classList.remove("open")); } }); } async function renderRoute(routeName) { activeController?.unmount?.(); activeController = null; const partial = await loadPartial(routeName); pageOutletEl.innerHTML = partial; activeRoute = routeName; setActiveNav(routeName); applyTranslations(pageOutletEl); if (routeName === "terminal") { activeController = new TerminalConsole(t); activeController.mount(); } if (window.innerWidth <= 920) { setSidebarOpen(false); } } async function syncRoute() { const routeName = getRouteFromHash(); await renderRoute(routeName); } bindNav(); bindChrome(); applyTranslations(document); window.addEventListener("hashchange", syncRoute); if (!window.location.hash) { navigateTo("overview"); } else { syncRoute(); }