// ╔══════════════════════════════════════════════════════════════╗
// ║ SMART HOME DEMO — Hi-Fi Dashboard Mockup ║
// ║ Modelliert nach Home Assistant, dark/cyan-Brand-Adaption ║
// ╚══════════════════════════════════════════════════════════════╝
const SMD_PALETTE = {
bgDeep: "#071520",
bgCard: "#0D2030",
bgCard2: "#11283C",
accent: "#3ABDD0",
soft: "#8DDBEA",
text: "#ffffff",
textDim: "rgba(255,255,255,0.55)",
border: "rgba(141,219,234,0.12)",
borderHi: "rgba(58,189,208,0.45)",
// chart accents
pv: "#F2A65A", // PV warm orange
battery: "#5DD3B0", // battery teal-green
grid: "#7B9BD3", // grid blue
water: "#5BBFD6", // water cyan
consumption: "#C28BD9",// purple consumption
warm: "#E8A5B5", // warm pink (waschmaschine)
};
// ── Mini sparkline ─────────────────────────────────────────────
function Sparkline({ data, color = SMD_PALETTE.accent, w = 72, h = 22 }) {
const max = Math.max(...data);
const min = Math.min(...data);
const range = max - min || 1;
const pts = data.map((v, i) => {
const x = (i / (data.length - 1)) * w;
const y = h - ((v - min) / range) * h;
return `${x.toFixed(1)},${y.toFixed(1)}`;
}).join(" ");
return (
);
}
// ── Inline Material-style icons (very small, white-line) ───────
const SMDIcons = {
light: (c) => ,
thermo: (c) => ,
bed: (c) => ,
kitchen: (c) => ,
shower: (c) => ,
sofa: (c) => ,
desk: (c) => ,
toilet: (c) => ,
garage: (c) => ,
garden: (c) => ,
attic: (c) => ,
server: (c) => ,
device: (c) => ,
shield: (c) => ,
media: (c) => ,
weather: (c) => ,
bolt: (c) => ,
scenes: (c) => ,
presence: (c) => ,
valve: (c) => ,
search: (c) => ,
plus: (c) => ,
menu: (c) => ,
edit: (c) => ,
msg: (c) => ,
arrowL: (c) => ,
chevR: (c) => ,
power: (c) => ,
// sidebar nav items
home: (c) => ,
grid: (c) => ,
user: (c) => ,
building: (c) => ,
list: (c) => ,
chart: (c) => ,
cal: (c) => ,
wrench: (c) => ,
bug: (c) => ,
flow: (c) => ,
play: (c) => ,
code: (c) => ,
link: (c) => ,
drop: (c) => ,
cast: (c) => ,
fire: (c) => ,
car: (c) => ,
factory: (c) => ,
lock: (c) => ,
};
// ── Path-aware data ────────────────────────────────────────────
const SMD_DATA = {
altbau: {
welcome: "Familie Bauer",
favorites: [
{ id: "f1", name: "Wohnzimmer", state: "21,4 °C", icon: "thermo", on: true, color: SMD_PALETTE.pv },
{ id: "f2", name: "Garage", state: "Geschlossen", icon: "garage", on: false },
{ id: "f3", name: "Außenlicht", state: "Auto", icon: "light", on: true, color: SMD_PALETTE.pv },
{ id: "f4", name: "Heizung", state: "Heizmodus", icon: "fire", on: true, color: SMD_PALETTE.warm },
{ id: "f5", name: "Hauptschalter", state: "Tag", icon: "scenes", on: true },
{ id: "f6", name: "Anwesenheit", state: "Zuhause", icon: "presence", on: true, color: SMD_PALETTE.battery },
],
floors: [
{ name: "EG", icon: "home", rooms: [
{ id: "wohnzimmer", name: "Wohnzimmer", state: "21,4 °C", icon: "sofa" },
{ id: "kueche", name: "Küche", state: "20,1 °C", icon: "kitchen" },
{ id: "esszimmer", name: "Esszimmer", state: "20,8 °C", icon: "kitchen" },
{ id: "bad", name: "Badezimmer", state: "23,2 °C", icon: "shower" },
{ id: "wc", name: "WC", state: "—", icon: "toilet" },
{ id: "gang", name: "Gang", state: "19,8 °C", icon: "home" },
]},
{ name: "OG", icon: "home", rooms: [
{ id: "schlafzimmer", name: "Schlafzimmer", state: "19,5 °C", icon: "bed" },
{ id: "kinderzimmer", name: "Kinderzimmer", state: "20,3 °C", icon: "bed" },
{ id: "buero", name: "Büro", state: "19,3 °C", icon: "desk" },
]},
{ name: "Außen", icon: "garden", rooms: [
{ id: "garage", name: "Garage", state: "—", icon: "garage" },
{ id: "garten", name: "Garten", state: "—", icon: "garden" },
{ id: "geraete", name: "Geräte", state: "32 aktiv", icon: "device" },
]},
],
summaries: [
{ name: "Entdeckte Geräte", value: "1 Gerät zum Hinzufügen", icon: "device", color: SMD_PALETTE.accent },
{ name: "Beleuchtung", value: "1 ein", icon: "light", color: SMD_PALETTE.pv },
{ name: "Raumklima", value: "20,3 °", icon: "thermo", color: SMD_PALETTE.pv },
{ name: "Sicherheit", value: "Aufgeschlossen", icon: "shield", color: SMD_PALETTE.warm },
{ name: "Mediaplayer", value: "Keine Wiedergabe", icon: "media", color: SMD_PALETTE.consumption },
{ name: "Wetter", value: "8,6 °C · Sonnig", icon: "weather", color: SMD_PALETTE.pv },
{ name: "Heutige Energie", value: "7,5 kWh", icon: "bolt", color: SMD_PALETTE.accent },
],
energy: {
pv: 24.34, battery: 3.6, grid: -13.25, gridCost: -1.19,
home: 7.5, water: 365.4, autarkie: 100, eigenverbrauch: 27, einspeisung: 13.25,
},
},
neubau: {
welcome: "Familie Hofer",
favorites: [
{ id: "f1", name: "Beschattung", state: "Auto · 60%", icon: "grid", on: true, color: SMD_PALETTE.pv },
{ id: "f2", name: "FBH Vorlauf", state: "32,4 °C", icon: "thermo", on: true, color: SMD_PALETTE.warm },
{ id: "f3", name: "Lüftung KWL", state: "Stufe 2", icon: "weather", on: true, color: SMD_PALETTE.water },
{ id: "f4", name: "Wallbox", state: "Lädt 11 kW", icon: "car", on: true, color: SMD_PALETTE.battery },
{ id: "f5", name: "Alarm", state: "Tag-Modus", icon: "shield", on: true },
{ id: "f6", name: "Szene Heim", state: "Aktiv", icon: "scenes", on: true, color: SMD_PALETTE.accent },
],
floors: [
{ name: "EG", icon: "home", rooms: [
{ id: "wohnen", name: "Wohnen/Essen", state: "22,1 °C", icon: "sofa" },
{ id: "kueche", name: "Küche", state: "21,8 °C", icon: "kitchen" },
{ id: "buero", name: "Homeoffice", state: "21,5 °C", icon: "desk" },
{ id: "bad-eg", name: "Bad EG", state: "—", icon: "shower" },
{ id: "garderobe", name: "Garderobe", state: "20,9 °C", icon: "home" },
]},
{ name: "OG", icon: "home", rooms: [
{ id: "schlafen", name: "Schlafen", state: "19,2 °C", icon: "bed" },
{ id: "kind1", name: "Kind 1", state: "20,1 °C", icon: "bed" },
{ id: "kind2", name: "Kind 2", state: "20,4 °C", icon: "bed" },
{ id: "bad-og", name: "Bad OG", state: "23,5 °C", icon: "shower" },
]},
{ name: "Technik & Außen", icon: "wrench", rooms: [
{ id: "technik", name: "Technikraum", state: "KNX online", icon: "server" },
{ id: "carport", name: "Carport", state: "Wallbox aktiv", icon: "car" },
{ id: "garten", name: "Garten", state: "Bewässerung aus", icon: "garden" },
]},
],
summaries: [
{ name: "KNX-Geräte", value: "84 online · 0 Fehler", icon: "flow", color: SMD_PALETTE.accent },
{ name: "Beleuchtung", value: "DALI · 6 ein", icon: "light", color: SMD_PALETTE.pv },
{ name: "Raumklima FBH", value: "21,3 °", icon: "thermo", color: SMD_PALETTE.warm },
{ name: "KWL", value: "Stufe 2 · 84% Eff.", icon: "weather", color: SMD_PALETTE.water },
{ name: "Sicherheit", value: "Tag-Modus aktiv", icon: "shield", color: SMD_PALETTE.battery },
{ name: "Wallbox", value: "Lädt · PV-Überschuss", icon: "car", color: SMD_PALETTE.pv },
{ name: "Heutige Energie", value: "12,3 kWh", icon: "bolt", color: SMD_PALETTE.accent },
],
energy: {
pv: 38.2, battery: 8.4, grid: -18.6, gridCost: -1.74,
home: 12.3, water: 142.8, autarkie: 96, eigenverbrauch: 42, einspeisung: 18.6,
},
},
gewerbe: {
welcome: "Standort Lambach",
favorites: [
{ id: "f1", name: "Lastspitze", state: "32,4 kW", icon: "bolt", on: true, color: SMD_PALETTE.pv },
{ id: "f2", name: "Tagesumsatz", state: "€ 24.860", icon: "chart", on: true, color: SMD_PALETTE.battery },
{ id: "f3", name: "KUKA Roboter 1", state: "Bereit", icon: "factory", on: true, color: SMD_PALETTE.accent },
{ id: "f4", name: "Zutritt Tor 1", state: "Geschlossen", icon: "lock", on: false },
{ id: "f5", name: "Anwesenheit", state: "17 Mitarbeiter", icon: "presence", on: true, color: SMD_PALETTE.accent },
{ id: "f6", name: "PV-Feld", state: "24,6 kW Live", icon: "grid", on: true, color: SMD_PALETTE.pv },
],
floors: [
{ name: "Halle", icon: "factory", rooms: [
{ id: "produktion", name: "Produktion", state: "12 MA · Linie läuft", icon: "factory" },
{ id: "werkstatt", name: "Werkstatt", state: "5 MA · KUKA bereit", icon: "wrench" },
{ id: "lager", name: "Lager", state: "Tor zu · 2 offen", icon: "garage" },
{ id: "ausgabe", name: "Ausgabe", state: "3 Abholungen", icon: "garage" },
]},
{ name: "Büro", icon: "building", rooms: [
{ id: "buero", name: "Großraum", state: "22,1 °C", icon: "desk" },
{ id: "besprech", name: "Besprechung", state: "Belegt 14:00", icon: "user" },
{ id: "empfang", name: "Empfang", state: "—", icon: "user" },
{ id: "kueche-bz", name: "Sozialraum", state: "20,8 °C", icon: "kitchen" },
]},
{ name: "Energie & Zutritt", icon: "bolt", rooms: [
{ id: "pv", name: "PV-Feld 24 kWp", state: "24,6 kW", icon: "grid" },
{ id: "speicher", name: "Speicher 60 kWh", state: "68%", icon: "bolt" },
{ id: "wallbox", name: "Wallbox-Park", state: "3/6 lädt", icon: "car" },
{ id: "zutritt", name: "Zutrittssystem", state: "12 aktiv", icon: "lock" },
]},
],
summaries: [
{ name: "Anlagen-Status", value: "Alles betriebsbereit", icon: "shield", color: SMD_PALETTE.battery },
{ name: "Tagesumsatz", value: "€ 24.860 · +8%", icon: "chart", color: SMD_PALETTE.battery },
{ name: "Anwesenheit", value: "17 Mitarbeiter", icon: "presence", color: SMD_PALETTE.accent },
{ name: "Werkstatt", value: "KUKA 1 bereit", icon: "factory", color: SMD_PALETTE.accent },
{ name: "Leistungsabnahme", value: "32,4 kW · stabil", icon: "bolt", color: SMD_PALETTE.pv },
{ name: "Zutritt", value: "Tor 1, 2 zu · Tor 3 offen", icon: "lock", color: SMD_PALETTE.warm },
{ name: "PV-Eigenverbrauch", value: "73% heute", icon: "grid", color: SMD_PALETTE.pv },
],
energy: {
pv: 184.2, battery: 22.4, grid: -41.6, gridCost: -3.86,
home: 132.6, water: 0, autarkie: 78, eigenverbrauch: 73, einspeisung: 41.6,
},
},
};
// ── Tile component (favorites + room) ──────────────────────────
function SMDTile({ icon, name, state, on, color, accent, large, onClick }) {
const Icon = SMDIcons[icon];
const iconColor = on ? (color || SMD_PALETTE.accent) : SMD_PALETTE.textDim;
const iconBg = on ? `${(color || SMD_PALETTE.accent)}22` : "rgba(255,255,255,0.04)";
return (
{Icon && Icon(iconColor)}
{name}
{state &&
{state}
}
);
}
// ── Summary list-row (right rail) ──────────────────────────────
function SMDSummaryRow({ icon, name, value, color }) {
const Icon = SMDIcons[icon];
return (
);
}
// ── Sidebar ────────────────────────────────────────────────────
function SMDSidebar({ activeView, onNav, tourActive, tourStep }) {
const items = [
{ k: "uebersicht", icon: "home", label: "Übersicht" },
{ k: "energie", icon: "bolt", label: "Energie" },
{ k: "kal", icon: "cal", label: "Kalender" },
];
// Map of view→index (for cursor highlight during tour)
const tourIdx = tourActive ? Math.min(tourStep, items.length - 1) : -1;
return (
);
}
// ── Top action bar ─────────────────────────────────────────────
function SMDTopBar({ title, back, onBack, tabs, activeTab, onTab }) {
return (
{back && (
{SMDIcons.arrowL(SMD_PALETTE.text)}
)}
{!tabs && (
{title}
)}
{tabs && (
{tabs.map((t) => (
onTab(t)} style={{
padding: "0 16px", border: 0, background: "transparent",
color: activeTab === t ? SMD_PALETTE.text : SMD_PALETTE.textDim,
fontSize: 13, fontWeight: 500, fontFamily: "Inter, sans-serif",
cursor: "pointer", borderBottom: `2px solid ${activeTab === t ? SMD_PALETTE.accent : "transparent"}`,
marginBottom: -1,
}}>{t}
))}
)}
{["plus", "search", "msg", "edit"].map((k) => (
{SMDIcons[k] && SMDIcons[k](SMD_PALETTE.textDim)}
))}
);
}
// ── Übersicht View ─────────────────────────────────────────────
function SMDOverview({ data, onRoom }) {
return (
Willkommen {data.welcome}
{/* Left column */}
{/* Favoriten */}
Favoriten
{data.favorites.map((f) => (
))}
{/* Floors */}
{data.floors.map((floor) => (
{SMDIcons[floor.icon] && SMDIcons[floor.icon](SMD_PALETTE.textDim)}
{floor.name}
{floor.rooms.map((r) => (
onRoom && onRoom(r)}/>
))}
))}
{/* Right rail */}
Zusammenfassungen
{data.summaries.map((s, i) => )}
);
}
const SMD_COMMERCIAL_ROOM_DETAILS = {
werkstatt: {
pill: { icon: "wrench", text: "5 Mitarbeiter · KUKA Roboter 1 bereit", color: SMD_PALETTE.accent },
stats: [
{ icon: "chart", name: "Tagesumsatz", state: "€ 8.420", color: SMD_PALETTE.battery },
{ icon: "presence", name: "Anwesenheit", state: "5 / 6 Mitarbeiter", color: SMD_PALETTE.accent },
{ icon: "factory", name: "KUKA Roboter 1", state: "Bereit · Auto", color: SMD_PALETTE.pv },
],
panels: [
{ title: "Maschinen & Anlagen", tiles: [
{ icon: "factory", name: "KUKA Roboter 1", state: "Auto · Zyklus 42 s", color: SMD_PALETTE.pv },
{ icon: "wrench", name: "CNC Fräse", state: "Standby", color: SMD_PALETTE.soft },
{ icon: "bolt", name: "Druckluft", state: "7,8 bar · OK", color: SMD_PALETTE.battery },
]},
{ title: "Personal & Aufträge", tiles: [
{ icon: "presence", name: "Mitarbeiter", state: "5 anwesend", color: SMD_PALETTE.accent },
{ icon: "list", name: "Auftrag SM-2418", state: "76% fertig", color: SMD_PALETTE.battery },
{ icon: "chart", name: "Heute fakturierbar", state: "€ 8.420", color: SMD_PALETTE.pv },
]},
{ title: "Energie & Sicherheit", tiles: [
{ icon: "bolt", name: "Werkstatt-Leistung", state: "4,8 kW", color: SMD_PALETTE.pv },
{ icon: "shield", name: "Roboterzelle", state: "Tür verriegelt", color: SMD_PALETTE.battery },
{ icon: "weather", name: "Absaugung", state: "Läuft · Filter OK", color: SMD_PALETTE.water },
]},
],
scenes: [
{ id: "start", name: "Werkstatt Start", state: "Licht, Druckluft, Absaugung" },
{ id: "pause", name: "Pause", state: "Roboter safe, Druckluft reduziert" },
{ id: "schluss", name: "Feierabend", state: "Alles aus, Alarm scharf" },
],
automations: [
{ icon: "flow", name: "KUKA Störung", state: "Push + Licht rot", color: SMD_PALETTE.warm },
{ icon: "flow", name: "Druckluft Nacht", state: "Leckage-Warnung aktiv", color: SMD_PALETTE.battery },
{ icon: "flow", name: "Tagesumsatz Snapshot", state: "17:00 Report", color: SMD_PALETTE.accent },
],
},
produktion: {
pill: { icon: "factory", text: "12 Mitarbeiter · Linie läuft", color: SMD_PALETTE.pv },
stats: [
{ icon: "chart", name: "Tagesumsatz", state: "€ 16.440", color: SMD_PALETTE.battery },
{ icon: "presence", name: "Anwesenheit", state: "12 / 14 Mitarbeiter", color: SMD_PALETTE.accent },
{ icon: "bolt", name: "Leistung jetzt", state: "18,6 kW", color: SMD_PALETTE.pv },
],
panels: [
{ title: "Linie & Maschinen", tiles: [
{ icon: "factory", name: "Linie 1", state: "Produktion", color: SMD_PALETTE.battery },
{ icon: "factory", name: "KUKA Roboter 2", state: "Auto · 97%", color: SMD_PALETTE.pv },
{ icon: "wrench", name: "Kompressor", state: "OK · 7,9 bar", color: SMD_PALETTE.water },
]},
{ title: "Schicht & Leistung", tiles: [
{ icon: "presence", name: "Schicht A", state: "12 anwesend", color: SMD_PALETTE.accent },
{ icon: "list", name: "Stückzahl heute", state: "842 Teile", color: SMD_PALETTE.battery },
{ icon: "chart", name: "OEE", state: "86%", color: SMD_PALETTE.pv },
]},
{ title: "Umgebung", tiles: [
{ icon: "thermo", name: "Hallentemperatur", state: "20,8 °C", color: SMD_PALETTE.warm },
{ icon: "weather", name: "Luftqualität", state: "CO₂ 612 ppm", color: SMD_PALETTE.water },
{ icon: "shield", name: "Sicherheitskreis", state: "Geschlossen", color: SMD_PALETTE.battery },
]},
],
scenes: [
{ id: "schichtstart", name: "Schichtstart", state: "Linie freigeben" },
{ id: "störung", name: "Störung", state: "Warnlicht + Eskalation" },
{ id: "reinigung", name: "Reinigung", state: "Maschinen safe" },
],
automations: [
{ icon: "flow", name: "Lastspitze Produktion", state: "Aktiv", color: SMD_PALETTE.pv },
{ icon: "flow", name: "Störung Linie 1", state: "Eskalation aktiv", color: SMD_PALETTE.warm },
{ icon: "flow", name: "Schichtreport", state: "15:00 / 23:00", color: SMD_PALETTE.accent },
],
},
lager: {
pill: { icon: "garage", text: "2 Mitarbeiter · Tore überwacht", color: SMD_PALETTE.soft },
stats: [
{ icon: "chart", name: "Warenausgang", state: "€ 6.120", color: SMD_PALETTE.battery },
{ icon: "presence", name: "Anwesenheit", state: "2 Mitarbeiter", color: SMD_PALETTE.accent },
{ icon: "garage", name: "Tore", state: "Tor 1 zu · Tor 2 offen", color: SMD_PALETTE.warm },
],
panels: [
{ title: "Logistik", tiles: [
{ icon: "garage", name: "Tor 1", state: "Geschlossen", color: SMD_PALETTE.battery },
{ icon: "garage", name: "Tor 2", state: "Offen seit 6 min", color: SMD_PALETTE.warm },
{ icon: "list", name: "Kommissionierung", state: "14 / 21 erledigt", color: SMD_PALETTE.accent },
]},
{ title: "Bestand & Klima", tiles: [
{ icon: "thermo", name: "Lagertemperatur", state: "18,4 °C", color: SMD_PALETTE.warm },
{ icon: "weather", name: "Luftfeuchte", state: "46%", color: SMD_PALETTE.water },
{ icon: "shield", name: "Nachtmodus", state: "Automatisch", color: SMD_PALETTE.battery },
]},
{ title: "Energie", tiles: [
{ icon: "bolt", name: "Lager Verbrauch", state: "1,9 kW", color: SMD_PALETTE.pv },
{ icon: "light", name: "Licht Gänge", state: "Präsenzgeführt", color: SMD_PALETTE.pv },
{ icon: "flow", name: "Tor-Heizung", state: "Aus", color: SMD_PALETTE.soft },
]},
],
scenes: [
{ id: "warenannahme", name: "Warenannahme", state: "Tor + Licht" },
{ id: "kommission", name: "Kommissionierung", state: "Zonenlicht aktiv" },
{ id: "lager-nacht", name: "Lager Nacht", state: "Tore prüfen" },
],
automations: [
{ icon: "flow", name: "Tor offen > 10 min", state: "Warnung aktiv", color: SMD_PALETTE.warm },
{ icon: "flow", name: "Lagerlicht Präsenz", state: "Aktiv", color: SMD_PALETTE.battery },
{ icon: "flow", name: "Warenausgang Report", state: "17:30", color: SMD_PALETTE.accent },
],
},
buero: {
pill: { icon: "desk", text: "8 Mitarbeiter · Raumklima OK", color: SMD_PALETTE.accent },
stats: [
{ icon: "chart", name: "Tagesumsatz", state: "€ 9.310", color: SMD_PALETTE.battery },
{ icon: "presence", name: "Anwesenheit", state: "8 / 10 Mitarbeiter", color: SMD_PALETTE.accent },
{ icon: "thermo", name: "Klima Büros", state: "21,8 °C", color: SMD_PALETTE.warm },
],
panels: [
{ title: "Bürokomfort", tiles: [
{ icon: "light", name: "Arbeitslicht", state: "Automatik", color: SMD_PALETTE.pv },
{ icon: "thermo", name: "Heizung/Kühlung", state: "21,8 °C", color: SMD_PALETTE.warm },
{ icon: "weather", name: "CO₂", state: "684 ppm", color: SMD_PALETTE.water },
]},
{ title: "Team & Zutritt", tiles: [
{ icon: "presence", name: "Mitarbeiter", state: "8 anwesend", color: SMD_PALETTE.accent },
{ icon: "lock", name: "Büro-Zutritt", state: "Offen bis 18:00", color: SMD_PALETTE.battery },
{ icon: "cal", name: "Besprechung", state: "14:00 belegt", color: SMD_PALETTE.soft },
]},
{ title: "Betrieb", tiles: [
{ icon: "bolt", name: "Büro-Verbrauch", state: "2,1 kW", color: SMD_PALETTE.pv },
{ icon: "server", name: "UniFi Netzwerk", state: "Online", color: SMD_PALETTE.battery },
{ icon: "chart", name: "Anfragen heute", state: "18", color: SMD_PALETTE.accent },
]},
],
scenes: [
{ id: "arbeit", name: "Arbeitszeit", state: "Licht + Klima" },
{ id: "meeting", name: "Meeting", state: "Beschattung + Display" },
{ id: "büro-aus", name: "Feierabend", state: "Standby + Zutritt" },
],
automations: [
{ icon: "flow", name: "CO₂ Meetingraum", state: "Aktiv", color: SMD_PALETTE.water },
{ icon: "flow", name: "Büro Feierabend", state: "18:15", color: SMD_PALETTE.battery },
{ icon: "flow", name: "Umsatz-Snapshot", state: "16:00", color: SMD_PALETTE.accent },
],
},
};
function getSMDCommercialProfile(room) {
const id = room?.id || "";
if (SMD_COMMERCIAL_ROOM_DETAILS[id]) return SMD_COMMERCIAL_ROOM_DETAILS[id];
if (/buero|besprech|empfang|kueche/.test(id)) return SMD_COMMERCIAL_ROOM_DETAILS.buero;
if (/lager|ausgabe/.test(id)) return SMD_COMMERCIAL_ROOM_DETAILS.lager;
if (/produktion/.test(id)) return SMD_COMMERCIAL_ROOM_DETAILS.produktion;
return SMD_COMMERCIAL_ROOM_DETAILS.werkstatt;
}
function SMDCommercialRoomDetail({ room }) {
const profile = getSMDCommercialProfile(room);
const [scene, setScene] = React.useState(profile.scenes[0]?.id || "start");
React.useEffect(() => {
setScene(profile.scenes[0]?.id || "start");
}, [room?.id]);
const Section = ({ title, children }) => (
{title}
{SMDIcons.chevR(SMD_PALETTE.textDim)}
{children}
);
const PillIcon = SMDIcons[profile.pill.icon] || SMDIcons.factory;
return (
{PillIcon(profile.pill.color)}
{profile.pill.text}
{profile.stats.map((s) => (
))}
{profile.panels.map((panel) => (
{panel.tiles.map((t) => (
))}
))}
{profile.scenes.map((s) => {
const active = scene === s.id;
return (
setScene(s.id)} style={{
background: active ? `${SMD_PALETTE.accent}14` : SMD_PALETTE.bgCard,
border: `1px solid ${active ? SMD_PALETTE.borderHi : SMD_PALETTE.border}`,
borderRadius: 10, padding: "10px 12px", display: "flex", alignItems: "center", gap: 10,
cursor: "pointer", textAlign: "left", color: "inherit",
transition: "all 0.15s",
}}>
{SMDIcons.scenes(active ? SMD_PALETTE.accent : SMD_PALETTE.soft)}
);
})}
{profile.automations.map((a) => (
))}
);
}
// ── Room Detail (Büro) ─────────────────────────────────────────
function SMDRoomDetail({ room, onBack }) {
// Static deep-detail for "Büro" — works for all paths as a sample room
const [scene, setScene] = React.useState("buero-hell");
const [dim, setDim] = React.useState(5);
const [temp, setTemp] = React.useState(5.0);
const Section = ({ title, action, children }) => (
{title}
{SMDIcons.chevR(SMD_PALETTE.textDim)}
{action}
{children}
);
return (
{/* temperature pill (centered) */}
{SMDIcons.thermo(SMD_PALETTE.warm)}
19,3 °C
{/* Beleuchtung */}
{SMDIcons.power(SMD_PALETTE.pv)}
Ein
}>
{/* Raumklima */}
{SMDIcons.fire(SMD_PALETTE.warm)}
setTemp(Math.max(0, temp - 0.5))} style={{
width: 32, height: 32, borderRadius: 8, border: `1px solid ${SMD_PALETTE.border}`,
background: SMD_PALETTE.bgDeep, color: SMD_PALETTE.text, cursor: "pointer", fontSize: 16,
}}>−
{temp.toFixed(1)} °C
setTemp(temp + 0.5)} style={{
width: 32, height: 32, borderRadius: 8, border: `1px solid ${SMD_PALETTE.border}`,
background: SMD_PALETTE.bgDeep, color: SMD_PALETTE.text, cursor: "pointer", fontSize: 16,
}}>+
{/* Mediaplayer */}
{SMDIcons.cast(SMD_PALETTE.accent)}
{/* Szenen */}
{[
{ id: "nacht", name: "Nachtlicht", state: "Vor 3 Jahren" },
{ id: "buero-hell", name: "Büro Hell", state: "Vor 3 Jahren" },
{ id: "gedimmt", name: "Gedimmt", state: "Unbekannt" },
{ id: "fokus", name: "Fokus", state: "Letzte Woche" },
].map((s) => {
const active = scene === s.id;
return (
setScene(s.id)} style={{
background: active ? `${SMD_PALETTE.accent}14` : SMD_PALETTE.bgCard,
border: `1px solid ${active ? SMD_PALETTE.borderHi : SMD_PALETTE.border}`,
borderRadius: 10, padding: "10px 12px", display: "flex", alignItems: "center", gap: 10,
cursor: "pointer", textAlign: "left", color: "inherit",
transition: "all 0.15s",
}}>
{SMDIcons.scenes(active ? SMD_PALETTE.accent : SMD_PALETTE.soft)}
);
})}
{/* Hardware groups */}
{/* Automation */}
{SMDIcons.flow(SMD_PALETTE.textDim)}
Automationen
);
}
// ── Energy distribution diagram ────────────────────────────────
function SMDEnergyDist({ e }) {
// 4 nodes around center "Home" — PV top, Water right, Battery bottom, Grid left
const cx = 220, cy = 200;
const nodeR = 38;
const dist = 130;
const nodes = {
pv: { x: cx, y: cy - dist, label: "PV", value: `${e.pv.toFixed(1)} kWh`, color: SMD_PALETTE.pv, icon: "bolt" },
water: { x: cx + dist, y: cy, label: "Wasser", value: `${e.water.toFixed(0)} L`, color: SMD_PALETTE.water, icon: "drop" },
battery: { x: cx, y: cy + dist, label: "Batterie", value: `${e.battery > 0 ? '↓' : '↑'} ${Math.abs(e.battery).toFixed(2)} kWh`, color: SMD_PALETTE.warm, icon: "bolt" },
grid: { x: cx - dist, y: cy, label: "Netz", value: `${e.grid > 0 ? '→' : '←'} ${Math.abs(e.grid).toFixed(2)} kWh`, color: SMD_PALETTE.grid, icon: "factory" },
home: { x: cx, y: cy, label: "Home", value: `${e.home.toFixed(1)} kWh`, color: SMD_PALETTE.accent, icon: "home" },
};
const Node = ({ n, big }) => {
const r = big ? nodeR : nodeR;
const Icon = SMDIcons[n.icon];
return (
{Icon && Icon(n.color)}
{n.value}
{n.label}
);
};
// curved paths between nodes (PV→Home, Battery→Home, Grid→Home, Water→Home)
const Path = ({ from, to, color, dashed }) => {
const fx = from.x, fy = from.y, tx = to.x, ty = to.y;
// simple quadratic curve toward center
const mx = (fx + tx) / 2, my = (fy + ty) / 2;
return (
);
};
// animated dots along path (approx via small circles + animateMotion)
const FlowDot = ({ from, to, color, dur = 3 }) => (
);
return (
);
}
// ── Bar chart (stacked-ish) ────────────────────────────────────
function SMDBarChart({ values, colors, height = 180, max, min = 0, suffix = "kW", label }) {
// values: array of {pos: [up bars], neg: [down bars]} per timestep
const w = 520, h = height;
const padL = 36, padR = 12, padT = 12, padB = 22;
const innerH = h - padT - padB;
const innerW = w - padL - padR;
const range = max - min;
const zeroY = padT + (max / range) * innerH;
const barW = innerW / values.length * 0.6;
const slot = innerW / values.length;
const yTicks = [];
const tickStep = (max - min) / 4;
for (let i = 0; i <= 4; i++) {
const v = max - tickStep * i;
yTicks.push({ v: Number(v.toFixed(1)), y: padT + (i / 4) * innerH });
}
return (
{/* y-axis ticks + grid */}
{yTicks.map((t, i) => (
{t.v}
))}
{/* unit */}
{suffix}
{/* bars */}
{values.map((step, i) => {
const x = padL + slot * i + (slot - barW) / 2;
let yPos = zeroY;
let yNeg = zeroY;
return (
{step.pos && step.pos.map((seg, j) => {
const segH = (seg / range) * innerH;
yPos -= segH;
return ;
})}
{step.neg && step.neg.map((seg, j) => {
const segH = (Math.abs(seg) / range) * innerH;
const r = ;
yNeg += segH;
return r;
})}
);
})}
{/* x labels (every 4th) */}
{values.map((_, i) => i % 4 === 0 && (
{`${i}:00`}
))}
);
}
// ── Area chart (PV vs grid) ────────────────────────────────────
function SMDAreaChart({ height = 180 }) {
const w = 520, h = height;
const padL = 36, padR = 12, padT = 12, padB = 22;
const innerH = h - padT - padB;
const innerW = w - padL - padR;
// Bell curve PV + smaller grid line
const N = 24;
const pv = Array.from({length: N}, (_, i) => {
const x = (i - 12) / 5;
return Math.max(0, 12 * Math.exp(-x*x) + (Math.random() - 0.5) * 1.2);
});
pv[0] = 0; pv[N-1] = 0; pv[3] = 0; pv[4] = 0.4; pv[5] = 1.2;
const grid = pv.map((v, i) => i > 6 && i < 14 ? Math.max(0, v - 4 - Math.random()) : v * 0.3);
const max = 14;
const toX = (i) => padL + (i / (N-1)) * innerW;
const toY = (v) => padT + innerH - (v / max) * innerH;
const pvPath = pv.map((v, i) => `${i === 0 ? 'M' : 'L'}${toX(i)},${toY(v)}`).join(" ") +
` L${toX(N-1)},${toY(0)} L${toX(0)},${toY(0)} Z`;
const gridPath = grid.map((v, i) => `${i === 0 ? 'M' : 'L'}${toX(i)},${toY(v)}`).join(" ") +
` L${toX(N-1)},${toY(0)} L${toX(0)},${toY(0)} Z`;
return (
{[0, 4, 8, 12, 14].map((v, i) => {
const y = toY(v);
return (
{v}
);
})}
kW
`${i === 0 ? 'M' : 'L'}${toX(i)},${toY(v)}`).join(" ")}
fill="none" stroke={SMD_PALETTE.pv} strokeWidth="1.5"/>
{[0, 4, 8, 12, 16, 20].map((hr, i) => (
{`${hr}:00`}
))}
);
}
// ── Energy Source row ──────────────────────────────────────────
function SMDQuelle({ color, name, value, cost }) {
return (
);
}
// ── Energy View ────────────────────────────────────────────────
function SMDEnergyView({ data }) {
const e = data.energy;
// build mock bar data
const N = 24;
const usage = Array.from({length: N}, (_, i) => {
const isDay = i > 6 && i < 18;
return {
pos: isDay ? [Math.max(0, (Math.random()-0.5) * 2 + 1.2)] : [0],
neg: !isDay ? [-Math.random() * 1.2 - 0.3] : [],
};
});
return (
{/* Energieverteilung */}
Energieverteilung
{SMDIcons.chevR(SMD_PALETTE.textDim)}
{/* Quellen-Tabelle + KPIs */}
Quellen
0 ? '−' : ''}${Math.abs(e.battery).toFixed(2)} kWh`} cost=""/>
{/* KPI gauges */}
{/* Charts row */}
Stromquellen
Stromnutzung
+{e.home.toFixed(1)} kWh
{/* Per-device consumption */}
Gesamtverbrauch · Einzelgeräte
Heute · pro Gerät
);
}
const SMD_DEVICES = [
{ name: "Büro EG", color: "#C8A88A", kwh: 4.3 },
{ name: "Werkstatt", color: "#E89BB4", kwh: 2.8 },
{ name: "Küche & Esszimmer", color: "#7AA8E0", kwh: 1.4 },
{ name: "Speisekammer", color: "#7DBC7D", kwh: 1.2 },
{ name: "Wärmepumpe", color: "#A0AED9", kwh: 0.7 },
{ name: "Büro OG", color: "#5DC8A8", kwh: 0.6 },
{ name: "Audio Wohnzimmer", color: "#E8C76E", kwh: 0.45 },
{ name: "Saugroboter", color: "#5DC8A8", kwh: 0.4 },
{ name: "Mediawand", color: "#9DD9C2", kwh: 0.32 },
{ name: "Badezimmer", color: "#A8D5E8", kwh: 0.22 },
{ name: "Kaffeemaschine", color: "#E07B6B", kwh: 0.18 },
{ name: "Außenbeleuchtung", color: "#B89DDB", kwh: 0.12 },
{ name: "Sauna", color: "#C29DD9", kwh: 0.08 },
{ name: "Waschmaschine", color: "#E8C76E", kwh: 0.05 },
];
function SMDDeviceList() {
const max = Math.max(...SMD_DEVICES.map(d => d.kwh));
const labelW = 168;
return (
{SMD_DEVICES.map((d, i) => {
const pct = (d.kwh / max) * 100;
return (
{d.name}
{d.kwh.toFixed(2)} kWh
);
})}
);
}
// ── Gauge (semi-circle) ────────────────────────────────────────
function SMDGauge({ value, max, label, suffix, color, wide }) {
const pct = Math.min(1, Math.max(0, value / max));
const r = 50, cx = 70, cy = 60;
// Halbkreis von links (180°) nach rechts (0°), oben offen
const x1 = cx - r; // 20, 60
const y1 = cy; // 60
const xEnd = cx + r; // 120, 60
const yEnd = cy;
// Länge des kompletten Halbkreis-Pfads = π · r
const arcLen = Math.PI * r;
const dashOffset = arcLen * (1 - pct);
return (
{/* Hintergrund-Bogen */}
{/* Wert-Bogen via dasharray, klippt sauber bei 0% und 100% */}
{value.toFixed(value >= 10 || suffix === " %" ? 0 : 2)}{suffix}
{label}
);
}
// ── Main DEMO component ────────────────────────────────────────
function SmartHomeDemo({ pathKey }) {
const data = SMD_DATA[pathKey] || SMD_DATA.altbau;
const [view, setView] = React.useState("uebersicht"); // uebersicht | raum | energie
const [room, setRoom] = React.useState(null);
const [eTab, setETab] = React.useState("Zusammenfassung");
const onRoom = (r) => { setRoom(r); setView("raum"); };
const onBack = () => { setView("uebersicht"); setRoom(null); };
const onNav = (k) => {
if (k === "uebersicht" || k === "raum") { setView("uebersicht"); setRoom(null); }
else if (k === "energie") setView("energie");
};
let title, tabs, activeTab, onTab;
if (view === "energie") {
tabs = ["Zusammenfassung", "Strom", "Wasser", "Jetzt"];
activeTab = eTab;
onTab = setETab;
} else if (view === "raum") {
title = room?.name || "Raum";
} else {
title = "Übersicht";
}
return (
{view === "uebersicht" && }
{view === "raum" && (pathKey === "gewerbe"
?
: )}
{view === "energie" && }
);
}
// ── Section wrapper for the landing page ───────────────────────
function SmartHomeDemoSection({ pathKey }) {
const isGewerbe = pathKey === "gewerbe";
return (
LIVE-DEMO
So sieht{" "}
{isGewerbe ? "dein Objekt" : "dein Zuhause"}
{" "}
aus.
{isGewerbe
? "Eine Betriebsoberfläche aus dem Alltag — klick dich durch Bereiche, Zutritt, Technikstatus und Energiedashboard. Dein Objekt wird ähnlich strukturiert: mit deinen Flächen, deinen Anlagen, deinen Werten."
: "Eine echte Konfiguration aus dem Alltag — klick dich durch Räume, Szenen und das Energiedashboard. Dein Setup wird ähnlich aussehen, mit deinen Räumen, deinen Geräten, deinen Werten."}
↑ Sidebar zeigt Hauptbereiche
· {isGewerbe ? "Bereiche klickbar — Detail mit Kennzahlen + Anlagen" : "Räume klickbar — Detail mit Szenen + Geräten"}
· Energie-Tab zeigt PV-Fluss, Quellen, Autarkiegrad
);
}
window.SmartHomeDemoSection = SmartHomeDemoSection;
window.SmartHomeDemo = SmartHomeDemo;
// Im Konfigurator (Step 2) bauen wir den Room-Detail dynamisch fuer den
// aktuellen Raum nach -- Komponenten + Palette dafuer exposen.
window.SMD_PALETTE = SMD_PALETTE;
window.SMDIcons = SMDIcons;
window.SMDTile = SMDTile;