(() => { "use strict"; const header = document.getElementById("siteHeader"); const menuButton = document.getElementById("menuButton"); const primaryNav = document.getElementById("primaryNav"); const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; const escapeHtml = (value) => String(value ?? "") .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); function updateHeader() { header?.classList.toggle("is-scrolled", window.scrollY > 20); } function closeMenu() { if (!menuButton || !primaryNav) return; menuButton.setAttribute("aria-expanded", "false"); primaryNav.classList.remove("is-open"); } menuButton?.addEventListener("click", () => { const nextOpen = menuButton.getAttribute("aria-expanded") !== "true"; menuButton.setAttribute("aria-expanded", String(nextOpen)); primaryNav?.classList.toggle("is-open", nextOpen); }); primaryNav?.addEventListener("click", (event) => { if (event.target instanceof HTMLAnchorElement) closeMenu(); }); document.addEventListener("keydown", (event) => { if (event.key === "Escape") closeMenu(); }); window.addEventListener("scroll", updateHeader, { passive: true }); updateHeader(); const revealTargets = document.querySelectorAll(".reveal"); if (reduceMotion || !("IntersectionObserver" in window)) { revealTargets.forEach((target) => target.classList.add("is-visible")); } else { const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (!entry.isIntersecting) return; entry.target.classList.add("is-visible"); observer.unobserve(entry.target); }); }, { threshold: 0.14, rootMargin: "0px 0px -6%" }); revealTargets.forEach((target) => observer.observe(target)); } async function readJson(path) { const response = await fetch(path, { headers: { Accept: "application/json" }, cache: "no-store" }); if (!response.ok) throw new Error(`${path}: ${response.status}`); return response.json(); } function normalizePosts(payload) { if (Array.isArray(payload)) return payload; if (Array.isArray(payload?.posts)) return payload.posts; if (Array.isArray(payload?.items)) return payload.items; return []; } function storyColor(index) { return [ "rgba(41,151,255,.62)", "rgba(148,74,255,.55)", "rgba(0,199,190,.45)", "rgba(255,103,31,.45)" ][index % 4]; } function renderPosts(posts) { const target = document.getElementById("latestPosts"); if (!target) return; const published = posts .filter((post) => post && post.href && post.title && post.status !== "planned") .slice(0, 4); if (!published.length) { target.innerHTML = '
MediaMaak

새로운 콘텐츠를 준비하고 있습니다.

'; return; } target.innerHTML = published.map((post, index) => { const category = post.category || post.series || "Insight"; const date = post.date || post.published_at || ""; const summary = post.summary || post.description || ""; return `
${escapeHtml(category)}

${escapeHtml(post.title)}

${summary ? `

${escapeHtml(summary)}

` : ""} ${date ? `` : ""}
`; }).join(""); } async function loadLatestPosts() { try { let payload; try { payload = await readJson("data/news-posts.json"); } catch { payload = await readJson("data/posts.json"); } renderPosts(normalizePosts(payload)); } catch (error) { console.warn("Latest posts unavailable", error); renderPosts([]); } } loadLatestPosts(); })();