oberflaeche: Seitenleiste mit zwei getrennten Bereichen KI-Box und Homelab

Statt der flachen Leiste oben (Start, Updates, Modelle, Homelab) steht links die Menuefuehrung: je Bereich ein
Block mit eigener Verbindungsanzeige und seinen Seiten, Updates mit Zahl. Das Homelab bekommt wie die KI-Box
ein Cockpit (Lage, Hinweise, Geraete) und eine Updates-Seite (/homelab/updates, offene Updates und Verlauf);
der Hinweis auf Box-Updates im Homelab faellt weg. Am Handy dieselbe Leiste als Schublade hinter dem
Menue-Knopf, oben Bereich und Seitentitel; die Leiste unten und das Mehr-Menue entfallen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-09-24 20:24:24 +02:00
co-authored by Claude Opus 5.5
parent a32f55645c
commit 6afec70640
7 changed files with 355 additions and 225 deletions
+76
View File
@@ -0,0 +1,76 @@
import { useRouterState } from "@tanstack/react-router"
import { Cpu, LayoutDashboard, type LucideIcon, RefreshCw } from "lucide-react"
import { useBoxZiele, useHomelab, useInstanz, usePartner } from "@/lib/abfragen"
import { offeneUpdates } from "@/lib/homelab"
import { useStromLage } from "@/lib/strom"
// Zwei Bereiche, sauber getrennt: die KI-Box (Box-Wart) und das Homelab (Proxmox-PC). Jeder hat seine
// eigenen Seiten und seine eigene Verbindungsanzeige; keine Seite zeigt etwas aus dem anderen Bereich.
export type Bereich = "box" | "homelab"
export const BEREICHE: { id: Bereich; name: string }[] = [
{ id: "box", name: "KI-Box" },
{ id: "homelab", name: "Homelab" },
]
export interface Seite {
to: "/" | "/updates" | "/modelle" | "/homelab" | "/homelab/updates"
label: string
Icon: LucideIcon
bereich: Bereich
/** Zeigt die Zahl offener Updates des Bereichs. */
zaehlt?: boolean
}
export const SEITEN: Seite[] = [
{ to: "/", label: "Cockpit", Icon: LayoutDashboard, bereich: "box" },
{ to: "/updates", label: "Updates", Icon: RefreshCw, bereich: "box", zaehlt: true },
{ to: "/modelle", label: "Modelle", Icon: Cpu, bereich: "box" },
{ to: "/homelab", label: "Cockpit", Icon: LayoutDashboard, bereich: "homelab" },
{ to: "/homelab/updates", label: "Updates", Icon: RefreshCw, bereich: "homelab", zaehlt: true },
]
export const bereichName = (b: Bereich) => BEREICHE.find((x) => x.id === b)?.name ?? b
/** Welche Seite gerade offen ist — für die Überschrift oben. */
export function useAktuelleSeite(): Seite {
const pfad = useRouterState({ select: (s) => s.location.pathname })
return SEITEN.find((s) => s.to === pfad) ?? SEITEN[0]
}
export type Verbindung = "online" | "verbinde" | "getrennt" | "fehlt"
export interface BereichStand {
verbindung: Verbindung
/** Updates, die per Knopf bereitstehen. */
updates: number
}
/**
* Verbindung und offene Updates je Bereich. Die Instanz, die die Seite ausliefert, meldet sich über den
* Live-Strom; die andere über die Partner-Prüfung (/api/partner).
*/
export function useBereichStand(): Record<Bereich, BereichStand> {
const instanz = useInstanz()
const partner = usePartner()
const strom = useStromLage()
const hier: Bereich = instanz.data?.rolle === "homelab" ? "homelab" : "box"
const eigen: Verbindung = strom === "live" ? "online" : strom
const p = partner.data
const fremd: Verbindung = !p ? "verbinde" : !p.eingerichtet ? "fehlt" : p.erreichbar ? "online" : "getrennt"
const verbindung: Record<Bereich, Verbindung> = hier === "box"
? { box: eigen, homelab: fremd }
: { box: fremd, homelab: eigen }
const box = useBoxZiele()
const homelab = useHomelab(verbindung.homelab === "online")
const boxUpdates = (box.data?.ziele ?? []).reduce(
(n, z) => n + z.bausteine.filter((b) => b.zustand === "neu" && b.aktion).length, 0,
)
const homelabUpdates = offeneUpdates(homelab.data?.ziele ?? []).filter((u) => u.baustein.aktion).length
return {
box: { verbindung: verbindung.box, updates: boxUpdates },
homelab: { verbindung: verbindung.homelab, updates: homelabUpdates },
}
}