/* SPDX-License-Identifier: Apache-2.0 * * Three behaviours, no framework: * 1. the hero console types a real boot log * 2. sections fade in once, as they arrive * 3. the bar takes a shadow once the page has scrolled under it * * All three are decoration. If this file fails to load the page is still * complete and still readable, which is the test any script on a * documentation site should have to pass. * * Niveus does the rest: its own niveus.js wires the appearance buttons, and * everything visual comes from the stylesheet. Nothing here sets a style. */ (function () { "use strict"; var reduced = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches; /* ---- 1. the boot log ------------------------------------------------ * These are real lines from a real boot, not invented ones. The timer * calibration line in particular is there because of what it cost: the * clock ran seven times slow until a graphics driver was made to * acknowledge its own interrupt. See docs/history/kernel.md. */ var LINES = [ { t: "[ 0.000]", k: "SchIFT", s: " 64-bit, 2 cpus" }, { t: "[ 0.004]", k: "cpu0", s: ": lapic timer 999941980 Hz, tsc 3792 MHz" }, { t: "[ 0.049]", k: "virtio-gpu", s: ": 1280x800, 4000 KB framebuffer" }, { t: "[ 0.088]", k: "e1000", s: ": 52:54:00:12:34:56, link up, irq 11" }, { t: "[ 0.143]", k: "schfs", s: ": mounted 'schos', generation 2" }, { t: "[ 0.169]", k: "net", s: ": eth0 10.0.2.15/255.255.255.0" }, { t: "[ 0.204]", k: "schinit", s: ": ready (pid 1)" }, { t: "[ 0.212]", k: "schinitd", s: ": 2 job(s) loaded, generation 1", g: true }, { t: "", k: "", s: "# " } ]; var out = document.getElementById("bootlog"); /* The classes are Niveus text roles, so the log is coloured by the same tokens as the rest of the page and follows the appearance with it. */ function span(cls, text) { var e = document.createElement("span"); if (cls) e.className = cls; e.textContent = text; return e; } function emit(line) { if (line.t) { out.appendChild(span("nv-text-tertiary", line.t + " ")); out.appendChild(span("nv-text-accent", line.k)); } out.appendChild(span(line.g ? "nv-text-success" : "", line.s)); out.appendChild(document.createTextNode("\n")); } if (out && reduced) { LINES.forEach(emit); // the whole log at once, no animation } else if (out) { var i = 0; (function step() { if (i >= LINES.length) return; emit(LINES[i++]); /* Uneven on purpose: a boot that ticks out at a metronome's pace reads as a progress bar rather than as a machine doing different work. */ setTimeout(step, 180 + Math.random() * 220); })(); } /* ---- 2. reveal on scroll ------------------------------------------ */ var targets = document.querySelectorAll("[data-reveal]"); if (reduced || !("IntersectionObserver" in window)) { Array.prototype.forEach.call(targets, function (el) { el.classList.add("is-revealed"); }); } else { var io = new IntersectionObserver(function (entries) { entries.forEach(function (entry) { if (!entry.isIntersecting) return; entry.target.classList.add("is-revealed"); io.unobserve(entry.target); // once, not on every scroll past }); }, { rootMargin: "0px 0px -12% 0px", threshold: 0.05 }); Array.prototype.forEach.call(targets, function (el) { io.observe(el); }); } /* ---- 3. the bar, once something has passed under it ---------------- */ var bar = document.querySelector(".nv-nav"); if (bar) { var onScroll = function () { if (window.scrollY > 8) bar.setAttribute("data-scrolled", ""); else bar.removeAttribute("data-scrolled"); }; addEventListener("scroll", onScroll, { passive: true }); onScroll(); } /* ---- and remember the appearance ----------------------------------- */ /* * Niveus changes the appearance; which one was chosen is this site's to * keep. The inline script in reads it back before first paint. */ document.documentElement.addEventListener("nv:theme", function (event) { try { localStorage.setItem("schos-theme", (event.detail && event.detail.theme) || "system"); } catch (e) { /* storage unavailable — the choice lasts this visit */ } }); })();