File size: 3,471 Bytes
9de795a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/** Farb-System für generische Eigen-Objekte (Kurator-Pipeline v3, Welle 3).
 *
 * EINE Quelle für die wählbaren Farben ist das Schema-Enum
 * `katalog-item.schema.json#/$defs/farbSlug` (16 kuratierte Interieur-Farben);
 * `FarbSlug` kommt aus den generierten Typen. Hier liegt nur die **Client-Optik**
 * (Slug → Hex) und die reine Auflösungslogik MANUELL > KI > Default – analog zu
 * `MATERIAL_LOOK` (Flächen) und `MATERIAL_FARBE` (Möbel-Basisfarbe). Die
 * Erdung/Validierung (Slug ∈ farbVarianten) passiert im Kurator (Python); hier
 * wird nichts geprüft, nur dargestellt.
 *
 * Die Schema↔Map-Deckung ist per Test abgesichert (`farben.test.ts`): sind neue
 * Slugs im Schema, fehlt hier ein Hex → der Test schlägt an (Drift-Schutz).
 */
import type { katalogItem } from "@fp/shared/generated";

export type FarbSlug = katalogItem.FarbSlug;

/**
 * Slug → Hex. Die Töne sind fürs Rendering fein abgestimmt (matte Interieur-
 * Farben, nicht knallig). `Record<FarbSlug, string>` erzwingt zur Compile-Zeit,
 * dass jeder Schema-Slug einen Hex hat; der Laufzeit-Test prüft die Gegenrichtung.
 */
export const FARBSLUG_HEX: Record<FarbSlug, string> = {
  // Neutraltöne
  weiss: "#f4f4f2",
  creme: "#ece5d8",
  sand: "#d9c9a8",
  beige: "#cbb99a",
  taupe: "#a89a8c",
  hellgrau: "#c9c9c6",
  warmgrau: "#b3aca4",
  anthrazit: "#3f4145",
  schwarz: "#232323",
  // Hölzer – hell nach dunkel
  "esche-hell": "#ddc9a3",
  "eiche-hell": "#c9a76c",
  "eiche-natur": "#a8834f",
  buche: "#c8a882",
  nussbaum: "#6f4e33",
  wenge: "#453026",
  // Metalle & Stein (gedämpft, damit sie neben Holz nicht schreien)
  chrom: "#c4c8cb",
  edelstahl: "#b9bebe",
  schwarzstahl: "#41454a",
  messing: "#ad8a4c",
  kupfer: "#a8674a",
  beton: "#9c9b97",
  "naturstein-hell": "#cfc7b8",
  "marmor-weiss": "#e8e6e0",
  // Farbakzente
  salbei: "#9aa88e",
  graugruen: "#7d8b7a",
  olive: "#6f7250",
  petrol: "#3c6069",
  blaugrau: "#7d8b96",
  dunkelblau: "#2d3a55",
  terracotta: "#b0603f",
  rostrot: "#9b4a2f",
  senf: "#c4964a",
  bordeaux: "#6e2b35",
};

/** Alle Slugs (stabile Reihenfolge = Insertion, entspricht dem Schema-Enum). */
export const FARBSLUGS = Object.keys(FARBSLUG_HEX) as FarbSlug[];

/** Type-Guard: ist `v` ein bekannter Farb-Slug? */
export function istFarbSlug(v: unknown): v is FarbSlug {
  return typeof v === "string" && v in FARBSLUG_HEX;
}

/** Hex-Wert eines Slugs (leerer Fallback #cccccc bei unbekanntem Slug). */
export function farbHex(slug: string | null | undefined): string {
  return slug && istFarbSlug(slug) ? FARBSLUG_HEX[slug] : "#cccccc";
}

/**
 * Effektive Farbvariante eines Objekts nach der eisernen Rangfolge
 * **MANUELL > KI > Default (= erste farbVariante)**.
 *
 * - `manuell`  – Nutzer-Override aus dem UI-State (pro placementId).
 * - `ki`       – `placement.farbe` aus dem Plan (Kurator-Wahl).
 * - Default    – erste Variante der `farbVarianten` des Katalog-Items.
 *
 * Rückgabe `undefined`, wenn keine gültige Variante bestimmbar ist (Item ohne
 * `farbVarianten` und ohne Override) → der Renderer nutzt dann seine
 * Material-Basisfarbe (unveränderter Pfad). Rein & deterministisch.
 */
export function loeseFarbSlug(
  farbVarianten: readonly string[] | null | undefined,
  ki: string | null | undefined,
  manuell: string | null | undefined,
): FarbSlug | undefined {
  const kandidat = manuell ?? ki ?? farbVarianten?.[0];
  return istFarbSlug(kandidat) ? kandidat : undefined;
}