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 (
``
);
}