danielrosehill's picture
Link the master Dataset Navigator
89ba8ce verified
Raw History Blame Contribute Delete
3.78 kB
const HF = "https://huggingface.co/";
const esc = (s) => String(s ?? "").replace(/[&<>"]/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" }[c]));
const link = (path, text) => `<a href="${esc(HF + path)}" target="_blank" rel="noopener">${esc(text)}</a>`;
const size = (b) => (b >= 1e9 ? (b / 1e9).toFixed(1) + " GB" : b >= 1e6 ? Math.round(b / 1e6) + " MB" : Math.max(1, Math.round(b / 1e3)) + " KB");
const logo = (o) => (o === "danielrosehill" ? '<img src="daniel.webp" alt="">' : o === "Hebrish" ? '<img src="hebrish.webp" alt="">' : "");
function card(d) {
const facts = [["Size", size(d.bytes)]];
if (d.rows >= 10) facts.push(["Rows", d.rows.toLocaleString("en-US")]);
if (d.license) facts.push(["License", esc(d.license)]);
return `<article class="card"><div class="who">${logo(d.owner)}<span>${esc(d.owner)} · ${esc(d.type)}</span></div>
<h3>${link("datasets/" + d.id, d.name)}</h3><p>${esc(d.summary)}</p>
${d.gated ? '<div class="meta"><span class="badge">Access request</span></div>' : ""}
<dl class="facts">${facts.map(([k, v]) => `<dt>${k}</dt><dd>${v}</dd>`).join("")}</dl></article>`;
}
const navCard = (n) => `<article class="card"><div class="who"><span>Navigator</span></div><h3>${link("spaces/" + n.space, n.name)}</h3><p>${esc(n.summary)}</p>
<div class="count">${n.count} <span>dataset${n.count === 1 ? "" : "s"}</span></div></article>`;
const topicCard = (g) => `<article class="card"><div class="who"><span>Topic</span></div><h3><a href="#${g.slug}">${esc(g.name)}</a></h3>
<p>${esc(g.datasets.slice(0, 3).map((d) => d.name).join(", "))} and more.</p><div class="count">${g.datasets.length} <span>datasets</span></div></article>`;
(async () => {
const data = await (await fetch("data.json")).json();
const q = document.getElementById("q"), out = document.getElementById("list"), tabs = document.getElementById("tabs");
const navName = Object.fromEntries(data.navigators.map((n) => [n.id, n.name]));
document.getElementById("built").textContent = data.built;
document.getElementById("count").textContent = `${data.total} datasets.`;
const grid = (html) => `<div class="grid">${html}</div>`;
const draw = () => {
const slug = location.hash.slice(1), current = data.groups.find((g) => g.slug === slug);
const term = q.value.trim().toLowerCase();
tabs.innerHTML = [`<a href="#"${!term && !current ? ' aria-current="page"' : ""}>Navigators</a>`,
...data.groups.map((g) => `<a href="#${g.slug}"${!term && g === current ? ' aria-current="page"' : ""}>${esc(g.tab)} (${g.datasets.length})</a>`)].join("");
if (!term) {
out.innerHTML = current ? `<h2>${esc(current.name)}</h2>` + grid(current.datasets.map(card).join(""))
: "<h2>Specialist navigators</h2>" + grid(data.navigators.map(navCard).join("")) + "<h2>By topic</h2>" + grid(data.groups.map(topicCard).join(""));
return;
}
const has = (...parts) => parts.join(" ").toLowerCase().includes(term);
const groups = data.groups.map((g) => [g, g.datasets.filter((d) => has(d.id, d.name, d.type, d.summary))]).filter(([, h]) => h.length);
const inside = data.inside.filter((d) => has(d.id, d.name, navName[d.nav]));
out.innerHTML = groups.map(([g, h]) => `<h2>${esc(g.name)}</h2>` + grid(h.map(card).join(""))).join("")
+ (inside.length ? "<h2>Inside the navigators</h2>" + grid(inside.map((d) => `<article class="card"><div class="who"><span>${esc(d.id.split("/")[0])} · ${esc(navName[d.nav])}</span></div><h3>${link("datasets/" + d.id, d.name)}</h3></article>`).join("")) : "");
if (!out.innerHTML) out.innerHTML = '<p class="empty">No datasets match.</p>';
};
q.addEventListener("input", draw);
addEventListener("hashchange", () => { q.value = ""; draw(); });
draw();
})();