feat: redesign dashboard messages UI with better sticker/image display and AI filtering

MessageCard:
- Add sticker image preview (renders actual sticker from URL, not just text name)
- Show attachment thumbnails inline (up to 4 with overflow counter)
- Remove dead columns (ai_policy_version, ai_evidence) from UI
- Add severity color coding (critical=red, high=orange, medium=yellow, low=blue)
- Add relative time display ('2h ago' instead of full datetime)
- Better hover effects and visual hierarchy

MessagesPanel:
- Add stats bar showing total/clean/warn/flagged/error/pending/deleted/edited counts
- Add AI status filter buttons (all, clean, warn, flagged, error, pending)
- Improve search UX with inline search icon and clear button
- Show filtered count in tab labels

ImageGrid:
- Include sticker images (was only attachments + embeds before)
- Add kind badge overlay (sticker/attachment/embed)
- Show user avatar next to image caption
- Better sticker rendering (object-contain with padding)

Header:
- Add shield icon per tab
- Improve tab titles and add descriptive subtitles

API client:
- Remove dead fields from MessageRecord (ai_moderation_raw, ai_policy_version, ai_evidence)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MythEclipse
2026-05-30 16:13:09 +07:00
co-authored by Claude Opus 4.8
parent a00a5a508f
commit c213300800
5 changed files with 347 additions and 121 deletions
+19 -5
View File
@@ -1,4 +1,4 @@
import { Wifi, WifiOff } from "lucide-react";
import { Wifi, WifiOff, Shield } from "lucide-react";
import type { WebSocketStatus } from "../../hooks/useDashboardSocket";
import type { DashboardTab } from "../../types/ui";
import type { VoiceStatus } from "../../types/voice";
@@ -7,12 +7,21 @@ import { Badge } from "../ui/badge";
const titles: Record<DashboardTab, string> = {
voice: "Voice Control",
media: "Media Player",
messages: "Messages",
messages: "Messages & Moderation",
recordings: "Voice Recordings",
analytics: "Analytics & Insights",
review: "Moderation Review",
};
const subtitles: Record<DashboardTab, string> = {
voice: "Join voice channels and stream audio.",
media: "Queue music, videos, and screen share.",
messages: "Capture, analyse, and moderate Discord messages.",
recordings: "Browse recorded voice segments.",
analytics: "Server moderation statistics and trends.",
review: "Review AI-flagged messages for moderation.",
};
interface HeaderProps {
activeTab: DashboardTab;
wsStatus: WebSocketStatus;
@@ -23,9 +32,14 @@ export function Header({ activeTab, wsStatus, voiceStatus }: HeaderProps) {
return (
<header className="sticky top-0 z-10 border-b border-border bg-background/80 px-4 py-4 backdrop-blur md:px-8">
<div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
<div>
<h1 className="text-2xl font-bold tracking-tight">{titles[activeTab]}</h1>
<p className="text-sm text-muted-foreground">Voice, media, and moderation in one dashboard.</p>
<div className="flex items-center gap-3">
<div className="flex h-9 w-9 items-center justify-center rounded-xl bg-primary/15 text-primary">
<Shield className="h-5 w-5" />
</div>
<div>
<h1 className="text-xl font-bold tracking-tight">{titles[activeTab]}</h1>
<p className="text-sm text-muted-foreground">{subtitles[activeTab]}</p>
</div>
</div>
<div className="flex flex-wrap gap-2">
<Badge variant={wsStatus === "connected" ? "success" : wsStatus === "error" ? "destructive" : "warning"}>