File size: 2,646 Bytes
1b02f77
 
 
 
 
 
 
 
 
310ba45
 
 
 
1b02f77
 
 
 
310ba45
1b02f77
 
 
 
 
 
 
 
 
310ba45
1b02f77
310ba45
 
 
1b02f77
310ba45
 
1b02f77
 
310ba45
1b02f77
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const HF = "https://huggingface.co/";
const esc = (s) => String(s ?? "").replace(/[&<>"]/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" }[c]));
const link = (id, text) => `<a href="${esc(HF + id)}" target="_blank" rel="noopener">${esc(text)}</a>`;

function card(m) {
  const org = m.owner === "Hebrish";
  const badges = [];
  if (m.status) badges.push(`<span class="badge">${esc(m.status)}</span>`);
  if (m.gated) badges.push('<span class="badge">Access request</span>');
  const facts = [];
  if (m.base_model) facts.push(["Base", link(m.base_model, m.base_model.split("/")[1])]);
  if (m.license) facts.push(["License", esc(m.license)]);
  if (m.variants.length) facts.push(["Formats", m.variants.map((v) => link(v.id, v.label)).join("")]);
  return `<article class="card">
    <div class="who"><img src="${org ? "hebrish.webp" : "daniel.webp"}" alt=""><span>${esc(m.owner)} · ${esc(m.type)}</span></div>
    <h3>${link(m.id, m.name)}</h3><p>${esc(m.summary)}</p>
    ${badges.length ? `<div class="meta">${badges.join("")}</div>` : ""}
    ${facts.length ? `<dl class="facts">${facts.map(([k, v]) => `<dt>${k}</dt><dd>${v}</dd>`).join("")}</dl>` : ""}</article>`;
}

(async () => {
  const data = await (await fetch("data.json")).json();
  const q = document.getElementById("q"), out = document.getElementById("list"), tabs = document.getElementById("tabs");
  const cards = data.groups.reduce((n, g) => n + g.models.length, 0);
  document.getElementById("built").textContent = data.built;
  document.getElementById("count").textContent = `${cards} models across ${data.repos} repositories.`;
  const draw = () => {
    const current = data.groups.find((g) => g.slug === location.hash.slice(1)) || data.groups[0];
    const term = q.value.trim().toLowerCase();
    tabs.innerHTML = data.groups.map((g) => `<a href="#${g.slug}"${!term && g === current ? ' aria-current="page"' : ""}>${esc(g.tab)} (${g.models.length})</a>`).join("");
    const grid = (list) => `<div class="grid">${list.map(card).join("")}</div>`;
    if (!term) { out.innerHTML = `<h2>${esc(current.name)}</h2>` + grid(current.models); return; }
    const match = (m) => [m.id, m.name, m.type, m.summary, m.base_model, ...m.variants.flatMap((v) => [v.id, v.label])].join(" ").toLowerCase().includes(term);
    out.innerHTML = data.groups.map((g) => [g, g.models.filter(match)]).filter(([, hit]) => hit.length)
      .map(([g, hit]) => `<h2>${esc(g.name)}</h2>` + grid(hit)).join("") || '<p class="empty">No models match.</p>';
  };
  q.addEventListener("input", draw);
  addEventListener("hashchange", () => { q.value = ""; draw(); });
  draw();
})();