// mindX docs reader: the three public documents in full (bundled, hashed in the browser against // the map), the Thesis and Manifesto read aloud, and the library of every document linked to its // page on mindx.pythai.net. Markdown goes through marked, then DOMPurify, then the link rewriter. (function () { 'use strict'; var SITE = 'https://mindx.pythai.net'; var HUB = 'https://huggingface.co/datasets/PYTHAI/mindX-docs/blob/main/docs/'; var HERE = { THESIS: 1, MANIFESTO: 1, NAV: 1 }; // bundled in this Space, byte-identical to the node var LABEL = { THESIS: 'Thesis', MANIFESTO: 'Manifesto', NAV: 'Navigation' }; var index = { docs: [] }, byName = {}, audio = {}; var tierFilter = 'all', query = ''; function $(id) { return document.getElementById(id); } function el(tag, cls, text) { var e = document.createElement(tag); if (cls) e.className = cls; if (text != null) e.textContent = String(text); return e; } function link(href, text, cls, internal) { var a = el('a', cls, text); a.href = href; if (internal) a.target = '_self'; else a.rel = 'noopener'; return a; } function nameOf(path) { return path.replace(/\.md$/i, ''); } function mins(sec) { var m = Math.round(sec / 60); return m + ' min'; } function fmt(n) { return Number(n).toLocaleString('en-US'); } function clear(n) { while (n.firstChild) n.removeChild(n.firstChild); } function slug(s) { return String(s).toLowerCase().trim().replace(/[^\w\s-]/g, '').replace(/\s+/g, '-'); } // ---------- listen ---------- function player(name) { var a = audio[name]; if (!a) return null; var card = el('div', 'card player'); card.appendChild(el('span', 'kind', 'listen · ' + mins(a.seconds) + ' · ' + a.parts.length + ' parts')); card.appendChild(el('h3', null, LABEL[name])); var d = byName[name]; if (d) card.appendChild(el('p', 'muted', d.title)); var au = document.createElement('audio'); au.controls = true; au.preload = 'none'; var part = 0; var status = el('div', 'part-status'); function load(i, play) { part = i; au.src = a.parts[i].file; status.textContent = 'part ' + (i + 1) + ' of ' + a.parts.length + ' · ' + mins(a.parts[i].seconds); Array.prototype.forEach.call(list.children, function (b, j) { b.classList.toggle('on', j === i); }); if (play) au.play().catch(function () {}); } au.addEventListener('ended', function () { if (part + 1 < a.parts.length) load(part + 1, true); }); card.appendChild(au); var list = el('div', 'parts'); a.parts.forEach(function (p, i) { var b = el('button', 'chip', (i + 1) + ' · ' + mins(p.seconds)); b.type = 'button'; b.addEventListener('click', function () { load(i, true); }); list.appendChild(b); }); card.appendChild(status); card.appendChild(list); var actions = el('div', 'actions'); actions.appendChild(link('docs.html?doc=' + name, 'read along ↓', 'more', true)); actions.lastChild.addEventListener('click', function (e) { e.preventDefault(); open(name, true); }); actions.appendChild(link(a.listen_url, 'listen on mindx.pythai.net ↗', 'more')); actions.appendChild(link(SITE + '/doc/' + name, 'read on mindx.pythai.net ↗', 'more')); card.appendChild(actions); card.appendChild(el('p', 'fine', 'Read by ' + a.voice.replace('piper:', 'piper · ') + ', rendered on my node from exactly these bytes · Ogg Opus')); load(0, false); return card; } // ---------- library ---------- function renderLibrary() { var ul = $('lib-list'); clear(ul); var q = query.toLowerCase(), shown = 0; var docs = index.docs.slice().sort(function (a, b) { var ta = a.tier === 'public' ? 0 : a.tier === 'member' ? 1 : 2, tb = b.tier === 'public' ? 0 : b.tier === 'member' ? 1 : 2; return ta - tb || a.path.localeCompare(b.path); }); docs.forEach(function (d) { if (tierFilter !== 'all' && d.tier !== tierFilter) return; if (q && (d.title + ' ' + d.path).toLowerCase().indexOf(q) < 0) return; shown++; if (shown > 400) return; var li = el('li', 'lib-item tier-' + d.tier); var name = nameOf(d.path); var a = HERE[name] ? link('docs.html?doc=' + name, d.title, 'lib-title', true) : link(d.url, d.title, 'lib-title'); if (HERE[name]) a.addEventListener('click', function (e) { e.preventDefault(); open(name, true); }); li.appendChild(a); var meta = el('span', 'lib-meta', d.path + ' · ' + fmt(d.words) + ' words'); li.appendChild(meta); li.appendChild(el('span', 'tag ' + (d.tier === 'public' ? 'ok' : d.tier === 'member' ? 'warn' : 'dim'), d.tier)); ul.appendChild(li); }); if (shown > 400) ul.appendChild(el('li', 'lib-more', (shown - 400) + ' more. Refine the search.')); if (!shown) ul.appendChild(el('li', 'lib-more', 'Nothing matches.')); var c = index.counts || {}; $('lib-count').textContent = fmt(index.docs.length) + ' documents · ' + (c.public || 0) + ' public'; } // ---------- reader ---------- function rewrite(root, current) { Array.prototype.slice.call(root.querySelectorAll('a[href]')).forEach(function (a) { var href = a.getAttribute('href') || ''; if (/^(https?:|mailto:)/i.test(href)) { a.target = '_blank'; a.rel = 'noopener'; return; } if (href.charAt(0) === '#') { a.target = '_self'; a.addEventListener('click', function (e) { var t = document.getElementById('h-' + slug(decodeURIComponent(href.slice(1)))); if (t) { e.preventDefault(); t.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); return; } var u; try { u = new URL(href, 'https://x.invalid/docs/'); } catch (e) { u = null; } var path = u ? u.pathname : ''; var md = /\.md$/i.test(path); if (md && path.indexOf('/docs/') === 0) { var name = decodeURIComponent(path.slice(6).replace(/\.md$/i, '')); if (HERE[name]) { a.href = 'docs.html?doc=' + name; a.target = '_self'; a.addEventListener('click', function (e) { e.preventDefault(); open(name, true); }); } else { a.href = SITE + '/doc/' + name; a.target = '_blank'; a.rel = 'noopener'; var d = byName[name]; a.title = d ? d.title + ' · ' + d.tier + ' · on mindx.pythai.net' : 'on mindx.pythai.net'; a.classList.add('ext-doc'); } return; } if (md) { // a Markdown file outside docs/: the node resolves it by name a.href = SITE + '/doc/' + path.split('/').pop().replace(/\.md$/i, ''); a.target = '_blank'; a.rel = 'noopener'; a.classList.add('ext-doc'); return; } // a source file: the active repository is private, so the reference stays as text var span = el('span', 'src-ref', a.textContent); span.title = 'in mindX’s source: ' + path.replace(/^\/+/, ''); a.parentNode.replaceChild(span, a); }); Array.prototype.slice.call(root.querySelectorAll('img')).forEach(function (img) { if (!/^https:/i.test(img.getAttribute('src') || '')) img.remove(); }); Array.prototype.slice.call(root.querySelectorAll('h1,h2,h3,h4')).forEach(function (h) { h.id = 'h-' + slug(h.textContent); }); } function hashHex(buf) { return crypto.subtle.digest('SHA-256', buf).then(function (d) { return Array.prototype.map.call(new Uint8Array(d), function (b) { return ('0' + b.toString(16)).slice(-2); }).join(''); }); } function meta(name, d, verdict) { var m = $('doc-meta'); clear(m); var row = el('div', 'meta-row'); row.appendChild(el('span', 'tag ' + (d.tier === 'public' ? 'ok' : 'dim'), d.tier)); row.appendChild(el('span', 'fine', d.path + ' · ' + fmt(d.words) + ' words')); if (verdict) row.appendChild(el('span', 'fine ' + (verdict.ok ? 'ok-text' : 'bad-text'), verdict.text)); m.appendChild(row); var actions = el('div', 'actions'); actions.appendChild(link(SITE + '/doc/' + name, 'read on mindx.pythai.net ↗', 'btn small')); if (audio[name]) { var l = link('#listen', 'listen here', 'btn small', true); l.addEventListener('click', function (e) { e.preventDefault(); $('listen').scrollIntoView({ behavior: 'smooth' }); }); actions.appendChild(l); actions.appendChild(link(audio[name].listen_url, 'listen on mindx.pythai.net ↗', 'btn small')); } if (HERE[name]) actions.appendChild(link(HUB + name + '.md', 'Markdown on the Hub ↗', 'btn small')); m.appendChild(actions); } function open(name, scroll) { var d = byName[name] || byName.NAV; name = nameOf(d.path); try { history.replaceState(null, '', 'docs.html?doc=' + encodeURIComponent(name)); } catch (e) {} var body = $('doc-body'); if (!HERE[name]) { // the library links these straight to the node; this is the fallback view meta(name, d, null); clear(body); body.appendChild(el('h1', null, d.title)); body.appendChild(el('p', null, 'This document is ' + d.tier + '-tier. It is on my node, behind the same gate as everything else there.')); body.appendChild(link(d.url, 'open it on mindx.pythai.net ↗', 'btn')); return; } meta(name, d, { ok: true, text: 'checking sha256…' }); clear(body); body.appendChild(el('p', 'muted', 'Loading ' + LABEL[name] + '…')); fetch('docs/' + name + '.md', { cache: 'no-cache' }).then(function (r) { if (!r.ok) throw new Error(r.status); return r.arrayBuffer(); }).then(function (buf) { var text = new TextDecoder('utf-8').decode(buf); var html = window.DOMPurify.sanitize(window.marked.parse(text), { USE_PROFILES: { html: true } }); clear(body); var frag = document.createElement('div'); frag.innerHTML = html; rewrite(frag, name); while (frag.firstChild) body.appendChild(frag.firstChild); if (scroll) $('reader').scrollIntoView({ behavior: 'smooth', block: 'start' }); return (window.crypto && crypto.subtle) ? hashHex(buf).then(function (hex) { meta(name, d, hex === d.sha256 ? { ok: true, text: 'sha256 ' + hex.slice(0, 12) + '… matches the map' } : { ok: false, text: 'sha256 ' + hex.slice(0, 12) + '… differs from the map' }); }) : meta(name, d, null); }).catch(function () { clear(body); body.appendChild(el('p', null, 'This copy did not load.')); body.appendChild(link(SITE + '/doc/' + name, 'read it on mindx.pythai.net ↗', 'btn')); }); } // ---------- boot ---------- $('lib-search').addEventListener('input', function (e) { query = e.target.value; renderLibrary(); }); Array.prototype.forEach.call(document.querySelectorAll('#lib-chips .chip'), function (b) { b.addEventListener('click', function () { tierFilter = b.getAttribute('data-tier'); Array.prototype.forEach.call(document.querySelectorAll('#lib-chips .chip'), function (x) { x.classList.toggle('on', x === b); }); renderLibrary(); }); }); Promise.all([ fetch('docs/index.json').then(function (r) { return r.json(); }).catch(function () { return { docs: [] }; }), fetch('audio/index.json').then(function (r) { return r.json(); }).catch(function () { return {}; }) ]).then(function (res) { index = res[0]; audio = res[1]; index.docs.forEach(function (d) { byName[nameOf(d.path)] = d; }); var box = $('players'); ['THESIS', 'MANIFESTO'].forEach(function (n) { var p = player(n); if (p) box.appendChild(p); }); renderLibrary(); var want = (new URLSearchParams(location.search).get('doc') || '').toUpperCase(); open(HERE[want] ? want : 'THESIS', false); if (location.hash === '#listen') $('listen').scrollIntoView(); }); })();