Files
mission-control-v2/frontend/src/components/cockpit/Lagekopf.tsx
T
HitonabiandClaude Opus 5.5 0d2687436e design v5: alle Seiten im neuen Look
- Gemeinsamer Lagekopf für beide Cockpits (Statusblock mit Schein, Kacheln mit
  Logo/Symbol und Zustandspunkt); KI-Box-Lampen als Dienst-Kacheln, Texte in
  normaler Schreibung. Alte Lampen-Komponente und Leuchtenfarben entfernt.
- Instrumente, Zählwerk, Checkliste, Flugplan, Radar-Kasten im neuen Stil;
  Instrumente ruhig in Indigo, Farbe für Zustände erst ab der Grenze.
- Übrige Seiten (Updates, Modelle, Nutzung, Suche, Monitoring, Dienste,
  Einstellungen, Protokoll, Dialoge): Glasflächen, feine Linien, Etiketten
  statt Instrumenten-Schild, Glas-Eingabefelder, deckende Dialoge.
- Dienste der KI-Box und Geräte im Monitoring mit Symbol bzw. Logo.
- Einstellungen: Karten mit Bereichs-Schein; Lizenzhinweis der Logos.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 15:46:35 +02:00

98 lines
4.3 KiB
TypeScript

import type { ReactNode } from "react"
import { cn } from "cn"
import { Geraetesymbol } from "@/components/cockpit/Geraetesymbol"
import type { Geraetebild, Punktzustand } from "@/lib/geraetebild"
import type { LampenZustand } from "@/lib/typen"
// Der Kopf beider Cockpits (Design v5, 25.09.2026): links der Statusblock mit Schein in der Farbe der Lage — drücken
// führt dorthin, wo etwas zu tun ist —, rechts die Kacheln der Geräte bzw. Dienste. Zustand immer auch in Worten.
export type Lageart = "ok" | "info" | "gelb" | "rot" | "stumm"
const ART: Record<Lageart, { block: string; glut: string; text: string }> = {
ok: { block: "bg-gruen/[0.07] ring-gruen/30", glut: "var(--gruen)", text: "text-gruen" },
info: { block: "bg-cyan/[0.07] ring-cyan/30", glut: "var(--cyan)", text: "text-cyan-text" },
gelb: { block: "bg-bernstein/[0.08] ring-bernstein/35", glut: "var(--bernstein)", text: "text-bernstein" },
rot: { block: "bg-rot/10 ring-rot/40", glut: "var(--rot)", text: "text-rot-text" },
stumm: { block: "bg-white/[0.04] ring-white/15", glut: "var(--text-3)", text: "text-text-2" },
}
export function Lagekopf({ art, oben, mitte, unten, aktiv, onAnsehen, label, children }: {
art: Lageart
oben: string
mitte: string
unten: string
aktiv: boolean
onAnsehen: () => void
/** Name des Abschnitts für Screenreader („Lage im Homelab“). */
label: string
/** Die Kacheln rechts (eine Liste von <li>). */
children: ReactNode
}) {
const a = ART[art]
return (
<section aria-label={label} className="auftauchen flaeche relative overflow-hidden rounded-3xl">
<div aria-hidden className="glut-atmet pointer-events-none absolute -top-40 -left-32 size-[460px] rounded-full"
style={{ background: `radial-gradient(closest-side, color-mix(in srgb, ${a.glut} 20%, transparent), transparent)` }} />
<div className="relative grid gap-4 p-4 sm:p-5 lg:grid-cols-[280px_minmax(0,1fr)] lg:gap-5">
<button
type="button"
onClick={onAnsehen}
disabled={!aktiv}
aria-label={`${oben}: ${mitte}`}
className={cn(
"flex min-h-[132px] flex-col items-start justify-center gap-1.5 rounded-2xl px-5 py-4 text-left ring-1 ring-inset transition-[filter]",
a.block, aktiv ? "cursor-pointer hover:brightness-125" : "cursor-default",
art === "gelb" && "lampe-atmet",
)}
>
<span className="etikett text-[11px] tracking-[0.18em] text-text-3">{oben}</span>
<span className={cn("text-[30px] leading-tight font-semibold tracking-[-0.01em] sm:text-[34px]", a.text)}>{mitte}</span>
<span className="text-[13.5px] text-text-2">{unten}</span>
</button>
<ul className="m-0 grid list-none grid-cols-1 gap-2 p-0 min-[480px]:grid-cols-2 xl:grid-cols-4">{children}</ul>
</div>
</section>
)
}
const LAMPE_PUNKT: Record<LampenZustand, Punktzustand> = { ok: "ok", aus: "aus", warn: "warn", info: "info", fehler: "rot" }
const WERT: Record<LampenZustand, string> = {
ok: "text-text-3", aus: "text-text-3", warn: "text-bernstein", info: "text-cyan-text", fehler: "text-rot-text",
}
const ZUSTAND_TEXT: Record<LampenZustand, string> = {
ok: "in Ordnung", aus: "aus", warn: "braucht Aufmerksamkeit", info: "Info", fehler: "Störung",
}
/** Eine Kachel im Lagekopf: Bild mit Zustandspunkt, Name, darunter der Wert in der Farbe des Zustands. */
export function Lagekachel({ bild, name, wert, zustand, onClick }: {
bild: Geraetebild
name: string
wert: string
zustand: LampenZustand
onClick?: () => void
}) {
const inhalt = (
<>
<Geraetesymbol bild={bild} punkt={LAMPE_PUNKT[zustand]} />
<span className="flex min-w-0 flex-col gap-0.5">
<span className="truncate text-[14.5px] leading-snug font-medium">{name}</span>
<span className={cn("truncate text-[12.5px] leading-snug", WERT[zustand])}>{wert}</span>
<span className="sr-only">{ZUSTAND_TEXT[zustand]}</span>
</span>
</>
)
const stil = "flaeche-innen flex h-full w-full min-w-0 items-center gap-3 rounded-xl px-3 py-2.5 text-left"
return (
<li>
{onClick ? (
<button type="button" onClick={onClick} className={cn(stil, "transition-colors hover:border-white/20 hover:bg-white/[0.05]")}>
{inhalt}
</button>
) : (
<div className={stil}>{inhalt}</div>
)}
</li>
)
}