theseus + site: fix duplicate extension cards + real-icon rendering

- Settings > Extensions: the Community list showed an entry even for
  extensions already listed above under Installed, so docx-editor
  appeared twice as soon as it landed in the gateway catalog. The
  render now filters out any catalog item whose id is installed —
  the Installed list handles updates via the poll + "Check for
  updates" button, so the Community list only needs to surface
  things you don't have. Empty-state copy branches on whether the
  catalog is empty vs "everything is installed".
- theseus.x/extensions catalog renderer accepts data:image/... icons
  in addition to emoji, so an extension whose manifest.icon is an
  SVG data URI (pdf-editor, docx-editor) renders as an <img> instead
  of the raw URI text.
- Static PDF Editor entry on that page now uses the same inline SVG
  badge the browser dock renders.
This commit is contained in:
Local Dev 2026-09-21 02:43:10 +02:00
parent be36492d8a
commit 1637e2dd16

View file

@ -181,7 +181,7 @@
</div>
<div class="ext" id="pdf-editor" data-ext="pdf-editor">
<h3><span class="icon">📄</span> PDF Editor <span class="cur" style="margin-left:auto">current <span data-live="version">0.1.0</span></span></h3>
<h3><span class="icon" aria-hidden="true"><svg width="20" height="20" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" style="vertical-align:middle"><path d="M6 2h8l6 6v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2z" fill="#dc2626"/><path d="M14 2v6h6z" fill="#991b1b"/><text x="12" y="17" text-anchor="middle" font-family="system-ui,-apple-system,sans-serif" font-size="5.5" font-weight="800" fill="#fff">PDF</text></svg></span> PDF Editor <span class="cur" style="margin-left:auto">current <span data-live="version">0.1.0</span></span></h3>
<div class="desc">Open a PDF in a full tab — read, highlight, mark up, reorder or rotate or drop pages,
fill form fields, save a new copy. Annotations are written as real PDF content, the original
is never touched. Opens from the toolbar's PDF Editor menu or the right-click <i>Open PDF in editor</i>
@ -278,9 +278,14 @@
const cat = r.ok ? await r.json() : { extensions: [] };
const list = Array.isArray(cat.extensions) ? cat.extensions : [];
if (!list.length) { box.innerHTML = '<div class="ext" style="color:var(--dim)">Nothing published yet — yours could be the first. See <a href="#build">Build and publish your own</a>.</div>'; return; }
const iconHtml = (icon) => {
const s = String(icon || "🧩");
if (/^data:image\//i.test(s)) return `<img src="${esc(s)}" alt="" style="width:20px;height:20px;vertical-align:middle">`;
return esc(s);
};
box.innerHTML = list.map((e) => `
<div class="ext" id="ext-${esc(e.id)}">
<h3><span class="icon">${esc(e.icon || "🧩")}</span> ${esc(e.name)} <span class="cur" style="margin-left:auto">v${esc(e.latest)}</span></h3>
<h3><span class="icon">${iconHtml(e.icon)}</span> ${esc(e.name)} <span class="cur" style="margin-left:auto">v${esc(e.latest)}</span></h3>
<div class="desc">${esc(e.description)}</div>
<div class="meta">Published by <b>${esc(e.publisher)}</b> · ${esc(String(e.versions || 1))} version${e.versions === 1 ? "" : "s"} · updated ${esc(String(e.updatedAt || "").slice(0, 10))}${e.capabilities && e.capabilities.length ? " · " + esc(e.capabilities.join(", ")) : ""}</div>
<div class="act">${installUi(e.id)}</div>