|
| 1 | +/* Knitweb shared navigation — injects one consistent hop-menu into every page |
| 2 | + * so the site is a single connected whole with no dead ends. Self-contained, |
| 3 | + * dependency-free, idempotent, accessible. Include once per page: |
| 4 | + * <script src="/nav.js" defer></script> |
| 5 | + */ |
| 6 | +(function () { |
| 7 | + "use strict"; |
| 8 | + if (document.getElementById("kw-nav")) return; // idempotent |
| 9 | + |
| 10 | + // The whole map — absolute canonical URLs so this exact menu is portable to |
| 11 | + // any host (knitweb.art, 5mart.ml, the repo /web folders) and always links to |
| 12 | + // the same live pages. `match` highlights the active item when served on the |
| 13 | + // canonical host. External properties are marked with ↗. |
| 14 | + var LINKS = [ |
| 15 | + { href: "https://knitweb.art/", label: "Knitweb", brand: true, match: /^\/(index\.html)?$/ }, |
| 16 | + { href: "https://knitweb.art/demos/", label: "Demos", match: /^\/demos\// }, |
| 17 | + { href: "https://knitweb.art/quantum/", label: "QuantumV", match: /^\/quantum\// }, |
| 18 | + { href: "https://knitweb.art/worlds.html", label: "WNW", match: /^\/worlds\.html$/ }, |
| 19 | + { href: "https://knitweb.art/docs/serverless-dapp-model.html", label: "Docs", match: /^\/docs\// }, |
| 20 | + { href: "https://node.knitweb.art", label: "Run a node", ext: true }, |
| 21 | + { href: "https://knitweb.github.io/molgang/", label: "MOLGANG", ext: true }, |
| 22 | + { href: "https://5mart.ml", label: "5mart.ml", ext: true } |
| 23 | + ]; |
| 24 | + |
| 25 | + var path = location.pathname.replace(/\/index\.html$/, "/"); |
| 26 | + |
| 27 | + var css = document.createElement("style"); |
| 28 | + css.textContent = [ |
| 29 | + "#kw-nav{position:sticky;top:0;z-index:9999;display:flex;align-items:center;gap:2px;", |
| 30 | + " padding:7px 14px;font:600 12px/1.4 'SF Mono',ui-monospace,Menlo,Consolas,monospace;", |
| 31 | + " background:rgba(10,13,20,.82);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);", |
| 32 | + " border-bottom:1px solid rgba(120,140,180,.20);overflow-x:auto;white-space:nowrap;scrollbar-width:none}", |
| 33 | + "#kw-nav::-webkit-scrollbar{display:none}", |
| 34 | + "#kw-nav a{color:#93a3bd;text-decoration:none;padding:5px 11px;border-radius:7px;transition:.15s;flex:0 0 auto}", |
| 35 | + "#kw-nav a:hover{color:#eaf1fb;background:rgba(255,255,255,.06)}", |
| 36 | + "#kw-nav a.kw-brand{color:#5fd0a5;font-weight:800;letter-spacing:-.2px;margin-right:6px}", |
| 37 | + "#kw-nav a.kw-active{color:#eaf1fb;background:rgba(95,208,165,.14);box-shadow:inset 0 0 0 1px rgba(95,208,165,.35)}", |
| 38 | + "#kw-nav .kw-ext::after{content:' ↗';color:#78a8ff;font-size:.9em}", |
| 39 | + "#kw-nav .kw-spacer{flex:1 1 auto}" |
| 40 | + ].join(""); |
| 41 | + document.head.appendChild(css); |
| 42 | + |
| 43 | + var nav = document.createElement("nav"); |
| 44 | + nav.id = "kw-nav"; |
| 45 | + nav.setAttribute("aria-label", "Knitweb site"); |
| 46 | + |
| 47 | + LINKS.forEach(function (l, i) { |
| 48 | + var a = document.createElement("a"); |
| 49 | + a.href = l.href; |
| 50 | + a.textContent = l.label; |
| 51 | + if (l.brand) a.className = "kw-brand"; |
| 52 | + if (l.ext) { a.className = (a.className ? a.className + " " : "") + "kw-ext"; a.target = "_blank"; a.rel = "noopener"; } |
| 53 | + if (l.match && l.match.test(path)) { a.className = (a.className ? a.className + " " : "") + "kw-active"; a.setAttribute("aria-current", "page"); } |
| 54 | + nav.appendChild(a); |
| 55 | + if (l.brand) { var sp = document.createElement("span"); sp.className = "kw-spacer"; nav.appendChild(sp); } |
| 56 | + }); |
| 57 | + |
| 58 | + document.body.insertBefore(nav, document.body.firstChild); |
| 59 | +})(); |
0 commit comments