Paritaetsrunden 2 und 3, Designpruefung umgesetzt (2026.8.30.8)
Drei zusammenhaengende Runden, alle live bei 375x812 gegen audi_ha_test geprueft und in beiden Codebasen angewandt. Paritaetsrunde 2: der gemeinsame Rahmen war das eigentliche Problem - Seitenrand, Kachelabstaende, Kopfleiste, Tableiste und vier Bausteine des Design-Systems trugen noch den Stand vor der iOS-Entscheidung. Dazu sieben Bildschirme neu aufgebaut. Zwei Panel-Fehler dabei mitbehoben: teaser() zeigte unter "Letzte Fahrt" den aeltesten Datensatz, und "Daten bearbeiten" war ein toter Knopf. Paritaetsrunde 3: das Panel hat nie Audi Type gerendert. @font-face in einem Shadow Root wird ignoriert - Schriftschnitte registriert der Browser pro Dokument, nie pro Shadow Tree. Die drei Schnitte liegen jetzt in audi-dashboard-schriften.css und werden ins Dokument gehaengt. Damit erledigt sich eine ganze Reihe von "die Schrift sieht anders aus"-Eindruecken: die beiden Anwendungen zeigten tatsaechlich verschiedene Schriften. Ausserdem "Daten bearbeiten" im Panel gebaut und portiert, das Zeilenmenue entfernt und die letzten neun Bildschirme angeglichen. Designpruefung: die fuenf Punkte der Reihenfolge. Beim vierten hat das Messen den Befund veraendert - gezaehlt waren die deklarierten Groessen, wirksam war laengst eine saubere Sieben-Schritt-Skala mit 27 Ausreissern; die sind jetzt auf den naechsten Schritt gezogen, keiner verschiebt sich um mehr als 1px. Zuletzt: die Standortvorschau zeichnete die falsche Nadel (das Panel wechselt den Icon-Satz ab 34px, die App nahm immer den grossen), und der Kopfabstand der App ist auf den sicheren Bereich reduziert - die 56px des Panels liegen dort unter der Kopfleiste von Home Assistant, in der nativen Huelle steht darueber nichts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1 +1 @@
|
||||
{"version":"2026.8.30.2","sha256":"88922cb0e3a7603b6e4e2fe7daee85513ec9e16c4ae7b2e0229f514bde58915f","bytes":248241,"gebaut":"2026-08-30T04:29:47Z"}
|
||||
{"version":"2026.8.30.8","sha256":"2754d426c7145d000fd2194d4dd85db096c2fcae008eb518584f189becfb0538","bytes":256098,"gebaut":"2026-08-30T16:30:51Z"}
|
||||
Binary file not shown.
@@ -71,6 +71,33 @@ const CSS_VERSION = (() => {
|
||||
Integrationsordner würde sie das nächste Update mitlöschen. */
|
||||
const STATIK = new URL(".", import.meta.url).href.replace(/\/$/, "");
|
||||
|
||||
/* Schriftschnitte MUESSEN im Dokument registriert werden, nicht im Shadow
|
||||
Root: @font-face-Regeln innerhalb eines Schattenbaums ignoriert der Browser
|
||||
grundsaetzlich, Schriftfamilien sind dokumentweit. Weil audi-dashboard.css
|
||||
(mit den eingebetteten Schnitten am Anfang) hier immer nur an ROOT gehaengt
|
||||
wurde, ist das Panel seit jeher auf Helvetica zurueckgefallen, obwohl
|
||||
"Audi Type" ganz vorn in jedem font-family-Stapel steht - beim
|
||||
Paritaetsabgleich 2026-08-30 dadurch aufgefallen, dass dieselbe
|
||||
Zeichenkette im Panel exakt so breit rendert wie in Helvetica, waehrend die
|
||||
companion-app mit derselben, bytegleichen Schriftdatei ~5 % schmaler setzt.
|
||||
Die Schnitte liegen deshalb jetzt in audi-dashboard-schriften.css, und nur
|
||||
diese Datei geht in document.head - sie enthaelt ausschliesslich
|
||||
@font-face und beeinflusst die uebrige HA-Oberflaeche nicht.
|
||||
|
||||
Der Umkehrfall ist in diesem Projekt schon einmal passiert: das
|
||||
Leaflet-Stylesheet lag in document.head und erreichte den Shadow Root nicht
|
||||
(siehe AGENTS.md, "fragmentierte Leaflet-Darstellung"). Beide Faelle haben
|
||||
dieselbe Ursache - Stylesheets wirken je Baum, Schriften nur im Dokument. */
|
||||
const SCHRIFTEN_ID = "audi-dashboard-schriften";
|
||||
function schriftenLaden() {
|
||||
if (document.getElementById(SCHRIFTEN_ID)) return;
|
||||
const link = document.createElement("link");
|
||||
link.id = SCHRIFTEN_ID;
|
||||
link.rel = "stylesheet";
|
||||
link.href = `${STATIK}/audi-dashboard-schriften.css?v=${CSS_VERSION}`;
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------- Namen des Backends
|
||||
Die eine Stelle, an der die Entity-IDs und Dienstnamen stehen. Sie sind
|
||||
ein Vertrag mit custom_components/audi_dashboard/const.py; die
|
||||
@@ -1190,7 +1217,18 @@ function badge() {
|
||||
|
||||
function teaser() {
|
||||
if (!TRIPS.length && !FILLS.length) return "";
|
||||
const t = TRIPS[0], f = FILLS[0];
|
||||
/* Bis 2026-08-30 stand hier TRIPS[0]/FILLS[0]. Beide Listen kommen vom
|
||||
Backend aufsteigend sortiert (vTrips()/vFuel() geben sie unveraendert in
|
||||
dieser Reihenfolge aus, aelteste Zeile zuerst) - Index 0 war damit der
|
||||
AELTESTE Datensatz, obwohl die Kachel "Letzte Fahrt"/"Letzter
|
||||
Tankvorgang" heisst. Beim Paritaetsabgleich mit der companion-app
|
||||
aufgefallen, die hier von Anfang an nach Zeitstempel sortiert hat.
|
||||
Jetzt beide gleich: der zeitlich juengste Datensatz. */
|
||||
const juengster = (liste, feld) =>
|
||||
liste.length
|
||||
? liste.slice().sort((a, b) => new Date(b[feld]) - new Date(a[feld]))[0]
|
||||
: null;
|
||||
const t = juengster(TRIPS, "ts_start"), f = juengster(FILLS, "ts");
|
||||
return `<div class="tile teaser"><span class="label">Zuletzt</span>
|
||||
${t ? `<button class="leaf" style="padding-left:0" data-go="trip:${t.trip_id}">
|
||||
<span class="k">Letzte Fahrt<small>${esc(t.start_address || "")} → ${esc(t.end_address || "")}</small></span>
|
||||
@@ -1429,7 +1467,10 @@ function vHome() {
|
||||
/* C2/C5/D1: Reihenfolge der myAudi-App - randloses Fahrzeugbild, Name und
|
||||
Status, große Reichweite mit farbigem Balken, dann Aktionskacheln. Die
|
||||
Kacheln führen zu Ansichten statt zu Fernsteuerung, die das Panel bewusst
|
||||
nicht kann. */
|
||||
nicht kann.
|
||||
"Zuletzt" steht seit der Designpruefung 2026-08-30 vor der Standortkarte:
|
||||
zwei kurze, haeufig gelesene Textzeilen lagen bisher unter einer 190px
|
||||
hohen Karte und damit auf dem Telefon unterhalb des ersten Bildschirms. */
|
||||
return `
|
||||
<div class="szene bleed ${szeneKlasse(startIndex())}"><div class="carbox">${carImg("fest")}</div></div>
|
||||
<div class="tile flat" style="margin-bottom:20px">
|
||||
@@ -1506,8 +1547,8 @@ function vHome() {
|
||||
${kmZeile}
|
||||
</div>`;
|
||||
})()}
|
||||
${standortKachel()}
|
||||
${teaser()}`;
|
||||
${teaser()}
|
||||
${standortKachel()}`;
|
||||
}
|
||||
|
||||
/* Kreis-Häkchen (ok) / Kreis-Kreuz (nicht ok) / Kreis-Fragezeichen (unbekannt)
|
||||
@@ -1875,7 +1916,7 @@ function vBatterieverlauf() {
|
||||
? `<span class="dot" style="background:${punktFarbe(soh.status)}"></span>${(soh.delta >= 0 ? "+" : "") + de(soh.delta, 2)} V`
|
||||
: `<span style="color:var(--fg3)">-</span>`}</dd></div>
|
||||
</dl>
|
||||
<span style="display:block;margin-top:10px;color:var(--fg2);font-size:13.5px;line-height:1.6">${soh.text}</span>
|
||||
<span style="display:block;margin-top:10px;color:var(--fg2);font-size:13px;line-height:1.6">${soh.text}</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@@ -2134,7 +2175,20 @@ function vService() {
|
||||
</div>`;
|
||||
}
|
||||
|
||||
/* "Daten bearbeiten" auf der Seite Identität und Technik. Der Knopf war bis
|
||||
2026-08-30 ohne Funktion (kein data-go, kein Handler) - beim
|
||||
Paritätsabgleich aufgefallen und auf Wunsch des Eigentümers jetzt umgesetzt.
|
||||
|
||||
Bearbeitet werden genau die Angaben, für die es sonst nirgends einen Editor
|
||||
gibt: die Werte des technischen Datenblatts (CAR.technik) und die
|
||||
Ausstattungslisten (CAR.ausstattung). Die Kopfdaten darüber - Modell,
|
||||
Kennzeichen, Ausführung, Erstzulassung, FIN - bleiben bewusst außen vor:
|
||||
die pflegt "Fahrzeug einrichten" in den Einstellungen, und zwei Eingabe-
|
||||
stellen für dasselbe Feld laufen erfahrungsgemäß auseinander. */
|
||||
let identBearbeitenOffen = false;
|
||||
|
||||
function vIdent() {
|
||||
if (identBearbeitenOffen) return vIdentBearbeiten();
|
||||
return `
|
||||
<div class="tile"><span class="label">Fahrzeug</span>
|
||||
<dl class="rows" style="margin-top:10px">
|
||||
@@ -2157,7 +2211,51 @@ function vIdent() {
|
||||
${g.sonder.map((x, i) => `<div class="row" ${i === g.sonder.length - 1 ? 'style="border-bottom:0"' : ""}>
|
||||
<dt style="color:var(--fg)">${esc(x)}</dt><dd></dd></div>`).join("")}
|
||||
</dl></div>`).join("")}
|
||||
<button class="aktion">Daten bearbeiten</button>`;
|
||||
<button class="aktion" data-identbearbeiten>Daten bearbeiten</button>`;
|
||||
}
|
||||
|
||||
/* Bearbeitungsansicht: je Technikgruppe eine Kachel mit einem Eingabefeld je
|
||||
Posten, je Ausstattungsgruppe eine Kachel mit einer Zeile je Position -
|
||||
beide mit "×" zum Entfernen und "+ Position hinzufügen", genau im Zuschnitt
|
||||
der Selbstbeteiligung in vVertragBearbeiten(). Gespeichert wird wie überall
|
||||
sonst sofort je Feld über profilSpeichern(). */
|
||||
function vIdentBearbeiten() {
|
||||
const technik = CAR.technik || [];
|
||||
const ausstattung = CAR.ausstattung || [];
|
||||
return `
|
||||
<div class="tile"><span class="label">Daten bearbeiten</span>
|
||||
<span class="label" style="margin-top:10px">Hier stehen das technische Datenblatt und die
|
||||
Ausstattung. Modell, Kennzeichen, Ausführung, Erstzulassung und Fahrgestellnummer pflegst du
|
||||
unter Einstellungen → Fahrzeug einrichten.</span>
|
||||
</div>
|
||||
${technik.map((g, gi) => `<div class="tile"><span class="label">${esc(g.gruppe)}</span>
|
||||
${(g.posten || []).map((pp, i) => `
|
||||
<div class="feld" ${i === g.posten.length - 1 ? 'style="border-bottom:0"' : ""}>
|
||||
<label for="tk${gi}-${i}">${esc(pp[0])}</label>
|
||||
<span style="display:inline-flex;align-items:center;gap:8px">
|
||||
<input id="tk${gi}-${i}" value="${esc(pp[1] || "")}" placeholder="noch offen"
|
||||
data-technik="${gi}|${i}">
|
||||
<button class="zeile-loeschen" data-technikdel="${gi}|${i}"
|
||||
aria-label="${esc(pp[0])} entfernen">×</button>
|
||||
</span>
|
||||
</div>`).join("")}
|
||||
${!(g.posten || []).length ? `<span class="label" style="margin-top:8px">Keine Angaben</span>` : ""}
|
||||
<button class="aktion" data-technikadd="${gi}">+ Position hinzufügen</button>
|
||||
</div>`).join("")}
|
||||
${ausstattung.map((g, gi) => `<div class="tile"><span class="label">${esc(g.gruppe)}</span>
|
||||
${(g.sonder || []).map((x, i) => `
|
||||
<div class="feld" ${i === g.sonder.length - 1 ? 'style="border-bottom:0"' : ""}>
|
||||
<label for="as${gi}-${i}">Position ${i + 1}</label>
|
||||
<span style="display:inline-flex;align-items:center;gap:8px">
|
||||
<input id="as${gi}-${i}" value="${esc(x)}" data-ausstattung="${gi}|${i}">
|
||||
<button class="zeile-loeschen" data-ausstattungdel="${gi}|${i}"
|
||||
aria-label="Position ${i + 1} entfernen">×</button>
|
||||
</span>
|
||||
</div>`).join("")}
|
||||
${!(g.sonder || []).length ? `<span class="label" style="margin-top:8px">Keine Ausstattung hinterlegt</span>` : ""}
|
||||
<button class="aktion" data-ausstattungadd="${gi}">+ Position hinzufügen</button>
|
||||
</div>`).join("")}
|
||||
<button class="aktion primaer" data-identbearbeiten>Fertig</button>`;
|
||||
}
|
||||
|
||||
function monatePlus(datum, monate) { const d = dat(datum); d.setMonth(d.getMonth() + monate); return d; }
|
||||
@@ -2686,7 +2784,7 @@ function vEinst() {
|
||||
if (laeuft === "installieren") return spinner("Installiere …");
|
||||
if (laeuft === "neustart") return spinner("Home Assistant startet neu …");
|
||||
if (u && u.installiert) {
|
||||
return `<span style="display:block;margin-top:8px;color:var(--fg2);font-size:13.5px;line-height:1.6">
|
||||
return `<span style="display:block;margin-top:8px;color:var(--fg2);font-size:13px;line-height:1.6">
|
||||
Version ${esc(u.version)} installiert - die neue Fassung wird erst nach einem Neustart
|
||||
geladen.</span>
|
||||
<button class="aktion" style="margin-top:14px" data-update="neustart">Installation abschließen - Jetzt neu starten</button>`;
|
||||
@@ -2694,13 +2792,13 @@ function vEinst() {
|
||||
if (laeuft === "pruefen") return spinner("Prüfe …");
|
||||
if (u && u.verfuegbar) {
|
||||
return `<dl class="rows"><div class="row" style="border-bottom:0"><dt>Verfügbare Version</dt><dd>${esc(u.version)}</dd></div></dl>
|
||||
<span style="display:block;margin-top:8px;color:var(--fg2);font-size:13.5px;line-height:1.6">
|
||||
<span style="display:block;margin-top:8px;color:var(--fg2);font-size:13px;line-height:1.6">
|
||||
Lädt die neueste Fassung von Gitea und ersetzt den Integrationsordner. Home Assistant
|
||||
muss danach neu gestartet werden. Fahrzeugprofil, Fahrten, Tankvorgänge und eigene
|
||||
Fotos bleiben dabei unangetastet - die liegen außerhalb des Integrationsordners.</span>
|
||||
<button class="aktion" style="margin-top:14px" data-update="installieren">Update installieren</button>`;
|
||||
}
|
||||
return `<span style="display:block;margin-top:8px;color:var(--fg2);font-size:13.5px;line-height:1.6">
|
||||
return `<span style="display:block;margin-top:8px;color:var(--fg2);font-size:13px;line-height:1.6">
|
||||
${u ? `Integration ist aktuell${u.geprueft_am ? ` (geprüft ${dedat(new Date(u.geprueft_am))})` : ""}.` : "Noch nicht geprüft."}</span>
|
||||
<button class="aktion" style="margin-top:14px" data-update="pruefen">Auf Update prüfen</button>`;
|
||||
})()}
|
||||
@@ -3171,6 +3269,15 @@ function vTripsFormular() {
|
||||
<button class="aktion primaer" data-fahrtspeichern>Speichern</button></div>` : ""}
|
||||
<button class="aktion ${fahrtOffen ? "" : "primaer"}" data-fahrt>${fahrtOffen ? "Abbrechen" : "Fahrt erfassen"}</button>`;
|
||||
}
|
||||
/* Jahre laufen absteigend, Monate und Zeilen liefen bis zur Designpruefung
|
||||
2026-08-30 aufsteigend - in derselben Liste zwei Richtungen, und die
|
||||
neueste Fahrt stand ganz unten, ausserhalb des sichtbaren Bereichs.
|
||||
neuesteZuerst() dreht Zeilen und Monatsreihenfolge um; der zuerst
|
||||
aufgeklappte Monat (mi === 0) ist damit automatisch der neueste. */
|
||||
function neuesteZuerst(liste, feld) {
|
||||
return liste.slice().sort((a, b) => new Date(b[feld]) - new Date(a[feld]));
|
||||
}
|
||||
|
||||
function vTrips() {
|
||||
const jahre = [...new Set(TRIPS.map((t) => new Date(t.ts_start).getFullYear()))].sort((a, b) => b - a);
|
||||
/* D5: Leerzustand nennt die Ursache - die Fahrtenerkennung greift erst, wenn
|
||||
@@ -3183,7 +3290,7 @@ function vTrips() {
|
||||
${vTripsFormular()}`;
|
||||
let h = `<div class="tile">`;
|
||||
jahre.forEach((j, ji) => {
|
||||
const tj = TRIPS.filter((t) => new Date(t.ts_start).getFullYear() === j);
|
||||
const tj = neuesteZuerst(TRIPS.filter((t) => new Date(t.ts_start).getFullYear() === j), "ts_start");
|
||||
h += `<button class="acc-h" aria-expanded="${ji === 0}" data-acc="y${j}"><span class="mark"></span>
|
||||
<span class="k">${j}</span><span class="v">${de(sum(tj, (t) => t.distance_km || 0))} km<br>${tj.length} Fahrten</span></button>
|
||||
<div class="acc-b ${ji === 0 ? "on" : ""}" id="y${j}">`;
|
||||
@@ -3244,9 +3351,13 @@ function vTrip(id) {
|
||||
|
||||
function quad(t, v) { return `<span class="label" style="margin-top:20px">${t}</span>
|
||||
<div class="quad">${v.map((x) => `<div><div class="n">${x[0]}</div><div class="l">${x[1]}</div></div>`).join("")}</div>`; }
|
||||
/* Der Kachelkopf traegt seit der Designpruefung 2026-08-30 denselben
|
||||
drehenden Pfeil wie die Aufklapp-Zeilen in Fahrten und Tanken. Vorher sah
|
||||
die Statistik aus wie fuenf feste Anzeigen - dass sich dahinter die
|
||||
gesamte Auswertung oeffnet, war an nichts zu erkennen. */
|
||||
function statTile(id, label, fig, unit, extra, body) {
|
||||
return `<div class="tile"><button class="tile-h" aria-expanded="false" data-acc="${id}">
|
||||
<span class="label">${label}</span>
|
||||
<span class="stat-kopfzeile"><span class="label">${label}</span><span class="mark"></span></span>
|
||||
<div style="display:flex;align-items:flex-end;justify-content:space-between;gap:14px;margin-top:12px">
|
||||
<div class="fig" style="font-size:34px">${fig}<span class="unit">${unit}</span></div>
|
||||
<span class="wert" style="padding-bottom:5px">${extra}</span></div>
|
||||
@@ -3639,7 +3750,7 @@ function vFuel() {
|
||||
${vFuelFormular()}`;
|
||||
let h = `<div class="tile">`;
|
||||
jahre.forEach((j, ji) => {
|
||||
const fj = FILLS.filter((f) => new Date(f.ts).getFullYear() === j);
|
||||
const fj = neuesteZuerst(FILLS.filter((f) => new Date(f.ts).getFullYear() === j), "ts");
|
||||
const ersparnisJahr = sum(fj, (f) => f.discount || 0);
|
||||
/* D2: Auf der Jahreszeile stehen nur die Kosten, groß. Preis und Menge
|
||||
folgen als Zweitzeile, die Ersparnis als neutrale Pille - vorher
|
||||
@@ -3649,7 +3760,7 @@ function vFuel() {
|
||||
<span class="v" style="display:flex;flex-direction:column;align-items:flex-end;gap:5px">
|
||||
<span style="font-size:17px;color:var(--fg)">${eur(sum(fj, (f) => f.fuel_total_eur || 0))} €</span>
|
||||
<span>${de(sum(fj, (f) => f.liters || 0), 1)} l · Ø ${de(schnittpreis(fj), 2)} €/l</span>
|
||||
${CAR.smartdeal.aktiv ? `<span class="marke"><span class="pill" style="font-size:11.5px;padding:4px 10px">${markenlogo()}<span style="margin-left:6px">−${eur(ersparnisJahr)} €</span></span></span>` : ""}
|
||||
${CAR.smartdeal.aktiv ? `<span class="marke"><span class="pill" style="font-size:12.5px;padding:4px 10px">${markenlogo()}<span style="margin-left:6px">−${eur(ersparnisJahr)} €</span></span></span>` : ""}
|
||||
</span></button>
|
||||
<div class="acc-b ${ji === 0 ? "on" : ""}" id="fy${j}">`;
|
||||
const monate = [...new Set(fj.map((f) => new Date(f.ts).toLocaleDateString("de-DE", { month: "long" })))];
|
||||
@@ -4062,7 +4173,7 @@ function vDatensatzPopup() {
|
||||
<input type="file" accept="${art === "fahrzeugprofil" ? "application/json" : "text/csv"}"
|
||||
data-datensatzladen="${art}" hidden ${datensatzLaeuft ? "disabled" : ""}></label>`
|
||||
).join("")}
|
||||
${datensatzErgebnis ? `<div style="margin-top:14px;font-size:13.5px;line-height:1.6;color:var(--fg)">${esc(datensatzErgebnisText(datensatzErgebnis))}</div>` : ""}
|
||||
${datensatzErgebnis ? `<div style="margin-top:14px;font-size:13px;line-height:1.6;color:var(--fg)">${esc(datensatzErgebnisText(datensatzErgebnis))}</div>` : ""}
|
||||
${datensatzFehler ? `<span class="label" style="margin-top:10px;color:var(--red)">${esc(datensatzFehler)}</span>` : ""}
|
||||
<button class="aktion primaer" style="margin-top:16px" data-datensatzzu>Fertig</button>
|
||||
</div>`;
|
||||
@@ -4423,6 +4534,9 @@ const go = (name, id) => {
|
||||
// Ein offenes Bearbeiten-Formular gehört zu genau der Fahrt, auf der es
|
||||
// geöffnet wurde - sonst begrüßt die nächste Fahrt einen mit Eingabefeldern.
|
||||
fahrtBearbeitenOffen = false;
|
||||
// Gleiches gilt für "Daten bearbeiten" auf Identität und Technik: wer die
|
||||
// Seite verlässt, soll sie beim nächsten Mal wieder lesend vorfinden.
|
||||
if (name !== "ident") identBearbeitenOffen = false;
|
||||
/* B3: echter Verlauf statt statischer ZURUECK-Tabelle. Ein Tabwechsel setzt
|
||||
den Stapel zurück, weil Tabs Wurzeln sind, keine Ebenen. */
|
||||
if (istTab(name)) routeStack = [];
|
||||
@@ -4433,6 +4547,7 @@ const go = (name, id) => {
|
||||
function zurueck() {
|
||||
sheet = null;
|
||||
fahrtBearbeitenOffen = false;
|
||||
identBearbeitenOffen = false;
|
||||
const ziel = routeStack.pop() || { name: ZURUECK[route.name] || "home" };
|
||||
navRichtung = "raus";
|
||||
route = ziel; render();
|
||||
@@ -5107,6 +5222,31 @@ function ereignisseVerdrahten() {
|
||||
if (dsExport) { datensatzExportieren(dsExport.dataset.datensatzsichern); return; }
|
||||
const del = e.target.closest("[data-loeschen]");
|
||||
if (del) { delete CAR.service.vereinbart[del.dataset.loeschen]; profilSpeichern(); render(); return; }
|
||||
/* Identität und Technik: Bearbeitungsansicht ein/aus, Positionen der
|
||||
Technik- und Ausstattungsgruppen anlegen/entfernen. */
|
||||
if (e.target.closest("[data-identbearbeiten]")) { identBearbeitenOffen = !identBearbeitenOffen; render(); return; }
|
||||
const tkdel = e.target.closest("[data-technikdel]");
|
||||
if (tkdel) {
|
||||
const [gi, i] = tkdel.dataset.technikdel.split("|").map(Number);
|
||||
CAR.technik[gi].posten.splice(i, 1); profilSpeichern(); render(); return;
|
||||
}
|
||||
const tkadd = e.target.closest("[data-technikadd]");
|
||||
if (tkadd) {
|
||||
const g = CAR.technik[+tkadd.dataset.technikadd];
|
||||
(g.posten = g.posten || []).push(["Neue Angabe", ""]);
|
||||
profilSpeichern(); render(); return;
|
||||
}
|
||||
const asdel = e.target.closest("[data-ausstattungdel]");
|
||||
if (asdel) {
|
||||
const [gi, i] = asdel.dataset.ausstattungdel.split("|").map(Number);
|
||||
CAR.ausstattung[gi].sonder.splice(i, 1); profilSpeichern(); render(); return;
|
||||
}
|
||||
const asadd = e.target.closest("[data-ausstattungadd]");
|
||||
if (asadd) {
|
||||
const g = CAR.ausstattung[+asadd.dataset.ausstattungadd];
|
||||
(g.sonder = g.sonder || []).push("");
|
||||
profilSpeichern(); render(); return;
|
||||
}
|
||||
const vseldel = e.target.closest("[data-vselbstdel]");
|
||||
if (vseldel) { CAR.versicherung.selbst.splice(+vseldel.dataset.vselbstdel, 1); profilSpeichern(); render(); return; }
|
||||
if (e.target.closest("[data-vselbstadd]")) { CAR.versicherung.selbst.push(["", ""]); profilSpeichern(); render(); return; }
|
||||
@@ -5409,6 +5549,21 @@ function ereignisseVerdrahten() {
|
||||
if (vnotruf) { CAR.versicherung[vnotruf] = e.target.value; profilSpeichern(); render(); return; }
|
||||
const vvertrag = e.target.dataset.vvertrag;
|
||||
if (vvertrag) { CAR.versicherung[vvertrag] = e.target.value; profilSpeichern(); render(); return; }
|
||||
/* Kein render() beim Tippen: der Cursor säße sonst nach jedem Zeichen
|
||||
wieder am Feldanfang - dieselbe Begründung wie beim Setup-Suchfeld und
|
||||
beim Tankpreisfeld weiter oben. */
|
||||
const technik = e.target.dataset.technik;
|
||||
if (technik) {
|
||||
const [gi, i] = technik.split("|").map(Number);
|
||||
CAR.technik[gi].posten[i][1] = e.target.value;
|
||||
profilSpeichern(); return;
|
||||
}
|
||||
const ausstattung = e.target.dataset.ausstattung;
|
||||
if (ausstattung) {
|
||||
const [gi, i] = ausstattung.split("|").map(Number);
|
||||
CAR.ausstattung[gi].sonder[i] = e.target.value;
|
||||
profilSpeichern(); return;
|
||||
}
|
||||
const vselbst = e.target.dataset.vselbst;
|
||||
if (vselbst) {
|
||||
const [i, feld] = vselbst.split("|");
|
||||
@@ -5719,6 +5874,8 @@ class AudiDashboardPanel extends HTMLElement {
|
||||
Reload. Vorher stand die App nach jedem Neuladen wieder auf Nacht. */
|
||||
HOST.dataset.theme = HOST.dataset.theme || themeGewaehlt();
|
||||
|
||||
schriftenLaden();
|
||||
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = `${STATIK}/audi-dashboard.css?v=${CSS_VERSION}`;
|
||||
|
||||
@@ -38,7 +38,13 @@
|
||||
--tile-2:#EFEFF4;
|
||||
--line:rgba(60,60,67,.13);
|
||||
--line-strong:rgba(60,60,67,.24);
|
||||
--fg:#000000; --fg2:#3C3C43; --fg3:#8E8E93;
|
||||
/* --fg3 traegt jede Kachelueberschrift, jede Einheit und jeden Zusatz.
|
||||
Auf hellem Grund lag #8E8E93 bei 2,92:1 gegen die Seitenflaeche und
|
||||
3,26:1 gegen die Kachel - fuer einen kurzen Blick im Auto bei
|
||||
Sonnenlicht zu wenig (Designpruefung 2026-08-30). #6B6B70 bringt beide
|
||||
auf 4,75:1 bzw. 5,30:1, ohne den ruhigen Gesamteindruck zu aendern.
|
||||
Der Nachtwert bleibt #8E8E93 - dort sind es ohnehin 5,86:1. */
|
||||
--fg:#000000; --fg2:#3C3C43; --fg3:#6B6B70;
|
||||
--ok:#34C759; --warn:#FF9F0A; --bad:#FF3B30;
|
||||
--ios-sep:rgba(60,60,67,.16);
|
||||
--ios-fill:rgba(120,120,128,.16);
|
||||
@@ -102,7 +108,7 @@ html,body{height:100%}
|
||||
.phone:has(.back.on) .topbar{padding:54px 16px 6px;gap:8px}
|
||||
.phone:has(.back.on) .head{align-items:center}
|
||||
.phone:has(.back.on) .title{font-size:17px;font-weight:400;letter-spacing:-.01em;text-align:center}
|
||||
.phone:has(.back.on) .sync{margin-top:2px;font-size:11.5px}
|
||||
.phone:has(.back.on) .sync{margin-top:2px;font-size:12.5px}
|
||||
|
||||
main#view{--seitenrand:16px;padding:0 var(--seitenrand) 30px;scroll-behavior:smooth}
|
||||
|
||||
@@ -195,7 +201,7 @@ main#view{--seitenrand:16px;padding:0 var(--seitenrand) 30px;scroll-behavior:smo
|
||||
.switch input:checked+.track{background:var(--ok)}
|
||||
.switch input:checked+.track::before{transform:translateX(20px)}
|
||||
|
||||
.pill{font-size:12px;letter-spacing:.01em;text-transform:none;padding:5px 11px;
|
||||
.pill{font-size:12.5px;letter-spacing:.01em;text-transform:none;padding:5px 11px;
|
||||
border:0;background:var(--ios-fill);color:var(--fg2)}
|
||||
|
||||
.status{padding:14px 0 2px}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"domain": "audi_dashboard",
|
||||
"name": "Audi Dashboard",
|
||||
"version": "2026.8.30.2",
|
||||
"version": "2026.8.30.8",
|
||||
"documentation": "https://gitea.nothaft.cloud/paul/audi-app/src/branch/main/README.md",
|
||||
"issue_tracker": "https://gitea.nothaft.cloud/paul/audi-app/issues",
|
||||
"codeowners": ["@paul"],
|
||||
|
||||
Reference in New Issue
Block a user