import { actionBarHTML } from "./layout"; import type { UserKind } from "../store"; export type ActorTag = "human" | "bot" | "system"; export function classifyActor(body: string, authorKind?: UserKind | null): ActorTag { const b = body ?? ""; if (b.startsWith("[system]")) return "system"; if (authorKind === "system") return "system"; if (authorKind === "bot") return "bot"; if (b.startsWith("[bot]")) return "bot"; return "human"; } export interface CommentView { id: number; tag: ActorTag; login: string; avatar: string; created_at: string; body_html: string; display_name?: string | null; reactions?: { e: string; n: number }[]; model?: string; } const TAG_LABEL: Record = { human: "๐Ÿ‘ค", bot: "๐Ÿค–", system: "โš™๏ธ" }; function esc(s: string): string { return (s ?? "") .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } export function relTime(iso: string): string { const t = Date.parse(iso); if (!Number.isFinite(t)) return ""; const d = (Date.now() - t) / 1000; if (d < 60) return "ๅˆšๅˆš"; if (d < 3600) return Math.floor(d / 60) + "ๅˆ†้’Ÿๅ‰"; if (d < 86400) return Math.floor(d / 3600) + "ๅฐๆ—ถๅ‰"; if (d < 86400 * 30) return Math.floor(d / 86400) + "ๅคฉๅ‰"; return new Date(t).toISOString().slice(0, 10); } // Must match app.js cardHTML so client hydration/polling produce identical markup. export function renderCommentCard(c: CommentView, cfg?: { translateUrl?: string; ttsBackends?: { url: string }[] }): string { const tag = c.tag || "human"; const label = TAG_LABEL[tag] || "๐Ÿ‘ค"; const rx = c.reactions && c.reactions.length ? `${c.reactions .map((r) => `${r.e}${r.n}`) .join("")}` : ""; const translateEnabled = cfg ? !!cfg.translateUrl && cfg.translateUrl.trim() !== "" : true; const ttsEnabled = cfg ? !!(cfg.ttsBackends && cfg.ttsBackends.some((b) => b.url && b.url.trim() !== "")) : true; return ( `
` + `
` + `${label} ${esc(tag)}` + `${esc(c.display_name || c.login)}` + (c.display_name ? `` : "") + `${relTime(c.created_at)}` + (c.model ? `${esc(c.model)}` : "") + rx + `` + actionBarHTML({ cid: String(c.id), copy: true, link: true, translate: true, tts: true, translateEnabled, ttsEnabled }) + `` + `
${c.body_html}
` ); }