feat(frontend): polish remaining views + centralize time/status helpers

- Add formatDuration + formatRelativeTime to lib/format.ts and aiTone to
  lib/ai-status.ts; dedupe duplicated helpers in messages/analysis views.
- Recordings: upload-status badge (pending/processing/failed), channel chip,
  relative time, hover lift, surface upload errors.
- Media: mode pill + duration on now-playing, volume meter, per-track duration
  and queue total in header.
- Moderation: relative timestamps in action rows + executor hint.
- Analysis & Dashboard: rank bars for top reactors for scannable comparison.
This commit is contained in:
asepharyana committed 2026-08-18 09:05:12 +07:00
1 parent 6bd6ddcdca
commit ff8a9c50ae
8 files changed
+250 -142

No files matched your search

@@ -29,7 +29,7 @@ import {
SectionHeader,
} from "@/components/shared";
import { useModerationActions, useModerationStats } from "@/hooks";
import { formatNumber } from "@/lib/format";
import { formatNumber, formatRelativeTime } from "@/lib/format";
import type {
ModerationAction,
ModerationActionType,
@@ -247,12 +247,18 @@ function ActionRow({ a }: { a: ModerationAction }) {
</span>
<Badge tone={tone}>{a.status}</Badge>
<span className="mono ml-auto text-[0.6rem] text-ink-faint">
{a.created_at ? new Date(a.created_at).toLocaleString() : "—"}
{formatRelativeTime(a.created_at)}
</span>
</div>
{a.reason && (
<div className="mt-0.5 text-xs text-ink-soft">“{a.reason}”</div>
)}
{a.executed_by && (
<div className="mono mt-0.5 text-[0.6rem] text-ink-faint">
by {a.executed_by}
{a.executed_at ? ` · ${formatRelativeTime(a.executed_at)}` : ""}
</div>
)}
{a.content && (
<div className="mt-1 line-clamp-2 rounded-[8px] bg-white/[0.03] px-2 py-1 text-xs text-ink-faint">
{a.content}