1const stops = [...document.querySelectorAll(".studio-stop[data-scene]")]; 2const sceneImage = document.querySelector(".scene-image"); 3const zoneLinks = [...document.querySelectorAll(".zone-nav a")]; 4const themeButton = document.querySelector("[data-theme-toggle]"); 5let activeIndex = 0; 6 7function updateThemeButton() { 8 const dark = document.documentElement.dataset.theme === "dark"; 9 themeButton.textContent = dark ? "â" : "â¾"; 10 themeButton.setAttribute("aria-label", dark ? "忢尿¥é´æ¨¡å¼" : "忢å°å¤é´æ¨¡å¼"); 11 themeButton.title = dark ? "æ¥é´æ¨¡å¼" : "å¤é´æ¨¡å¼"; 12} 13 14themeButton.addEventListener("click", () => { 15 const nextTheme = document.documentElement.dataset.theme === "dark" ? "light" : "dark"; 16 document.documentElement.dataset.theme = nextTheme; 17 localStorage.setItem("zaiye-site-theme", nextTheme); 18 updateThemeButton(); 19}); 20 21updateThemeButton(); 22 23function revealScene() { 24 document.body.classList.add("scene-ready"); 25} 26 27if (sceneImage.complete && sceneImage.naturalWidth) { 28 revealScene(); 29} else { 30 sceneImage.addEventListener("load", revealScene, { once: true }); 31 sceneImage.addEventListener("error", revealScene, { once: true }); 32} 33 34function showStop(index) { 35 activeIndex = Math.max(0, Math.min(stops.length - 1, index)); 36 const activeStop = stops[activeIndex]; 37 document.body.dataset.scene = activeStop.dataset.scene; 38 stops.forEach((stop, stopIndex) => { 39 stop.classList.toggle("is-active", stopIndex === activeIndex); 40 }); 41 zoneLinks.forEach((link) => { 42 const isCurrent = link.hash === `#${activeStop.id}`; 43 if (isCurrent) link.setAttribute("aria-current", "location"); 44 else link.removeAttribute("aria-current"); 45 }); 46} 47 48function travelTo(index) { 49 const target = stops[Math.max(0, Math.min(stops.length - 1, index))]; 50 target.scrollIntoView({ behavior: "smooth", block: "start" }); 51} 52 53const observer = new IntersectionObserver((entries) => { 54 const visible = entries 55 .filter((entry) => entry.isIntersecting) 56 .sort((left, right) => right.intersectionRatio - left.intersectionRatio)[0]; 57 if (!visible) return; 58 showStop(stops.indexOf(visible.target)); 59}, { threshold: [0.45, 0.65, 0.85] }); 60 61stops.forEach((stop) => observer.observe(stop)); 62 63document.addEventListener("keydown", (event) => { 64 if (event.target.closest("a, button")) return; 65 if (["ArrowDown", "PageDown"].includes(event.key)) { 66 event.preventDefault(); 67 travelTo(activeIndex + 1); 68 } 69 if (["ArrowUp", "PageUp"].includes(event.key)) { 70 event.preventDefault(); 71 travelTo(activeIndex - 1); 72 } 73}); 74 75showStop(0);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.