fix(frontend): zirkuläre CSS-Variablen endgültig behoben - kein @theme-Namespace mehr
Vorheriger Fix (--mabea-* Zwischen-Variablen) hat den Zirkel nur eine Ebene verschoben statt aufgelöst: da @theme weiterhin --color-primary selbst neu definierte (höherer Layer als global.css), zeigte --mabea-primary auf --color-primary, welches wiederum auf --mabea-primary zeigte - derselbe Zirkel, nur indirekt. Coming from CSS-Spec: eine zirkuläre var()-Kette macht die Property zur "guaranteed-invalid value", unabhängig davon über wie viele Zwischenschritte sie läuft. Echter Fix: kein @theme-Mapping auf --color-* mehr, damit keine Namenskollision mit global.css überhaupt erst entstehen kann. Alle betroffenen Tailwind-Klassen (bg-primary, text-danger, border-l-warning, bg-surface-sunken, text-muted-foreground, ring-primary, etc.) auf Arbitrary-Value-Syntax umgestellt (z.B. bg-[var(--color-primary)]) - referenziert global.css-Variablen direkt, ohne je einen neuen Property-Namen im Theme-Layer zu belegen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
This commit is contained in:
@@ -216,7 +216,7 @@ export function DashboardPage() {
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold tracking-tight">Dashboard</h1>
|
||||
{zuletztAktualisiert && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<p className="text-xs text-[var(--color-text-muted)]">
|
||||
Aktualisiert um {zuletztAktualisiert.toLocaleTimeString("de-DE")}
|
||||
</p>
|
||||
)}
|
||||
@@ -252,17 +252,17 @@ export function DashboardPage() {
|
||||
{laedt && (
|
||||
<div className="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{Array.from({ length: 6 }).map((_, i) => (
|
||||
<div key={i} className="h-40 animate-pulse rounded-[14px] border border-border bg-surface-sunken" />
|
||||
<div key={i} className="h-40 animate-pulse rounded-[14px] border border-[var(--color-border)] bg-[var(--color-surface-sunken)]" />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{bearbeitenModus && layout.ausgeblendet.length > 0 && (
|
||||
<div className="mt-3 rounded-md border border-border bg-surface-sunken px-4 py-3 text-sm">
|
||||
<div className="mt-3 rounded-md border border-[var(--color-border)] bg-[var(--color-surface-sunken)] px-4 py-3 text-sm">
|
||||
Ausgeblendet:{" "}
|
||||
{layout.ausgeblendet.map((id, i) => (
|
||||
<span key={id}>
|
||||
{i > 0 && ", "}
|
||||
<button className="text-primary underline underline-offset-2" onClick={() => ausblendenUmschalten(id)}>
|
||||
<button className="text-[var(--color-primary)] underline underline-offset-2" onClick={() => ausblendenUmschalten(id)}>
|
||||
{TITEL[id]} wieder einblenden
|
||||
</button>
|
||||
</span>
|
||||
@@ -270,7 +270,7 @@ export function DashboardPage() {
|
||||
</div>
|
||||
)}
|
||||
{bearbeitenModus && (
|
||||
<p className="mt-2 text-xs text-muted-foreground">
|
||||
<p className="mt-2 text-xs text-[var(--color-text-muted)]">
|
||||
Kachel ziehen zum Verschieben, an der unteren rechten Ecke ziehen zum Vergrößern/Verkleinern.
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -7,9 +7,9 @@ import { cn } from "../../lib/utils";
|
||||
export type TileAkzent = "neutral" | "warning" | "danger";
|
||||
|
||||
const AKZENT_KLASSE: Record<TileAkzent, string> = {
|
||||
neutral: "border-l-border",
|
||||
warning: "border-l-warning",
|
||||
danger: "border-l-danger",
|
||||
neutral: "border-l-[var(--color-border)]",
|
||||
warning: "border-l-[var(--color-warning)]",
|
||||
danger: "border-l-[var(--color-danger)]",
|
||||
};
|
||||
|
||||
interface Props extends HTMLAttributes<HTMLDivElement> {
|
||||
|
||||
@@ -14,7 +14,7 @@ function AblaufdatenTileKomponente({ ablaufdaten }: Props) {
|
||||
const [alleAnzeigen, setAlleAnzeigen] = useState(false);
|
||||
|
||||
if (ablaufdaten.length === 0) {
|
||||
return <p className="text-sm text-muted-foreground">Keine bald ablaufenden Chargen.</p>;
|
||||
return <p className="text-sm text-[var(--color-text-muted)]">Keine bald ablaufenden Chargen.</p>;
|
||||
}
|
||||
|
||||
const sichtbare = alleAnzeigen ? ablaufdaten : ablaufdaten.slice(0, ANZAHL_OHNE_AUFKLAPPEN);
|
||||
@@ -25,14 +25,14 @@ function AblaufdatenTileKomponente({ ablaufdaten }: Props) {
|
||||
{sichtbare.map((a) => (
|
||||
<li
|
||||
key={`${a.objekt_id}-${a.material_id}`}
|
||||
className="flex items-center gap-3 border-b border-border py-2 last:border-0"
|
||||
className="flex items-center gap-3 border-b border-[var(--color-border)] py-2 last:border-0"
|
||||
>
|
||||
<InventoryStatus status={a.status} />
|
||||
<div className="min-w-0 flex-1">
|
||||
<Link to={`/akte/objekt/${a.objekt_id}`} className="block truncate font-medium">
|
||||
{a.objekt_name} – {a.material_name}
|
||||
</Link>
|
||||
<span className="text-xs text-muted-foreground">{a.ablaufdatum}</span>
|
||||
<span className="text-xs text-[var(--color-text-muted)]">{a.ablaufdatum}</span>
|
||||
</div>
|
||||
<span className="shrink-0 tabular-nums text-sm font-semibold">{a.verbleibende_tage} Tage</span>
|
||||
</li>
|
||||
@@ -40,7 +40,7 @@ function AblaufdatenTileKomponente({ ablaufdaten }: Props) {
|
||||
</ul>
|
||||
{ablaufdaten.length > ANZAHL_OHNE_AUFKLAPPEN && (
|
||||
<button
|
||||
className="mt-2 text-sm font-medium text-primary underline-offset-2 hover:underline"
|
||||
className="mt-2 text-sm font-medium text-[var(--color-primary)] underline-offset-2 hover:underline"
|
||||
onClick={() => setAlleAnzeigen(!alleAnzeigen)}
|
||||
>
|
||||
{alleAnzeigen ? "Weniger anzeigen" : `Alle anzeigen (${ablaufdaten.length})`}
|
||||
|
||||
@@ -39,10 +39,10 @@ function EinsatzbereitschaftTileKomponente({ bereitschaft }: Props) {
|
||||
<>
|
||||
<p className="leading-none">
|
||||
<span className="text-4xl font-bold tabular-nums">{bereitschaft.einsatzbereit}</span>
|
||||
<span className="text-sm font-semibold text-muted-foreground">/{bereitschaft.gesamt} einsatzbereit</span>
|
||||
<span className="text-sm font-semibold text-[var(--color-text-muted)]">/{bereitschaft.gesamt} einsatzbereit</span>
|
||||
</p>
|
||||
|
||||
<div className="mt-3 flex h-2.5 w-full overflow-hidden rounded-full bg-surface-sunken">
|
||||
<div className="mt-3 flex h-2.5 w-full overflow-hidden rounded-full bg-[var(--color-surface-sunken)]">
|
||||
{segmente.map(
|
||||
(s) =>
|
||||
s.anzahl > 0 && (
|
||||
@@ -59,14 +59,14 @@ function EinsatzbereitschaftTileKomponente({ bereitschaft }: Props) {
|
||||
{segmente.map((s) => (
|
||||
<div key={s.label} className="flex items-center gap-1.5 text-sm">
|
||||
<span className="h-2 w-2 shrink-0 rounded-full" style={{ backgroundColor: s.farbVar }} />
|
||||
<span className="text-muted-foreground">{s.label}</span>
|
||||
<span className="text-[var(--color-text-muted)]">{s.label}</span>
|
||||
<span className="ml-auto font-semibold tabular-nums">{s.anzahl}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{bereitschaft.nie_kontrolliert_gesamt > bereitschaft.unbekannt && (
|
||||
<p className="mt-3 text-xs text-muted-foreground">
|
||||
<p className="mt-3 text-xs text-[var(--color-text-muted)]">
|
||||
Davon {bereitschaft.nie_kontrolliert_gesamt} insgesamt noch nie kontrolliert (auch bei Objekten mit weiteren
|
||||
Problemen).
|
||||
</p>
|
||||
@@ -75,7 +75,7 @@ function EinsatzbereitschaftTileKomponente({ bereitschaft }: Props) {
|
||||
{bereitschaft.details.length > 0 && (
|
||||
<>
|
||||
<button
|
||||
className="mt-3 text-sm font-medium text-primary underline-offset-2 hover:underline"
|
||||
className="mt-3 text-sm font-medium text-[var(--color-primary)] underline-offset-2 hover:underline"
|
||||
onClick={() => setDetailsOffen(!detailsOffen)}
|
||||
>
|
||||
{detailsOffen ? "Details ausblenden" : "Details anzeigen"}
|
||||
@@ -83,13 +83,13 @@ function EinsatzbereitschaftTileKomponente({ bereitschaft }: Props) {
|
||||
{detailsOffen && (
|
||||
<ul className="mt-2">
|
||||
{bereitschaft.details.map((d) => (
|
||||
<li key={d.objekt_id} className="flex items-center justify-between gap-2 border-b border-border py-2 last:border-0">
|
||||
<li key={d.objekt_id} className="flex items-center justify-between gap-2 border-b border-[var(--color-border)] py-2 last:border-0">
|
||||
<Link to={`/objekte/${d.objekt_id}/kontrolle`} className="truncate font-medium">
|
||||
{d.name} ({d.code})
|
||||
</Link>
|
||||
<span className="flex shrink-0 items-center gap-2">
|
||||
<ReadinessBadge status={readinessVonGruenden(d.gruende)} />
|
||||
<span className="hidden text-xs text-muted-foreground sm:inline">
|
||||
<span className="hidden text-xs text-[var(--color-text-muted)] sm:inline">
|
||||
{d.gruende.map((g) => GRUND_TEXT[g] ?? g).join(", ")}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -10,7 +10,7 @@ function KennzahlenTileKomponente({ kennzahlen }: Props) {
|
||||
return (
|
||||
<div>
|
||||
<p className="text-4xl font-bold tabular-nums leading-none">{kennzahlen.anzahl_offener_fehlbestaende}</p>
|
||||
<p className="mb-3 text-xs uppercase tracking-wide text-muted-foreground">Offene Fehlbestände</p>
|
||||
<p className="mb-3 text-xs uppercase tracking-wide text-[var(--color-text-muted)]">Offene Fehlbestände</p>
|
||||
<ul className="card-list">
|
||||
<li style={{ padding: "0.3rem 0" }}>Genehmigte Mindermengen: {kennzahlen.anzahl_genehmigter_mindermengen}</li>
|
||||
<li style={{ padding: "0.3rem 0" }}>
|
||||
|
||||
@@ -16,12 +16,12 @@ function MaengelTileKomponente({ maengel, maengelNeuAnzahl, maengelKritischAnzah
|
||||
return (
|
||||
<>
|
||||
<p className="text-4xl font-bold tabular-nums leading-none">{maengelOffenListe.length}</p>
|
||||
<p className="mb-2 text-xs uppercase tracking-wide text-muted-foreground">Offen</p>
|
||||
<p className="mb-2 text-xs uppercase tracking-wide text-[var(--color-text-muted)]">Offen</p>
|
||||
{maengelNeuAnzahl > 0 && (
|
||||
<p className="font-semibold text-warning">{maengelNeuAnzahl} neu gemeldet</p>
|
||||
<p className="font-semibold text-[var(--color-warning)]">{maengelNeuAnzahl} neu gemeldet</p>
|
||||
)}
|
||||
{maengelKritischAnzahl > 0 && (
|
||||
<p className="text-danger">{maengelKritischAnzahl} kritisch (blockiert Einsatzbereitschaft)</p>
|
||||
<p className="text-[var(--color-danger)]">{maengelKritischAnzahl} kritisch (blockiert Einsatzbereitschaft)</p>
|
||||
)}
|
||||
{maengelOffenListe.length > 0 && (
|
||||
<>
|
||||
|
||||
@@ -14,7 +14,7 @@ function PrueftermineTileKomponente({ prueftermine }: Props) {
|
||||
const [alleAnzeigen, setAlleAnzeigen] = useState(false);
|
||||
|
||||
if (prueftermine.length === 0) {
|
||||
return <p className="text-sm text-muted-foreground">Keine anstehenden oder überfälligen Geräteprüfungen.</p>;
|
||||
return <p className="text-sm text-[var(--color-text-muted)]">Keine anstehenden oder überfälligen Geräteprüfungen.</p>;
|
||||
}
|
||||
|
||||
const sichtbare = alleAnzeigen ? prueftermine : prueftermine.slice(0, ANZAHL_OHNE_AUFKLAPPEN);
|
||||
@@ -25,14 +25,14 @@ function PrueftermineTileKomponente({ prueftermine }: Props) {
|
||||
{sichtbare.map((p) => (
|
||||
<li
|
||||
key={`${p.typ}-${p.objekt_id}-${p.faelligkeitsdatum}`}
|
||||
className="flex items-center gap-3 border-b border-border py-2 last:border-0"
|
||||
className="flex items-center gap-3 border-b border-[var(--color-border)] py-2 last:border-0"
|
||||
>
|
||||
<InspectionStatus status={p.status} />
|
||||
<div className="min-w-0 flex-1">
|
||||
<Link to={`/akte/objekt/${p.objekt_id}`} className="block truncate font-medium">
|
||||
{p.bezeichnung}
|
||||
</Link>
|
||||
<span className="text-xs text-muted-foreground">{p.faelligkeitsdatum}</span>
|
||||
<span className="text-xs text-[var(--color-text-muted)]">{p.faelligkeitsdatum}</span>
|
||||
</div>
|
||||
<span className="shrink-0 tabular-nums text-sm font-semibold">{p.verbleibende_tage} Tage</span>
|
||||
</li>
|
||||
@@ -40,7 +40,7 @@ function PrueftermineTileKomponente({ prueftermine }: Props) {
|
||||
</ul>
|
||||
{prueftermine.length > ANZAHL_OHNE_AUFKLAPPEN && (
|
||||
<button
|
||||
className="mt-2 text-sm font-medium text-primary underline-offset-2 hover:underline"
|
||||
className="mt-2 text-sm font-medium text-[var(--color-primary)] underline-offset-2 hover:underline"
|
||||
onClick={() => setAlleAnzeigen(!alleAnzeigen)}
|
||||
>
|
||||
{alleAnzeigen ? "Weniger anzeigen" : `Alle anzeigen (${prueftermine.length})`}
|
||||
|
||||
@@ -13,7 +13,7 @@ function QualifikationTileKomponente({ qualifikationsablaeufe }: Props) {
|
||||
const [alleAnzeigen, setAlleAnzeigen] = useState(false);
|
||||
|
||||
if (qualifikationsablaeufe.length === 0) {
|
||||
return <p className="text-sm text-muted-foreground">Keine bald ablaufenden Qualifikationen.</p>;
|
||||
return <p className="text-sm text-[var(--color-text-muted)]">Keine bald ablaufenden Qualifikationen.</p>;
|
||||
}
|
||||
|
||||
const sichtbare = alleAnzeigen ? qualifikationsablaeufe : qualifikationsablaeufe.slice(0, ANZAHL_OHNE_AUFKLAPPEN);
|
||||
@@ -22,11 +22,11 @@ function QualifikationTileKomponente({ qualifikationsablaeufe }: Props) {
|
||||
<>
|
||||
<ul>
|
||||
{sichtbare.map((q) => (
|
||||
<li key={q.benutzer_qualifikation_id} className="flex items-center gap-3 border-b border-border py-2 last:border-0">
|
||||
<li key={q.benutzer_qualifikation_id} className="flex items-center gap-3 border-b border-[var(--color-border)] py-2 last:border-0">
|
||||
<FristBadge status={q.status} />
|
||||
<div className="min-w-0 flex-1">
|
||||
<span className="block truncate font-medium">{q.benutzer_name}</span>
|
||||
<span className="text-xs text-muted-foreground">{q.qualifikationstyp_name}</span>
|
||||
<span className="text-xs text-[var(--color-text-muted)]">{q.qualifikationstyp_name}</span>
|
||||
</div>
|
||||
<span className="shrink-0 tabular-nums text-sm font-semibold">{q.verbleibende_tage} Tage</span>
|
||||
</li>
|
||||
@@ -34,7 +34,7 @@ function QualifikationTileKomponente({ qualifikationsablaeufe }: Props) {
|
||||
</ul>
|
||||
{qualifikationsablaeufe.length > ANZAHL_OHNE_AUFKLAPPEN && (
|
||||
<button
|
||||
className="mt-2 text-sm font-medium text-primary underline-offset-2 hover:underline"
|
||||
className="mt-2 text-sm font-medium text-[var(--color-primary)] underline-offset-2 hover:underline"
|
||||
onClick={() => setAlleAnzeigen(!alleAnzeigen)}
|
||||
>
|
||||
{alleAnzeigen ? "Weniger anzeigen" : `Alle anzeigen (${qualifikationsablaeufe.length})`}
|
||||
|
||||
Reference in New Issue
Block a user