--- title: Domains --- ```js import {API, POLL} from "./components/config.js"; ``` ```js const domainsState = (async function*() { while (true) { let domains = [], repos = [], ok = false; try { const [rd, rr] = await Promise.all([ fetch(`${API}/domains/?status=all`), fetch(`${API}/repos/`), ]); ok = rd.ok && rr.ok; if (ok) { [domains, repos] = await Promise.all([rd.json(), rr.json()]); } } catch {} yield {domains, repos, ok, ts: new Date()}; await new Promise(res => setTimeout(res, POLL)); } })(); ``` ```js const domains = domainsState.domains ?? []; const repos = domainsState.repos ?? []; const _ok = domainsState.ok ?? false; const _ts = domainsState.ts; ``` # Domains ```js import {injectTocTop} from "./components/toc-sidebar.js"; import {withDocHelp} from "./components/doc-overlay.js"; import {openEntityModal} from "./components/entity-modal.js"; // ── Live indicator ───────────────────────────────────────────────────────────── const _liveEl = html`
${_ok ? `Live · updated ${_ts?.toLocaleTimeString()}` : html`Offline — run: make api`}
`; withDocHelp(_liveEl, "/docs/live-data"); injectTocTop("live-indicator", _liveEl); const _h1 = document.querySelector("#observablehq-main h1"); if (_h1) { _h1.style.position = "relative"; withDocHelp(_h1, "/docs/domains"); } // ── KPI row ──────────────────────────────────────────────────────────────────── const activeDomains = domains.filter(d => d.status === "active"); const archivedDomains = domains.filter(d => d.status === "archived"); const newestDomain = [...domains].sort((a, b) => b.created_at?.localeCompare(a.created_at ?? "") ?? 0)[0]; display(html`
${domains.length}
total domains
${activeDomains.length}
active
${repos.length}
total repos
${newestDomain?.name ?? "—"}
newest domain
`); ``` ## Domain Cards ```js // Build repo index by domain_id const reposByDomain = {}; for (const repo of repos) { if (!reposByDomain[repo.domain_id]) reposByDomain[repo.domain_id] = []; reposByDomain[repo.domain_id].push(repo); } if (domains.length === 0) { display(html`

No domains found. API may be offline.

`); } else { display(html`
${domains.map(d => { const domainRepos = reposByDomain[d.id] ?? []; return html`
${d.slug} ${d.status}
${d.name}
${d.description ? html`
${d.description.slice(0, 160)}${d.description.length > 160 ? " …" : ""}
` : ""}
${domainRepos.length === 0 ? html`no repos registered` : domainRepos.map(r => html`
${r.name} ${r.local_path ? html`${r.local_path}` : ""} ${r.remote_url ? html`${r.remote_url.replace(/^https?:\/\//, "")}` : ""}
`) }
`; })}
`); } ```