PageSourceSearch

https://www.halimmadi.com/Assets/js/desktop.js

js halimmadi.com collected 2026-10-07 16:11:14 UTC 14,589 bytes, 407 lines download raw bytes

1/* desktop.js v2 - shared behaviors for the desktop language.
2   1. The HUMAN / MACHINE pill. Built here (no markup on the page) and
3      docked into the page flow: the last child of main.desk, or the node
4      after .page on the older pages. CSS makes it sticky, so it floats at
5      the bottom right while the page is longer than the screen and rests
6      in its own slot above the footer once the reader arrives there. One
7      element, no scroll listener.
8   2. MACHINE opens the page's markdown twin, <dir>/index.md, the page as
9      agents read it: one full-width window at the top of the desk, the
10      other windows hidden. HUMAN, H or Escape puts the page back; M
11      toggles. No API, no seam arithmetic: the same window every time.
12   3. App menu, draggable windows, rotator: as before.
13   Progressive: with JS off there is no pill (it does nothing without JS)
14   and the rotator shows its first image (mark it .is-on in markup). */
15(function () {
16  var LOADING = "loading the room…";
17  var FAILED = "couldn't load this one. it'll come back. ↻";
18  var ORIGIN = "https://www.halimmadi.com";
19
20  function el(tag, cls, text) {
21    var n = document.createElement(tag);
22    if (cls) n.className = cls;
23    if (text != null) n.textContent = text;
24    return n;
25  }
26  function isEditable(t) {
27    if (!t) return false;
28    var tag = t.tagName;
29    return tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || t.isContentEditable === true;
30  }
31
32  // ── the page's twin ────────────────────────────────────────
33  // "/about/" -> "/about/index.md"; "/" -> "/index.md"; a path without its
34  // trailing slash resolves the same way.
35  function pagePath() {
36    var p = location.pathname || "/";
37    p = p.replace(/index\.html$/, "");
38    if (p.charAt(p.length - 1) !== "/") p += "/";
39    return p;
40  }
41  function twinPath() {
42    return pagePath() + "index.md";
43  }
44
45  // ── the pill ───────────────────────────────────────────────
46  var pill = null;
47  var humanBtn = null;
48  var machineBtn = null;
49
50  function option(mode, on) {
51    var b = el("button", "mode-toggle__option" + (on ? " is-active" : ""));
52    b.type = "button";
53    b.setAttribute("data-mode", mode);
54    b.setAttribute("aria-pressed", String(on));
55    var radio = el("span", "mode-toggle__radio");
56    radio.setAttribute("aria-hidden", "true");
57    b.appendChild(radio);
58    b.appendChild(el("span", "mode-toggle__label", mode));
59    b.addEventListener("click", function () {
60      setMode(mode === "machine");
61    });
62    return b;
63  }
64  function buildPill() {
65    if (document.querySelector(".mode-toggle")) return;
66    pill = el("div", "mode-toggle");
67    pill.setAttribute("role", "group");
68    pill.setAttribute("aria-label", "human or machine");
69    humanBtn = option("human", true);
70    machineBtn = option("machine", false);
71    pill.appendChild(humanBtn);
72    pill.appendChild(machineBtn);
73    var desk = document.querySelector("main.desk");
74    var page = document.querySelector(".page");
75    var footer = document.querySelector("footer.fb");
76    if (desk) desk.appendChild(pill);
77    else if (page && page.parentNode) page.parentNode.insertBefore(pill, page.nextSibling);
78    else if (footer && footer.parentNode) footer.parentNode.insertBefore(pill, footer);
79    else document.body.appendChild(pill);
80  }
81  function paintPill(machine) {
82    if (humanBtn) {
83      humanBtn.classList.toggle("is-active", !machine);
84      humanBtn.setAttribute("aria-pressed", String(!machine));
85    }
86    if (machineBtn) {
87      machineBtn.classList.toggle("is-active", machine);
88      machineBtn.setAttribute("aria-pressed", String(machine));
89    }
90  }
91
92  // ── the machine window ─────────────────────────────────────
93  var mx = { win: null, host: null, meta: null, slot: null, copy: null, md: "", scrollY: 0 };
94
95  function tokens(text) {
96    var bytes;
97    try {
98      bytes = new TextEncoder().encode(text).length;
99    } catch (_) {
100      bytes = text.length;
101    }
102    var n = Math.max(100, Math.round(bytes / 4 / 100) * 100);
103    return "~" + String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ",") + " tokens";
104  }
105
106  function buildWindow() {
107    var label = twinPath().replace(/^\//, "");
108    var win = el("section", "win win--machine");
109    win.setAttribute("data-machine-window", "");
110    win.setAttribute("aria-label", "machine");
111
112    var bar = el("div", "win__bar");
113    var dots = el("span", "dots");
114    dots.setAttribute("aria-hidden", "true");
115    dots.appendChild(el("i"));
116    dots.appendChild(el("i"));
117    dots.appendChild(el("i"));
118    bar.appendChild(dots);
119    bar.appendChild(el("p", "win__t", label));
120    var meta = el("span", "win__meta", "");
121    meta.setAttribute("data-machine-meta", "");
122    bar.appendChild(meta);
123    win.appendChild(bar);
124
125    var body = el("div", "win__b");
126    body.appendChild(el("p", "note mx__lead", "this page, as agents read it. the same words, none of the furniture."));
127
128    var cmd = el("div", "mx__cmd");
129    cmd.appendChild(el("span", "k", "fetch"));
130    cmd.appendChild(el("code", "mx__code", 'curl -H "Accept: text/markdown" ' + ORIGIN + pagePath()));
131    var copy = el("button", "btn", "copy");
132    copy.type = "button";
133    copy.setAttribute("data-machine-copy", "");
134    copy.addEventListener("click", copyTwin);
135    cmd.appendChild(copy);
136    body.appendChild(cmd);
137
138    var links = el("p", "mx__links");
139    [
140      ["open raw", twinPath()],
141      ["llms.txt", "/llms.txt"],
142      ["llms-full.txt", "/llms-full.txt"],
143    ].forEach(function (pair) {
144      var a = el("a", "k", pair[0]);
145      a.setAttribute("href", pair[1]);
146      links.appendChild(a);
147    });
148    body.appendChild(links);
149
150    var slot = el("div", "mx__slot");
151    slot.setAttribute("data-machine-slot", "");
152    body.appendChild(slot);
153    win.appendChild(body);
154
155    mx.win = win;
156    mx.meta = meta;
157    mx.slot = slot;
158    mx.copy = copy;
159    return win;
160  }
161
162  function mountWindow(win) {
163    var desk = document.querySelector("main.desk");
164    if (desk) {
165      desk.insertBefore(win, desk.firstElementChild);
166      mx.host = null;
167      return;
168    }
169    var host = el("main", "desk desk--machine");
170    host.appendChild(win);
171    var page = document.querySelector(".page");
172    var footer = document.querySelector("footer.fb");
173    if (page && page.parentNode) page.parentNode.insertBefore(host, page);
174    else if (footer && footer.parentNode) footer.parentNode.insertBefore(host, footer);
175    else document.body.appendChild(host);
176    mx.host = host;
177  }
178
179  function showNote(text, retry) {
180    if (!mx.slot) return;
181    mx.slot.textContent = "";
182    var p = el("p", "note mx__state", text);
183    if (retry) {
184      p.setAttribute("role", "button");
185      p.setAttribute("tabindex", "0");
186      p.addEventListener("click", loadTwin);
187      p.addEventListener("keydown", function (e) {
188        if (e.key === "Enter" || e.key === " ") {
189          e.preventDefault();
190          loadTwin();
191        }
192      });
193    }
194    mx.slot.appendChild(p);
195  }
196
197  function loadTwin() {
198    if (!mx.slot) return;
199    mx.md = "";
200    if (mx.meta) mx.meta.textContent = "";
201    if (mx.copy) mx.copy.disabled = true;
202    showNote(LOADING, false);
203    var want = mx.win;
204    fetch(twinPath(), { headers: { Accept: "text/markdown" }, cache: "no-cache" })
205      .then(function (r) {
206        if (!r.ok) throw new Error("twin " + r.status);
207        return r.text();
208      })
209      .then(function (text) {
210        if (mx.win !== want || !mx.slot) return;
211        mx.md = text;
212        mx.slot.textContent = "";
213        var pre = el("pre", "mx__md", text);
214        pre.setAttribute("data-machine-md", "");
215        mx.slot.appendChild(pre);
216        if (mx.meta) mx.meta.textContent = tokens(text);
217        if (mx.copy) mx.copy.disabled = false;
218      })
219      .catch(function () {
220        if (mx.win !== want) return;
221        showNote(FAILED, true);
222      });
223  }
224
225  function copyTwin() {
226    if (!mx.md || !mx.copy) return;
227    var btn = mx.copy;
228    var done = function () {
229      btn.textContent = "copied";
230      setTimeout(function () {
231        btn.textContent = "copy";
232      }, 1000);
233    };
234    try {
235      navigator.clipboard.writeText(mx.md).then(done, function () {});
236    } catch (_) {
237      /* no clipboard here: the raw file is one link away */
238    }
239  }
240
241  function openMachine() {
242    if (mx.win && mx.win.isConnected) return;
243    mx.scrollY = window.scrollY || 0;
244    var win = buildWindow();
245    mountWindow(win);
246    document.body.classList.add("machine-mode");
247    loadTwin();
248    window.scrollTo(0, 0);
249  }
250  function closeMachine() {
251    var node = mx.host || mx.win;
252    var wasOpen = !!(node && node.parentNode);
253    if (wasOpen) node.parentNode.removeChild(node);
254    mx.win = null;
255    mx.host = null;
256    mx.meta = null;
257    mx.slot = null;
258    mx.copy = null;
259    mx.md = "";
260    document.body.classList.remove("machine-mode");
261    if (wasOpen) window.scrollTo(0, mx.scrollY);
262  }
263
264  function setMode(machine) {
265    paintPill(machine);
266    if (machine) openMachine();
267    else closeMachine();
268  }
269  function isMachine() {
270    return document.body.classList.contains("machine-mode");
271  }
272
273  buildPill();
274  document.addEventListener("keydown", function (e) {
275    if (e.key === "Escape") {
276      if (isMachine()) {
277        e.preventDefault();
278        setMode(false);
279      }
280      return;
281    }
282    if (isEditable(e.target) || e.metaKey || e.ctrlKey || e.altKey) return;
283    if (e.key === "m" || e.key === "M") {
284      e.preventDefault();
285      setMode(!isMachine());
286    } else if (e.key === "h" || e.key === "H") {
287      e.preventDefault();
288      setMode(false);
289    }
290  });
291
292  // ── app menu (the site map behind the wordmark) ───────────
293  var more = document.querySelector("[data-menu-toggle]");
294  var drop = document.querySelector("[data-menu-drop]");
295  if (more && drop) {
296    function closeMenu() {
297      drop.hidden = true;
298      more.setAttribute("aria-expanded", "false");
299    }
300    more.addEventListener("click", function (e) {
301      e.stopPropagation();
302      var open = drop.hidden;
303      drop.hidden = !open;
304      more.setAttribute("aria-expanded", String(open));
305    });
306    document.addEventListener("click", function (e) {
307      if (!drop.hidden && !drop.contains(e.target)) closeMenu();
308    });
309    document.addEventListener("keydown", function (e) {
310      if (e.key === "Escape") closeMenu();
311    });
312  }
313
314  // ── draggable windows (desktop only: fine pointer, wide) ──
315  var canDrag =
316    window.matchMedia &&
317    window.matchMedia("(pointer: fine) and (min-width: 760px)").matches;
318  if (canDrag) {
319    var zTop = 10;
320    document.querySelectorAll(".win > .win__bar").forEach(function (bar) {
321      var win = bar.parentElement;
322      var dx = 0, dy = 0, sx = 0, sy = 0, ox = 0, oy = 0, active = false;
323      bar.addEventListener("pointerdown", function (e) {
324        if (e.button !== 0) return;
325        if (e.target.closest("a, button, input, select, textarea")) return;
326        active = true;
327        sx = e.clientX; sy = e.clientY; ox = dx; oy = dy;
328        win.classList.add("is-dragging", "is-moved");
329        win.style.zIndex = String(++zTop);
330        bar.setPointerCapture(e.pointerId);
331        e.preventDefault();
332      });
333      bar.addEventListener("pointermove", function (e) {
334        if (!active) return;
335        dx = ox + (e.clientX - sx);
336        dy = oy + (e.clientY - sy);
337        win.style.transform = "translate(" + dx + "px," + dy + "px)";
338      });
339      function stop() {
340        if (!active) return;
341        active = false;
342        win.classList.remove("is-dragging");
343      }
344      bar.addEventListener("pointerup", stop);
345      bar.addEventListener("pointercancel", stop);
346      bar.addEventListener("dblclick", function () {
347        dx = dy = 0;
348        win.style.transform = "";
349        win.classList.remove("is-moved");
350      });
351    });
352  }
353
354  // ── rotator ───────────────────────────────────────────────
355  document.querySelectorAll(".rot").forEach(function (rot) {
356    var imgs = rot.querySelectorAll("img");
357    if (imgs.length < 2) return;
358    var i = 0;
359    imgs.forEach(function (im, n) {
360      im.classList.toggle("is-on", n === 0);
361    });
362    setInterval(function () {
363      imgs[i].classList.remove("is-on");
364      i = (i + 1) % imgs.length;
365      imgs[i].classList.add("is-on");
366      var cap = rot.querySelector(".rot__cap");
367      if (cap && imgs[i].dataset.cap) cap.textContent = imgs[i].dataset.cap;
368    }, 5000);
369  });
370})();
371
372/* ═══════════════════════════════════════════
373   Analytics: Umami, privacy-first and cookieless. This used to ride in
374   chrome.js; the desktop language replaced that file, so it lives here.
375   Event names are an API. Never rename them: dashboards and goals
376   depend on the history. Shared across every halimmadi.com surface.
377   ═══════════════════════════════════════════ */
378(function () {
379  var s = document.createElement("script");
380  s.defer = true;
381  s.src = "https://umami-three-dun.vercel.app/script.js";
382  s.setAttribute("data-website-id", "e43d9630-c1e2-4580-abf9-da675306fc6d");
383  document.head.appendChild(s);
384})();
385
386/* Funnel events by delegated click. connect-cta is every path into the
387   form; the form itself fires booking-inquiry on success (connect/). */
388document.addEventListener(
389  "click",
390  function (e) {
391    var a = e.target && e.target.closest ? e.target.closest("a[href]") : null;
392    if (!a || !window.umami) return;
393    var href = a.getAttribute("href") || "";
394    var from = location.pathname;
395    var label = (a.textContent || "").trim().replace(/\s+/g, " ").slice(0, 40);
396    if (/^\/connect\/?(#.*)?$/.test(href) || /halimmadi\.com\/connect/.test(href)) {
397      window.umami.track("connect-cta", { from: from, label: label });
398    } else if (/instagram\.com\/yalla_halim/i.test(href)) {
399      window.umami.track("instagram-click", { from: from });
400    } else if (/halimmadi\.substack\.com/i.test(href)) {
401      window.umami.track("substack-click", { from: from });
402    } else if (/^mailto:/i.test(href)) {
403      window.umami.track("email-click", { from: from });
404    }
405  },
406  true
407);

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.