feat: migrate frontend to Astro + expand AI moderation + backend admin/runtime config
Frontend: - migrate from Vite to Astro (astro.config.mjs, pages/, layouts/) - add admin panel, settings page, command palette, error boundary - refactor App.tsx, MascotChatbot, Sidebar, Header, DashboardLayout - update API client, WebSocket, auth, dashboard features Backend: - add admin module and config routes - refactor middlewares, Redis connection, WebSocket server/bridge - add runtime config loader Discord Gateway: - refactor AI moderation: circuit breaker, concurrency limiter, fallback processor - add media analysis client, Seaxng search, user profile learner - add new drizzle migration Shared: - extend database schema, add new config fields
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import { motion } from "framer-motion";
|
||||
import { Wifi, WifiOff } from "lucide-react";
|
||||
import { Moon, Sun, Wifi, WifiOff } from "lucide-react";
|
||||
import type { DashboardTab } from "../entities/ui/types.js";
|
||||
import type { VoiceStatus } from "../entities/voice/types.js";
|
||||
import type { ThemeMode } from "../hooks/useTheme";
|
||||
import { fadeSlideUp } from "../shared/hooks/useFramerStagger";
|
||||
import { cn } from "../shared/lib/utils";
|
||||
import { Badge } from "../shared/ui";
|
||||
@@ -11,18 +12,23 @@ const titles: Record<DashboardTab, string> = {
|
||||
messages: "Messages & Moderation",
|
||||
live: "Voice & Media",
|
||||
dashboard: "Dashboard",
|
||||
settings: "Admin Settings",
|
||||
};
|
||||
|
||||
const subtitles: Record<DashboardTab, string> = {
|
||||
messages: "Capture, analyse, and moderate Discord messages.",
|
||||
live: "Join voice channels, play media, stream audio, and browse recordings.",
|
||||
dashboard: "Server statistics, user profiles, and AI moderation overview.",
|
||||
settings: "Manage dashboard visibility, runtime configuration, and authentication.",
|
||||
};
|
||||
|
||||
interface HeaderProps {
|
||||
activeTab: DashboardTab;
|
||||
wsStatus: WsStatus;
|
||||
voiceStatus: VoiceStatus;
|
||||
themeMode: ThemeMode;
|
||||
isDark: boolean;
|
||||
onThemeToggle: () => void;
|
||||
}
|
||||
|
||||
/** Dot indicator colour for WS badge */
|
||||
@@ -63,7 +69,7 @@ function VoiceIndicator({ voiceStatus }: { voiceStatus: VoiceStatus }) {
|
||||
);
|
||||
}
|
||||
|
||||
export function Header({ activeTab, wsStatus, voiceStatus }: HeaderProps) {
|
||||
export function Header({ activeTab, wsStatus, voiceStatus, themeMode, isDark, onThemeToggle }: HeaderProps) {
|
||||
return (
|
||||
<header className="sticky top-0 z-10 border-b border-border/50 bg-background/70 px-4 py-4 backdrop-blur-sm md:px-8">
|
||||
<div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
||||
@@ -92,8 +98,22 @@ export function Header({ activeTab, wsStatus, voiceStatus }: HeaderProps) {
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
{/* Right: status badges */}
|
||||
{/* Right: status badges + theme toggle */}
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{/* Theme toggle */}
|
||||
<button
|
||||
onClick={onThemeToggle}
|
||||
className="flex items-center gap-1.5 rounded-lg border border-border bg-card/50 px-3 py-1.5 text-xs text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors"
|
||||
title={`Switch to ${isDark ? "light" : "dark"} mode`}
|
||||
>
|
||||
{isDark ? (
|
||||
<Sun className="h-3.5 w-3.5 text-amber-400" />
|
||||
) : (
|
||||
<Moon className="h-3.5 w-3.5 text-indigo-400" />
|
||||
)}
|
||||
<span className="hidden sm:inline">{isDark ? "Light" : "Dark"}</span>
|
||||
</button>
|
||||
|
||||
{/* WS Badge */}
|
||||
<Badge
|
||||
variant="outline"
|
||||
|
||||
Reference in New Issue
Block a user