Spaces:
Running
Running
| 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; }; | |
| } | |