// MEDIABROWSER Official Site Script // 1) IntersectionObserver Scroll Reveal // 2) Mobile Navigation Menu Controller // 3) Hero UI Simulator Micro-Interactions // 4) Dynamic Releases Renderer (releases.json) // ── 1. Scroll Reveal Controller ────────────────────────────── (function initReveal() { const items = document.querySelectorAll(".reveal"); if (!items.length) return; if (window.matchMedia("(prefers-reduced-motion: reduce)").matches || !("IntersectionObserver" in window)) { return; } document.documentElement.classList.add("js"); const io = new IntersectionObserver((entries) => { for (const e of entries) { if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); } } }, { threshold: 0.12, rootMargin: "0px 0px -6% 0px" }); items.forEach((el) => io.observe(el)); })(); // ── 2. Mobile Nav Drawer Controller ────────────────────────── (function initMobileNav() { const toggleBtn = document.getElementById("nav-toggle"); const overlay = document.getElementById("mobile-menu"); if (!toggleBtn || !overlay) return; function toggleMenu() { const isActive = overlay.classList.toggle("is-active"); toggleBtn.setAttribute("aria-expanded", String(isActive)); document.body.style.overflow = isActive ? "hidden" : ""; } toggleBtn.addEventListener("click", toggleMenu); overlay.querySelectorAll(".mobile-menu-link").forEach((link) => { link.addEventListener("click", () => { overlay.classList.remove("is-active"); toggleBtn.setAttribute("aria-expanded", "false"); document.body.style.overflow = ""; }); }); })(); // ── 3. Hero UI Simulator Micro-Animation ───────────────────── (function initHeroSimulator() { const progressEl = document.getElementById("sim-progress"); const percentEl = document.getElementById("sim-percent"); const speedEl = document.getElementById("sim-speed"); if (!progressEl || !percentEl || !speedEl) return; let current = 72; let direction = 1; setInterval(() => { if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return; if (direction === 1) { current += 0.8; if (current >= 96) direction = -1; } else { current = 64; direction = 1; } const rounded = Math.min(99, Math.floor(current)); progressEl.style.width = rounded + "%"; percentEl.textContent = rounded + "%"; const baseSpeed = 18.2 + (Math.random() * 2.4 - 1.2); speedEl.textContent = baseSpeed.toFixed(1) + " MB/s"; }, 1200); })(); // ── 4. Releases Renderer ───────────────────────────────────── const PLATFORMS = [ { id: "windows", label: "Windows", icon: "windows-logo", sub: "x64 및 ARM64 네이티브 설치자 (exe)", match: (n) => /setup.*\.exe$/i.test(n) || /win/i.test(n) }, { id: "macos", label: "macOS 프리뷰", icon: "apple-logo", sub: "Apple Silicon & Intel tar.gz 프리뷰 빌드", match: (n) => /osx|darwin|mac/i.test(n) }, { id: "linux", label: "Linux 프리뷰", icon: "linux-logo", sub: "Ubuntu, Fedora, Arch tar.gz 프리뷰 빌드", match: (n) => /linux/i.test(n) }, { id: "android", label: "Android", icon: "android-logo", sub: "스마트폰 로컬 스트리밍 컴패니언 APK", match: (n) => /\.apk$/i.test(n) }, ]; function detectPreferredAsset(name) { const ua = navigator.userAgent; if (/Windows/i.test(ua)) return /setup-x64\.exe$/i.test(name); if (/Android/i.test(ua)) return /\.apk$/i.test(name); if (/Mac/i.test(ua)) return /osx-arm64/i.test(name); if (/Linux/i.test(ua)) return /linux-x64/i.test(name); return false; } function fmtSize(bytes) { if (!bytes) return ""; const mb = bytes / 1048576; return mb >= 1024 ? (mb / 1024).toFixed(1) + " GB" : mb.toFixed(1) + " MB"; } function fmtDate(iso) { if (!iso) return ""; const d = new Date(iso); return `${d.getFullYear()}년 ${d.getMonth() + 1}월 ${d.getDate()}일`; } function esc(s) { return String(s).replace(/[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ }[c])); } function assetRow(a, recommended) { return `
${esc(r.notes)}
` : ""} ${groupsHtml(r.assets)}`; if (featured) { return `${esc(r.notes)}
` : ""} ${groupsHtml(r.assets)}빌드 파이프라인이 정상 작동 중이며 곧 공식 설치자가 배포됩니다. 먼저 사용 안내를 둘러보세요.
네트워크 상태를 확인하고 새로고침해 주세요. 급하신 경우 릴리스 저장소에서 직접 다운로드하실 수 있습니다.