feat: complete UI/UX Rework into Sleek Glassmorphic AI OS (June 2026)

This commit is contained in:
Hitonabi
2026-06-25 22:18:51 +02:00
parent e1da5c797d
commit 6a8e55cc43
18 changed files with 2362 additions and 787 deletions
+95 -37
View File
@@ -1,20 +1,31 @@
import { useEffect, useState } from "react"
import { ExternalLink } from "lucide-react"
import { Bot, ExternalLink, Activity, Cpu, Wrench, Shield } from "lucide-react"
import { api, type AgentStatus } from "@/lib/api"
import { cn } from "@/lib/utils"
function Dot({ ok }: { ok: boolean }) {
return <span className={cn("h-2 w-2 rounded-full", ok ? "bg-emerald-500" : "bg-amber-500")} />
}
function Tile({ label, ok, detail }: { label: string; ok: boolean; detail?: string }) {
function Tile({ label, ok, detail, icon: Icon }: { label: string; ok: boolean; detail?: string; icon: any }) {
return (
<div className="rounded-lg border border-border bg-card p-4">
<div className="flex items-center gap-2">
<Dot ok={ok} />
<span className="text-sm font-medium">{label}</span>
<div className={cn(
"rounded-2xl border bg-card/45 backdrop-blur-md p-5 shadow-lg shadow-black/10 flex flex-col justify-between gap-3 hover:border-primary/40 transition-all duration-300",
ok ? "border-border/60" : "border-amber-500/30"
)}>
<div className="flex items-center justify-between">
<span className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground">{label}</span>
<Icon className={cn("h-4.5 w-4.5", ok ? "text-primary" : "text-amber-500")} />
</div>
<div className="space-y-1.5">
<div className="flex items-center gap-2">
<span className={cn(
"h-2 w-2 rounded-full ring-2 ring-black/40",
ok ? "bg-emerald-500 animate-pulse" : "bg-amber-500"
)} />
<span className="text-xs font-semibold text-foreground">
{ok ? "Bereit / Online" : "Offline / Inaktiv"}
</span>
</div>
{detail && <div className="text-[10px] font-mono text-muted-foreground truncate max-w-[200px]" title={detail}>{detail}</div>}
</div>
{detail && <div className="mt-1 text-xs text-muted-foreground">{detail}</div>}
</div>
)
}
@@ -26,60 +37,107 @@ export function AgentView() {
useEffect(() => {
const load = () => api<AgentStatus>("/api/agent/status").then(setS).catch((e) => setError(String(e)))
load()
const t = setInterval(load, 8000)
const t = setInterval(load, 5000)
return () => clearInterval(t)
}, [])
return (
<div className="space-y-4">
<div className="flex items-start justify-between">
<div className="space-y-6">
{/* Header */}
<div className="flex flex-col sm:flex-row justify-between sm:items-center gap-4">
<div>
<h1 className="text-xl font-semibold">Hermes</h1>
<h1 className="text-2xl font-space font-bold tracking-tight bg-gradient-to-r from-foreground via-foreground to-primary bg-clip-text text-transparent">
Hermes Agenten-Cockpit
</h1>
<p className="text-sm text-muted-foreground">
Der autonome Agent läuft eigenständig (Gateway :8642) und hat seine eigene Oberfläche
(hermes-webui :8787). Mission Control verlinkt nur Chat &amp; Steuerung leben dort.
Hermes ist ein autonomer Agent, der im Hintergrund der Box läuft (Port <code>:8642</code>) und seine eigene UI besitzt.
</p>
</div>
{s?.webui_url && (
<a
href={s.webui_url}
target="_blank"
rel="noopener"
className={cn(
"flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium",
"flex h-9 px-4 items-center gap-1.5 text-xs font-semibold rounded-lg transition-all cursor-pointer shadow-md shrink-0 self-start",
s.webui_reachable
? "bg-primary text-primary-foreground hover:opacity-90"
: "border border-border text-muted-foreground",
? "bg-primary text-primary-foreground hover:opacity-90 shadow-primary/10"
: "border border-border/60 text-muted-foreground bg-background/20"
)}
>
<ExternalLink className="h-4 w-4" /> Hermes öffnen
<ExternalLink className="h-4 w-4" />
<span>Hermes WebUI öffnen</span>
</a>
)}
</div>
{error && <div className="text-sm text-muted-foreground">Status nicht lesbar ({error}).</div>}
{error && (
<div className="rounded-xl border border-red-500/20 bg-red-500/5 p-4 text-xs text-red-400 font-mono">
Status nicht lesbar ({error}).
</div>
)}
{s && (
<>
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
<Tile label="Gateway (:8642)" ok={s.gateway_reachable} detail={s.gateway_reachable ? "erreichbar" : "offline"} />
<Tile label="WebUI (:8787)" ok={s.webui_reachable} detail={s.webui_reachable ? "erreichbar" : "offline"} />
<Tile label="Brain" ok={s.gateway_reachable} detail={`model: ${s.brain_model || "auto"}`} />
<Tile label="Verdrahtung" ok={s.has_config} detail={`config ${s.has_config ? "✓" : "—"} · skills ${s.has_skills ? "✓" : "—"} · memories ${s.has_memories ? "✓" : "—"}`} />
<div className="space-y-6">
{/* Tile Grid */}
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
<Tile
label="Agent Gateway"
ok={s.gateway_reachable}
detail="Port :8642 (REST API)"
icon={Bot}
/>
<Tile
label="Agent WebUI"
ok={s.webui_reachable}
detail="Port :8787 (Chat UI)"
icon={Activity}
/>
<Tile
label="Aktives Gehirn"
ok={s.gateway_reachable}
detail={s.brain_model ? `Model: ${s.brain_model}` : "Model: auto"}
icon={Cpu}
/>
<Tile
label="Verdrahtung"
ok={s.has_config}
detail={`Config: ${s.has_config ? "✓" : "—"} · Skills: ${s.has_skills ? "✓" : "—"} · Memory: ${s.has_memories ? "✓" : "—"}`}
icon={Wrench}
/>
</div>
{/* Diagnostic Details if Offline */}
{!s.gateway_reachable && (
<div className="rounded-xl border border-dashed border-border bg-card/50 p-5 text-sm">
<div className="mb-2 font-medium">Hermes ist (hier) offline</div>
<p className="text-muted-foreground">
Der Agent + hermes-webui laufen auf der Box. Einrichtung & volle Verdrahtung
(Brain = <code>model: auto</code>, Tools/MCP inkl. <code>mcp_mc</code> + <code>mcp_memory</code>,
SSHWindows, lokale Browser-/Such-MCP) sind im Runbook beschrieben:
<code className="ml-1">docs/HERMES_SETUP.md</code>.
</p>
<div className="rounded-2xl border border-border/60 bg-card/45 backdrop-blur-md p-6 space-y-4 shadow-lg shadow-black/10">
<div className="flex items-center gap-2">
<Shield className="h-5 w-5 text-amber-500" />
<h3 className="text-sm font-bold uppercase tracking-wider text-foreground">Hermes-Agent Diagnostics</h3>
</div>
<div className="text-xs text-muted-foreground space-y-3 leading-relaxed">
<p>
Der Hermes-Dienst ist auf der Box derzeit offline oder kann sich nicht mit dem lokalen llama-swap verbinden.
</p>
<p>
Stelle sicher, dass die systemd-Dienste auf der Box laufen. Du kannst den Status im <strong>OS &amp; Updates Drawer</strong> prüfen und die Dienste bei Bedarf neu starten.
</p>
<div className="p-3.5 bg-background/25 rounded-xl border border-border/30 font-mono text-[10px] space-y-1">
<div className="text-muted-foreground/60"># Dienste manuell auf der Box prüfen:</div>
<div className="text-primary">systemctl --user status hermes-gateway</div>
<div className="text-primary">systemctl --user status hermes-webui</div>
</div>
<p>
Weitere Einrichtungsdetails (Brain-Konfiguration, MCP-Kopplungen, SSH-Tunneling und Such-Engines) findest du in der Dokumentationsdatei:
<code className="ml-1 px-1.5 py-0.5 rounded bg-muted/40 text-foreground border border-border/30">docs/HERMES_SETUP.md</code>.
</p>
</div>
</div>
)}
</>
</div>
)}
</div>
)