import { coverUrl, escapeAttr, escapeHtml, formatCount, formatDate, formatDelta, formatDuration, formatPercent, metricLabel, statusLabel, } from "./format.js"; export function cover(item, className = "thumb") { const url = coverUrl(item.cover); const title = escapeAttr(item.title || "视频封面"); if (!url) { return ``; } return `
${title}
`; } export function rankBadge(rank) { if (!rank) return ""; const top = rank <= 3 ? ` rank-${rank}` : ""; return `${rank}`; } export function videoCard(item, { rank = null, primary = "view", showStatus = false } = {}) { const metrics = item.metrics || {}; const primaryValue = metrics[primary]; const growth = item.growth; const delta = growth?.available ? growth.delta : null; const title = escapeHtml(item.title || "(无标题)"); const up = escapeHtml(item.up_name || "未知 UP"); const upMid = item.up_mid; // 卡片本身已经是 ,这里不能再嵌套链接,否则 HTML 解析会截断卡片。 const upLink = upMid ? `${up}` : up; const status = showStatus && item.status ? `${escapeHtml(statusLabel(item.status))}` : ""; return ` ${rankBadge(rank)} ${cover(item, "video-thumb")}

${title}

${upLink} ${escapeHtml(formatDate(item.pubdate))} ${escapeHtml(formatDuration(item.duration))} ${status}
${formatCount(primaryValue)}${escapeHtml(metricLabel(primary))} ${delta !== null ? `${formatDelta(delta)}` : ""} 赞 ${formatCount(metrics.like)} 币 ${formatCount(metrics.coin)} 藏 ${formatCount(metrics.favorite)} 互动 ${formatPercent(item.interaction_rate)}
`; } export function upCard(item, { rank = null } = {}) { const best = item.best_video || {}; const displayCover = cover( { title: best.title || item.up_name, cover: best.cover }, "video-thumb up-thumb", ); return ` ${rankBadge(rank)} ${displayCover}

${escapeHtml(item.up_name || `UP ${item.up_mid}`)}

${formatNumber(item.video_count)} 条视频 均播 ${formatCount(item.avg_views)}
${formatCount(item.total_views)}总播放 总互动 ${formatCount(item.total_interactions)} 均互动 ${formatPercent(item.avg_interaction)}
`; } export function metricGrid(item) { const metrics = item.metrics || {}; const growth = item.growth; return `
${["view", "like", "coin", "favorite", "share", "reply", "danmaku"].map((metric) => { const extra = metric === "view" && growth?.available ? `${formatDelta(growth.delta)}` : ""; return `
${escapeHtml(metricLabel(metric))} ${formatCount(metrics[metric])}${extra}
`; }).join("")}
`; } export function sectionHeader(title, extra = "") { return `

${escapeHtml(title)}

${extra}
`; } export function emptyState(title, message = "", action = "") { return `
${escapeHtml(title)} ${message ? `

${escapeHtml(message)}

` : ""}${action}
`; } export function badge(text, kind = "subtle") { return `${escapeHtml(text)}`; } export function chip(label, active, data, value = "") { return ``; } export function formatNumber(value) { return value === null || value === undefined ? "—" : Number(value).toLocaleString("zh-CN"); } export function metricChips(metrics, active, dataName = "metric") { return metrics.map((metric) => chip( metricLabel(metric), metric === active, dataName, metric, )).join(""); } export function centerActiveChips(root) { root.querySelectorAll(".chip-row.scroll-x").forEach((row) => { const active = row.querySelector(".chip.active"); if (!active) return; const target = active.offsetLeft - row.clientWidth / 2 + active.clientWidth / 2; row.scrollLeft = Math.max(0, target); }); } export function pager(page, pages) { if (!pages || pages <= 1) return ""; return `
第 ${page} / ${pages} 页
`; }