Jump to…
snowfeat: given a new redesign and emulated terminal homepagerxkspqmsoknz1mo
Matt W1// The ⌘K palette. Enhancement only.
Matt W2//
Matt W3// Without this script the masthead control is a plain link to /search and the
Matt W4// overlay stays `hidden`, so nothing here is load-bearing — it is a faster
Matt W5// route to a page that is reachable anyway. That is also why the ⌘K keycap
Matt W6// starts hidden in the markup: advertising a shortcut that does not work is
Matt W7// worse than not advertising it.
Matt W8//
Matt W9// Results come from htmx hitting /search?fragment=1. This file never renders a
Matt W10// result, so there is no second copy of the visibility rule to get wrong.
Matt W11(function () {
Matt W12 var backdrop = document.querySelector("[data-palette]");
Matt W13 var input = document.querySelector("[data-palette-input]");
Matt W14 if (!backdrop || !input) return;
Matt W15
Matt W16 var opener = document.querySelector("[data-palette-open]");
Matt W17 var kbd = document.querySelector("[data-palette-kbd]");
Matt W18 var lastFocus = null;
Matt W19
Matt W20 // Mac gets ⌘, everything else Ctrl. Checking the platform is unreliable in
Matt W21 // general but perfectly adequate for choosing which glyph to draw.
Matt W22 var isMac = /Mac|iPhone|iPad/.test(navigator.platform || "");
Matt W23 if (kbd) {
Matt W24 kbd.textContent = isMac ? "⌘K" : "Ctrl K";
Matt W25 kbd.hidden = false;
Matt W26 }
Matt W27
Matt W28 function open() {
Matt W29 if (!backdrop.hidden) return;
Matt W30 lastFocus = document.activeElement;
Matt W31 backdrop.hidden = false;
Matt W32 input.value = "";
Matt W33 input.focus();
Matt W34 }
Matt W35
Matt W36 function close() {
Matt W37 if (backdrop.hidden) return;
Matt W38 backdrop.hidden = true;
Matt W39 if (lastFocus && lastFocus.focus) lastFocus.focus();
Matt W40 }
Matt W41
Matt W42 if (opener) {
Matt W43 opener.addEventListener("click", function (e) {
Matt W44 e.preventDefault();
Matt W45 open();
Matt W46 });
Matt W47 }
Matt W48
Matt W49 document.addEventListener("keydown", function (e) {
Matt W50 var accel = isMac ? e.metaKey : e.ctrlKey;
Matt W51 if (accel && (e.key === "k" || e.key === "K")) {
Matt W52 e.preventDefault();
Matt W53 backdrop.hidden ? open() : close();
Matt W54 return;
Matt W55 }
Matt W56 if (e.key === "Escape" && !backdrop.hidden) {
Matt W57 e.preventDefault();
Matt W58 close();
Matt W59 }
Matt W60 });
Matt W61
Matt W62 // Clicking the backdrop closes; clicking the panel inside it must not.
Matt W63 backdrop.addEventListener("click", function (e) {
Matt W64 if (e.target === backdrop) close();
Matt W65 });
Matt W66
Matt W67 // Arrow keys walk the results. The input keeps focus throughout so typing
Matt W68 // never has to be resumed — only Enter leaves, by following the active row.
Matt W69 function items() {
Matt W70 return Array.prototype.slice.call(
Matt W71 backdrop.querySelectorAll(".palette-item")
Matt W72 );
Matt W73 }
Matt W74
Matt W75 function activeIndex(list) {
Matt W76 for (var i = 0; i < list.length; i++) {
Matt W77 if (list[i].classList.contains("is-active")) return i;
Matt W78 }
Matt W79 return -1;
Matt W80 }
Matt W81
Matt W82 function activate(list, i) {
Matt W83 list.forEach(function (el) {
Matt W84 el.classList.remove("is-active");
Matt W85 });
Matt W86 if (list[i]) {
Matt W87 list[i].classList.add("is-active");
Matt W88 list[i].scrollIntoView({ block: "nearest" });
Matt W89 }
Matt W90 }
Matt W91
Matt W92 input.addEventListener("keydown", function (e) {
Matt W93 var list = items();
Matt W94 if (!list.length) return;
Matt W95 var i = activeIndex(list);
Matt W96
Matt W97 if (e.key === "ArrowDown") {
Matt W98 e.preventDefault();
Matt W99 activate(list, i + 1 >= list.length ? 0 : i + 1);
Matt W100 } else if (e.key === "ArrowUp") {
Matt W101 e.preventDefault();
Matt W102 activate(list, i <= 0 ? list.length - 1 : i - 1);
Matt W103 } else if (e.key === "Enter") {
Matt W104 // With nothing selected, fall through to the form's own behaviour:
Matt W105 // a full search for whatever was typed.
Matt W106 if (i < 0) return;
Matt W107 e.preventDefault();
Matt W108 list[i].click();
Matt W109 }
Matt W110 });
Matt W111
Matt W112 // Fresh results, fresh selection: the first row is pre-selected so Enter
Matt W113 // does the obvious thing immediately after typing.
Matt W114 document.body.addEventListener("htmx:afterSwap", function (e) {
Matt W115 if (e.target && e.target.id === "palette-results") {
Matt W116 var list = items();
Matt W117 if (list.length) activate(list, 0);
Matt W118 }
Matt W119 });
Matt W120
Matt W121 backdrop.addEventListener("click", function (e) {
Matt W122 var cmd = e.target.closest && e.target.closest("[data-palette-theme]");
Matt W123 if (cmd && window.dogfoodToggleTheme) {
Matt W124 e.preventDefault();
Matt W125 window.dogfoodToggleTheme();
Matt W126 close();
Matt W127 }
Matt W128 });
Matt W129})();

129 lines · JavaScript