/** * Author: Simon-Pierre Boucher * Contact: contact@spboucher.ai * Project: Groupe Ka / Ka Maps * * Theme contract. Ka Maps ships the base cartography and behavior; each * Groupe Ka app supplies one of these objects to make the map its own. */ export type KaMapMode = "light" | "dark"; /** Marker/label treatment for one item family (sale, rent, valuation…). */ export interface MarkerStyleTokens { /** Pill background. */ background: string; /** Pill text. */ text: string; /** Halo/outline behind the pill for map contrast. */ halo: string; /** Background when selected. */ selectedBackground: string; /** Text when selected. */ selectedText: string; } /** Basemap palette — one per mode, derived from the Ka base cartography. */ export interface BasemapPalette { background: string; water: string; waterway: string; park: string; wood: string; residential: string; building: string; buildingOutline: string; road: string; roadCasing: string; roadSecondary: string; primary: string; primaryCasing: string; motorway: string; motorwayCasing: string; boundary: string; label: string; labelHalo: string; cityLabel: string; roadLabel: string; waterLabel: string; } export interface KaMapTheme { /** App identity: "lou-ka" | "immo-ka" | "vrai-prix" | future apps. */ id: string; /** Product name shown in attribution/UI, e.g. "Lou-Ka Maps". */ productName: string; /** Primary accent (controls, selection ring, active states). */ accent: string; /** Text color readable on `accent`. */ onAccent: string; /** UI font stack for controls/popups (CSS font-family). */ fontFamily: string; /** Marker styles per item family. Absent families fall back to `sale`. */ markers: { sale: MarkerStyleTokens; rent?: MarkerStyleTokens; valuation?: MarkerStyleTokens; /** Emphasized items (MapProperty.highlight), e.g. under-valuation deals. */ highlight?: MarkerStyleTokens; }; /** Cluster bubble styling. */ cluster: { background: string; text: string; border: string; /** Valeur indicative affichée sous la bulle (v2) — défaut : border. */ valueText?: string; /** Halo du texte de valeur (v2) — défaut : blanc translucide. */ valueHalo?: string; }; /** Optional per-app overrides merged over the Ka base palettes. */ basemapOverrides?: { light?: Partial; dark?: Partial; }; /** Whether the app supports dark mode at all. */ supportsDark: boolean; } /** Ka Light Map — restrained warm-paper cartography for property discovery. */ export const KA_LIGHT_PALETTE: BasemapPalette = { background: "#f5f3ee", water: "#c9dbe4", waterway: "#c2d6e0", park: "#dbe7d2", wood: "#d3e2ca", residential: "#efece5", building: "#e6e0d5", buildingOutline: "#d9d2c4", road: "#ffffff", roadCasing: "#e0dacd", roadSecondary: "#fdf8ec", primary: "#f6d17c", primaryCasing: "#cfa14a", motorway: "#e0584c", motorwayCasing: "#ad342d", boundary: "#b3a794", label: "#4d473c", labelHalo: "rgba(245, 243, 238, 0.9)", cityLabel: "#38332a", roadLabel: "#7a7364", waterLabel: "#5d7f91", }; /** Ka Dark Map — purpose-designed night cartography (not an inversion). */ export const KA_DARK_PALETTE: BasemapPalette = { background: "#14161a", water: "#0b1218", waterway: "#0e1620", park: "#18211a", wood: "#161f18", residential: "#171a1f", building: "#1d2126", buildingOutline: "#242930", road: "#242931", roadCasing: "#0f1114", roadSecondary: "#2a2f37", primary: "#3c3a30", primaryCasing: "#23211b", motorway: "#7e352c", motorwayCasing: "#4c1f19", boundary: "#4a4f58", label: "#b9bec7", labelHalo: "rgba(20, 22, 26, 0.9)", cityLabel: "#dfe3e9", roadLabel: "#8a9099", waterLabel: "#5f7f93", }; /** Merge app overrides over a base palette. */ export function resolvePalette( mode: KaMapMode, theme: KaMapTheme, ): BasemapPalette { const base = mode === "dark" ? KA_DARK_PALETTE : KA_LIGHT_PALETTE; const overrides = theme.basemapOverrides?.[mode]; return overrides ? { ...base, ...overrides } : base; } /** Marker tokens for an item family, falling back to `sale`. */ export function markerTokens( theme: KaMapTheme, family: "sale" | "rent" | "valuation" | "highlight", ): MarkerStyleTokens { return theme.markers[family] ?? theme.markers.sale; }