Initialer Import: HA-Panel, Design-System, Companion-App

Drei zusammengehörige Teile in einem Repository:

- homeassistant/  Das fertige, im Einsatz befindliche Home-Assistant-Panel
  (panel_custom Custom Element + pyscript-Backend). Echte Fahrzeug- und
  Personendaten (fahrzeugprofil.json, fahrten.jsonl, tankvorgaenge.jsonl,
  Tankbelege) bleiben per .gitignore außen vor; die anonymisierte Vorlage
  fahrzeugprofil.example.json ist mit dabei.

- design-system/  Eigenständige React-Komponentenbibliothek (@audi-dash/ui),
  die die visuelle Sprache des Panels nachbildet - ohne Audi-Markenzeichen
  und ohne die lizenzierte Hausschrift. Dient als Grundlage für Claude
  Design. War bis hierher ein eigenes Repository und ist in dieses
  eingeschmolzen worden.

- companion-app/  Datenschicht der neuen App DataMetric360 (iOS/Android via
  Capacitor, zusätzlich als Iframe im HA-Dashboard). Noch ohne Oberfläche:
  REST- und WebSocket-Zugriff auf Home Assistant plus Warteschlange für
  Änderungen ohne Netz. Ersetzt das eingespritzte hass-Objekt, das nur
  innerhalb des HA-Frontends existiert.

Dazu die Projektdokumentation: SPECIFICATION.md (Ist-Stand des Panels),
COMPANION_APP_ARCHITECTURE.md (Architekturentscheidungen der neuen App),
AUDIT_2026-08-10.md, DESIGN_BRIEF_DATAMETRIC360.md und der ursprüngliche
Bauauftrag.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-08-11 00:20:05 +02:00
co-authored by Claude Opus 5
commit e1d570992e
151 changed files with 18162 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
.ads-seg {
display: flex;
gap: var(--sp-2);
}
.ads-seg button {
flex: 1;
border: 1px solid var(--line-strong);
background: none;
color: var(--fg2);
font-family: inherit;
font-size: 11px;
letter-spacing: .12em;
text-transform: uppercase;
padding: 11px 8px;
border-radius: var(--r-pill);
cursor: pointer;
}
.ads-seg button.ads-seg__on {
border-color: var(--red);
color: var(--fg);
}
+37
View File
@@ -0,0 +1,37 @@
import * as React from "react";
export interface SegOption<T extends string = string> {
value: T;
label: React.ReactNode;
}
export interface SegProps<T extends string = string> {
options: SegOption<T>[];
value: T;
onChange: (value: T) => void;
className?: string;
}
export function Seg<T extends string = string>({
options,
value,
onChange,
className,
}: SegProps<T>) {
const classes = ["ads-seg"];
if (className) classes.push(className);
return (
<div className={classes.join(" ")}>
{options.map((opt) => (
<button
key={opt.value}
type="button"
className={opt.value === value ? "ads-seg__on" : undefined}
onClick={() => onChange(opt.value)}
>
{opt.label}
</button>
))}
</div>
);
}
@@ -0,0 +1,2 @@
export { Seg } from "./Seg";
export type { SegProps, SegOption } from "./Seg";