roulette / js /ui.js
ratandeep's picture
Deploy Build Small Roulette — static space serendipity engine for the org
653b61d
Raw
History Blame Contribute Delete
4.05 kB
const $ = (id) => document.getElementById(id);
export function renderCard(vm, store) {
$("topbar").hidden = false;
$("bottombar").hidden = false;
$("card-emoji").textContent = vm.emoji;
$("card-title").textContent = vm.title;
const track = $("card-track");
track.hidden = !vm.track;
track.textContent = vm.track || "";
const likes = $("hf-likes");
likes.textContent = `♥ ${vm.likes}`;
likes.href = vm.hfUrl;
$("btn-open").href = vm.hfUrl;
setLikeState(store.isLiked(vm.id));
setSaveState(store.isSaved(vm.id));
}
export function setLikeState(on) { $("btn-like").classList.toggle("on", !!on); }
export function setSaveState(on) { $("btn-save").classList.toggle("on", !!on); }
export function setHfLikes(n) { $("hf-likes").textContent = `♥ ${n}`; }
export function setProgress(p) {
$("progress").textContent = `↳ ${p.seen} / ${p.total} seen · lap ${p.round}`;
}
export function setSavedCount(n) { $("btn-saved").textContent = `☰ Saved (${n})`; }
export function setTrackFilterLabel(track) {
$("btn-track").textContent = `⤮ ${track || "All"}`;
}
let toastTimer = null;
export function toast(msg, ms = 2600) {
const t = $("toast");
t.textContent = msg;
t.hidden = false;
clearTimeout(toastTimer);
toastTimer = setTimeout(() => (t.hidden = true), ms);
}
export function renderAuth(user, { onSignIn, onSignOut }) {
const a = $("auth");
a.innerHTML = "";
if (user) {
const img = document.createElement("img");
img.src = user.picture; img.width = 22; img.height = 22;
img.className = "avatar";
const out = document.createElement("button");
out.className = "btn btn-ghost";
out.textContent = `@${user.preferred_username} ⏏`;
out.onclick = onSignOut;
a.append(img, out);
} else {
const inBtn = document.createElement("button");
inBtn.className = "btn btn-ghost";
inBtn.textContent = "Sign in to like on HF";
inBtn.onclick = onSignIn;
a.append(inBtn);
}
}
const NAMED = {
indigo: "#4f46e5", green: "#16a34a", blue: "#2563eb", red: "#dc2626", yellow: "#eab308",
purple: "#9333ea", pink: "#db2777", orange: "#ea580c", gray: "#6b7280", teal: "#0d9488",
};
function cssColor(name) { return NAMED[name] || "#6b7280"; }
export function openDrawer(savedVms, { onOpenHere, onUnsave }) {
const d = $("drawer");
d.hidden = false;
d.innerHTML = `<div class="drawer-head">
<strong>Saved (${savedVms.length})</strong>
<button class="btn btn-ghost" id="drawer-close">✕</button></div>`;
$("drawer-close").onclick = () => (d.hidden = true);
if (!savedVms.length) {
d.insertAdjacentHTML("beforeend", `<p class="drawer-empty">Nothing saved yet. Tap 💾 on a project you like.</p>`);
return;
}
for (const vm of savedVms) {
const row = document.createElement("div");
row.className = "saved-row";
row.innerHTML = `
<span class="saved-thumb" style="background:linear-gradient(135deg,${cssColor(vm.colorFrom)},${cssColor(vm.colorTo)})">${vm.emoji}</span>
<span class="saved-meta">
<span class="saved-title">${vm.title}</span>
<span class="saved-sub">${vm.track || vm.sdk}</span>
</span>`;
row.onclick = () => onOpenHere(vm.id);
const un = document.createElement("button");
un.className = "btn btn-ghost";
un.textContent = "🗑";
un.onclick = (e) => { e.stopPropagation(); onUnsave(vm.id); row.remove(); };
row.append(un);
d.append(row);
}
}
export function showShortcuts() {
const o = $("overlay");
o.hidden = false;
o.innerHTML = `<div class="overlay-card">
<h3>Shortcuts</h3>
<ul class="keys">
<li><kbd>Space</kbd> / <kbd>→</kbd> Next</li>
<li><kbd>←</kbd> Prev</li>
<li><kbd>L</kbd> Like</li>
<li><kbd>S</kbd> Save</li>
<li><kbd>O</kbd> Open on HF</li>
<li><kbd>?</kbd> This help</li>
</ul>
<button class="btn btn-next" id="ov-close">Got it</button></div>`;
$("ov-close").onclick = () => (o.hidden = true);
o.onclick = (e) => { if (e.target === o) o.hidden = true; };
}