diff --git a/AGENTS.md b/AGENTS.md index 5a53c0f..b230402 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,7 +13,11 @@ two-tone pin+car icon — see section C; a third round the same day found and fi "fragmented Leaflet rendering" defect at its root — the Leaflet stylesheet was loaded into `document.head` and therefore never reached the panel's shadow root — plus light-only map tiles, the CI `poi-car` marker, the red frame on list rows, the select-field grey box, and two more -generic-receipt-parser gaps). This file is the entry point for every new agent +generic-receipt-parser gaps; a sixth round the same day fixed the map pins' real visibility problem +(the CI `poi-car`/`poi` icons are thin outline-only paths, only 13-40% filled — solved with a solid +silhouette layer extracted from each icon's own outer contour, not a redraw), applied a batch of +~20 user-reported UI polish items against Apple's Human Interface Guidelines, some via a guided +Q&A, and lowered the battery-voltage statistic's cutoff from 13.2V to 12.8V). This file is the entry point for every new agent session: what this repo is, what is finished, what is missing, and how to work here. Detail lives in the linked documents — this file points, it does not duplicate. @@ -836,6 +840,92 @@ wraps the web app for iPhone; a PWA home-screen install is the accepted intermed app re-renders on each backend push (~30 s), rebuilding the map and re-centring it. Panning the map from the console and checking later therefore proves nothing — spy on `L.Map.prototype.flyTo` instead. +- [x] Sixth round the same day (2026-08-16) — a large batch of user-reported UI polish items, plus + the map pins' real visibility root cause: + (1) **Map pins were genuinely near-invisible, not just a styling nit.** The user reported the + vehicle's map pin looked "transparent"; reproduced empirically (not by eye) by rasterizing the + live marker's SVG to a canvas and sampling alpha — only ~13% of the icon's own bounding box had + any ink, and the exact center pixel was fully transparent. Root cause: `CI.poiCarL`/`poiCar` + (and `poiL`/`poiS`, used for the Einzelbeleg station pin) are pure **contour** forms — the + balloon outline is drawn as two nested, oppositely-wound paths that cancel to a 1px ring under + the default nonzero fill rule, plus thin interior detail lines; there is no filled area at all. + A first fix (solid navy circle behind just the icon's round "head", via `::before`) was + explicitly rejected by the user ("I want the whole icon solid, not just the car" / "make the + needle opaque") — correct, since it only covered ~36% of the icon and left the pointed tip as a + bare outline. Real fix: each icon's `d` attribute is multiple sub-paths (split at top-level + M/m); the **first** sub-path alone is already the complete, correct outer balloon silhouette + (verified by rasterizing it in isolation — solid center pixel, 36-41% fill ratio, matching a + normal teardrop-in-square ratio). Extracted that first sub-path verbatim (no redrawing) into + four new `CI.poiCarLSil`/`poiCarSil`/`poiLSil`/`poiSSil` constants, fixed-color-filled (not + `currentColor`), and `fahrzeugMarkerSVG()`/`tankstellenMarkerSVG()` now render it as the bottom + layer behind the original detailed icon; `.fahrzeug-pin`'s color switched from dark navy to + white so the original outline/detail lines read against the new solid fill, exactly like the + white-glyph-on-solid-teardrop convention of Google/Apple Maps pins. Applies uniformly to both + marker types now (station pin included, per explicit user request), so the earlier per-variant + `.auto` CSS modifier and its circle-position math were removed again as dead weight. + (2) **Battery voltage statistic cutoff lowered 13.2V → 12.8V** (`AGM_RUHE_MAX_V` in + `audi-dashboard-app.js`) — user's point: anything above ~12.8V (full-charge resting voltage per + the existing in-code research citation) is already alternator output, not the battery's own + state, so admitting up to 13.2V let charging-tail values distort the charge-state stats. + (3) **Battery chart Y-axis no longer "stretches."** `bvZeichnen()` recomputed `yMin`/`yMax` from + whatever points were currently zoomed into (min 0.4V span + 15% pad) on every redraw, so the + axis rescaled on every pan/zoom gesture. Now computed once from the full dataset in + `vBatterieverlauf()` (`bvYDomain`) and reused unchanged across zoom/pan. + (4) Removed two explanatory paragraphs from the Batteriespannung detail view ("Näherung auf + Basis…" and "Ziehen zum Verschieben…") per explicit request. + (5) **Tankfüllung now shows "X % / X l"** (`vAudi()`) instead of a literal-litre primary value + with a redundant "100 % von 58 l" sub-line. + (6) Removed the "· noch etwa X l im Tank" suffix from the Übersicht's "Reichweite" label + (`vHome()`); the now-unused `liter` local was removed with it. + (7) **Active/primary buttons are grey again, not red** — `.aktion.primaer` in + `audi-dashboard-ios.css` filled with `--ios-tint` (red) since the 2026-08-13 iOS-overlay + decision; explicit user request to drop that and match the base stylesheet's neutral + `var(--fg)`/`var(--canvas)` fill. Destructive actions (`.aktion.loeschen`) intentionally stay + red — Apple's own HIG reserves red specifically for destructive actions, so this one use is + correct per the guideline, not just left over. + (8) **` @@ -1957,8 +1978,7 @@ function vEinst() { ? `
Laufleistung
${de(CAR.oel.herstellerKm)} km
Zeit
${CAR.oel.herstellerMonate} Monate
-
- Aus dem Fahrzeug gelesen` + ` : `
@@ -2329,13 +2349,11 @@ function vReifen() {
` : ""} +
${k === "sommer" ? "Sommer" : "Winter"}
${t.km != null ? de(t.km) : "–"}km
-
- -
${feld(k, "marke", "Hersteller")} ${feld(k, "modell", "Modell")} diff --git a/homeassistant/installationspaket/www/audi-dashboard-ios.css b/homeassistant/installationspaket/www/audi-dashboard-ios.css index aa1114e..4312794 100644 --- a/homeassistant/installationspaket/www/audi-dashboard-ios.css +++ b/homeassistant/installationspaket/www/audi-dashboard-ios.css @@ -122,14 +122,15 @@ main#view{--seitenrand:16px;padding:0 var(--seitenrand) 30px;scroll-behavior:smo letter-spacing:0;text-transform:none;color:var(--fg2)} .seg button.on{background:var(--tile-2);color:var(--fg);box-shadow:0 1px 3px rgba(0,0,0,.25)} -/* Rot bleibt Akzent/Primäraktion/destruktiv, nicht Flächenfarbe jeder Aktion - (Design-Review 2026-08-13 §B): .aktion allein ist die neutrale - Sekundäraktion, .primaer die einzige rot gefüllte Fläche. */ +/* Aktive/Primär-Buttons sind grau, nicht rot (Nutzerwunsch 2026-08-16): Rot + bleibt nur noch für destruktive Aktionen (.loeschen). .aktion allein ist + die neutrale Sekundäraktion, .primaer die grau gefüllte Hauptaktion - + dieselbe Fläche wie die Grundauflage (var(--fg)/var(--canvas)). */ .aktion{margin-top:18px;padding:15px;border:0;border-radius:14px; background:var(--ios-fill);color:var(--fg);font-size:16px;font-weight:400; letter-spacing:0;text-transform:none} .aktion:hover{background:var(--tile-2)} -.aktion.primaer{background:var(--ios-tint);color:#fff} +.aktion.primaer{background:var(--fg);color:var(--canvas)} .aktion.primaer:hover{filter:brightness(1.08)} .aktion.loeschen{background:var(--ios-fill);color:var(--bad);border:0} .aktion.loeschen:hover{background:var(--bad);color:#fff;filter:none} @@ -151,6 +152,18 @@ main#view{--seitenrand:16px;padding:0 var(--seitenrand) 30px;scroll-behavior:smo .feld input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]), .feld select{background:var(--ios-fill);padding:8px 10px} .feld input:focus,.feld select:focus{color:var(--fg)} +/* Pull-down-Button-Optik (Apple HIG): ein einzelner Abwaerts-Chevron statt + des (durch appearance:none in audi-dashboard.css bereits entfernten) + nativen Browser-Pfeils - macht die Auswahlfelder als solche erkennbar, + ohne ein eigenes Menue-Widget nachzubauen. Farbe fix auf --ios-grau, das + ist bereits die Farbe aller anderen Chevrons (.chev) in beiden Themes. */ +.feld select{ + padding-right:28px; + background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5l3.5 3.5 3.5-3.5' fill='none' stroke='%238E8E93' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); + background-repeat:no-repeat; + background-position:right 9px center; + background-size:10px 10px; +} .notiz{background:var(--ios-fill);border:0;border-radius:12px;font-size:16px} .switch{width:51px;height:31px} @@ -201,6 +214,13 @@ main#view{--seitenrand:16px;padding:0 var(--seitenrand) 30px;scroll-behavior:smo .tab.on{color:var(--fg);border-top-color:transparent} .tab.on .tabpille{background:rgba(255,255,255,.14)} :host([data-theme="tag"]) .tab.on .tabpille{background:rgba(0,0,0,.07)} +/* Ist die Beschriftung sichtbar (nicht .tabbar.ohne), soll die graue Flaeche + Icon UND Text umschliessen statt nur die enge Pille ums Icon - die Flaeche + wandert dafuer vom Icon-Symbol auf den ganzen Tab-Knopf. Im reinen + Icon-Modus bleibt die enge Pille wie zuvor. */ +.tabbar:not(.ohne) .tab.on{background:rgba(255,255,255,.14);border-radius:14px} +:host([data-theme="tag"]) .tabbar:not(.ohne) .tab.on{background:rgba(0,0,0,.07)} +.tabbar:not(.ohne) .tab.on .tabpille{background:none} .tabbar.ohne .tab{padding:11px 2px 10px} :focus-visible{outline:2px solid var(--ios-tint);outline-offset:2px} @@ -254,9 +274,9 @@ main#view{--seitenrand:16px;padding:0 var(--seitenrand) 30px;scroll-behavior:smo .tabpille{width:auto;height:auto;border-radius:0;background:none} .tab.on .tabpille{background:none} .tab:hover{background:var(--tile)} - /* Aktive Navigation: Rot bleibt Text-/Icon-Akzent, die Fläche wird neutral - statt rosa hinterlegt (Design-Review §B - Rot nicht als Flächenfarbe). */ - .tab.on{background:var(--ios-fill);color:var(--ios-tint)} + /* Aktives Symbol: dieselbe Farbe wie die Kopfzeile (--fg), nicht mehr Rot - + Fläche bleibt neutral hinterlegt statt rosa (Design-Review §B). */ + .tab.on{background:var(--ios-fill);color:var(--fg)} .tabbar.ohne .tab span{display:block} .tabbar.ohne .tab{padding:12px 14px;gap:14px} .tabbar.ohne .tab svg{width:22px;height:22px} diff --git a/homeassistant/installationspaket/www/audi-dashboard.css b/homeassistant/installationspaket/www/audi-dashboard.css index ad1ab74..ba4b87f 100644 --- a/homeassistant/installationspaket/www/audi-dashboard.css +++ b/homeassistant/installationspaket/www/audi-dashboard.css @@ -148,7 +148,7 @@ align-items: center; gap: 6px; margin-top: 4px; - font-size: 10.5px; + font-size: 11px; color: var(--fg3); white-space: nowrap; } @@ -443,7 +443,10 @@ button.tile, .tilebtn { transition: background .15s, transform .1s; } .carfix { width: 100%; aspect-ratio: 16 / 9; } .carfix.klein { aspect-ratio: 16 / 8; } .carfix.mini { width: 78px; height: 78px; aspect-ratio: auto; } -.radbild { width: 96px; height: 96px; aspect-ratio: auto; border-radius: 50%; } +/* Reifenfoto ist oft eine breite Aufnahme; statt beide Ränder symmetrisch + wegzuschneiden (object-fit:cover-Standard), bleibt bewusst der rechte Rand + des Originalfotos erhalten - dort sitzt das Rad meist im Bild. */ +.radbild { width: 96px; height: 96px; aspect-ratio: auto; border-radius: 50%; object-position: right center; } .bildbox { position: relative; width: 100%; aspect-ratio: 4 / 3; border-radius: 12px; overflow: hidden; } .bildbox img { display: block; width: 100%; height: 100%; object-fit: cover; } @@ -521,7 +524,18 @@ button.tile, .tilebtn { transition: background .15s, transform .1s; } appearance: none; } .feld input:focus, .feld select:focus, .notiz:focus { outline: none; border-color: var(--red); } -.feld select { padding-right: 30px; background-image: none; } +/* Pull-down-Button-Optik (Apple HIG): einzelner Abwaerts-Chevron statt des + durch appearance:none oben entfernten nativen Browser-Pfeils. */ +.feld select { + padding-right: 30px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5l3.5 3.5 3.5-3.5' fill='none' stroke='%238a94a3' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 11px center; + background-size: 10px 10px; +} +:host([data-theme=tag]) .feld select { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5l3.5 3.5 3.5-3.5' fill='none' stroke='%23666666' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); +} .feld > span { flex: 0 1 auto; min-width: 0; } .mitEinheit { display: inline-flex; align-items: center; gap: var(--sp-2); max-width: 100%; } .mitEinheit input { min-width: 0; width: 96px; text-align: right; } @@ -713,16 +727,20 @@ button.tile, .tilebtn { transition: background .15s, transform .1s; } } .fahrzeug-pin-wrap { background: none; border: none; } -/* poi-car aus dem CI-Satz ist eine reine Konturform in currentColor - auf - Kartenkacheln waere sie ohne Trennung zum Untergrund kaum lesbar. Die - gestapelten weissen drop-shadows ziehen deshalb einen Halo um die Kontur, - der letzte Schatten gibt Tiefe. Feste Farbe statt Theme-Variable, damit die - Nadel in Tag- und Nachtansicht gleich aussieht. */ +/* poi-car/poi aus dem CI-Satz sind reine Konturformen (Ring aus zwei + gegenlaeufigen Randlinien + duenne Detaillinien) - eine Pixelprobe ergab + nur 13-40% gefuellte Flaeche in der eigenen Bounding-Box und war auf + Kartenkacheln praktisch unsichtbar (Nutzer-Feedback "Pin ist transparent"). + fahrzeugMarkerSVG()/tankstellenMarkerSVG() rendern deshalb zusaetzlich eine + Vollton-Silhouette (CI.*Sil, exakt der aeussere Ballon-Umriss desselben + CI-Pfads, keine Neuzeichnung) als unterste Ebene; die Iconfarbe hier ist + deshalb weiss statt dunkel, damit Umriss und Detaillinien auf der jetzt + massiven Flaeche lesbar bleiben. Feste Farben statt Theme-Variablen, damit + die Nadeln in Tag- und Nachtansicht gleich aussehen. */ .fahrzeug-pin { display: flex; align-items: center; justify-content: center; - color: #182634; - filter: drop-shadow(0 0 1px #fff) drop-shadow(0 0 1px #fff) - drop-shadow(0 0 2px #fff) drop-shadow(0 2px 4px rgba(0,0,0,.4)); + color: #fff; + filter: drop-shadow(0 2px 4px rgba(0,0,0,.4)); } .user-pin-wrap { background: none; border: none; } .user-pin { @@ -856,6 +874,30 @@ button.tile, .tilebtn { transition: background .15s, transform .1s; } .radkopf { display: flex; flex-direction: column; margin-top: var(--sp-4); } +/* Kompakte Pille statt voller Breite (Apple-HIG-Pull-down-Maß): oben rechts + in der Kachel, obere Kante auf Höhe des Radfotos, rechter Abstand + identisch zum linken Texteinzug (beides var(--sp-5), die Kachel-Innen- + polsterung). */ +.montiert { + position: absolute; top: var(--sp-5); right: var(--sp-5); + display: inline-flex; align-items: center; justify-content: center; + font-family: inherit; font-size: 12px; letter-spacing: normal; + color: var(--fg2); + background: none; + border: 1px solid var(--line-strong); + border-radius: var(--r-pill); + padding: 7px 13px; + cursor: pointer; + transition: background .15s, color .15s, border-color .15s, transform .1s; +} +/* Optisch bleibt die Pille klein, die Tippflaeche wird per unsichtbarem + Pseudo-Element auf Apple-HIG-Mindestmass 44x44pt gebracht (Klick auf die + Flaeche des ::before zaehlt als Klick auf den echten Button). */ +.montiert::before { content: ""; position: absolute; top: -8px; bottom: -8px; left: 0; right: 0; } +.montiert:hover { background: var(--shade); } +.montiert:active { transform: scale(.96); background: var(--shade); } +.montiert.on { background: var(--fg); border-color: var(--fg); color: var(--canvas); } + /* ------------------------------------------------- B4: Action Sheet Ersetzt confirm()/alert(). Von unten eingeblendet, destruktive Zeile rot, Abbrechen abgesetzt - iOS-Muster. */ diff --git a/homeassistant/www/audi-dashboard-app.js b/homeassistant/www/audi-dashboard-app.js index 42ef544..3f4133a 100644 --- a/homeassistant/www/audi-dashboard-app.js +++ b/homeassistant/www/audi-dashboard-app.js @@ -560,7 +560,9 @@ function standortBekannt() { return CAR.standortLat != null && CAR.standortLon ! function fahrzeugMarkerSVG(px = 34) { const gross = px >= 34; const box = gross ? 48 : 24; - return ``; + const sil = gross ? CI.poiCarLSil : CI.poiCarSil; + const icon = gross ? CI.poiCarL : CI.poiCar; + return ``; } /* Tankstellenposition im Einzelbeleg - dieselbe Nadelform wie beim Fahrzeug, @@ -569,7 +571,9 @@ function fahrzeugMarkerSVG(px = 34) { function tankstellenMarkerSVG(px = 32) { const gross = px >= 34; const box = gross ? 48 : 24; - return ``; + const sil = gross ? CI.poiLSil : CI.poiSSil; + const icon = gross ? CI.poiL : CI.poiS; + return ``; } /* Fahrzustand fürs Menü: "fährt" solange die aktuelle Fahrt noch offen ist @@ -928,6 +932,20 @@ const CI = { poiL: '', poiS: '', poiCarL: '', + /* Vollton-Silhouetten fuer die Kartennadeln: poi-car/poi sind reine Kontur- + formen (Ring aus zwei gegenlaeufigen Randlinien + duenne Detaillinien im + Inneren) - eine Pixelprobe ergab nur 13-40% gefuellte Flaeche und war auf + Kartenkacheln praktisch unsichtbar (Nutzer-Feedback "Pin ist transparent/ + durchsichtig"). Jede Silhouette ist exakt das erste Teilpfad-Segment des + jeweiligen CI-Pfads oben (die aeussere Ballonform, vor dem Punkt, der die + Ring-Innenlinie startet) - keine Neuzeichnung, nur der bereits im CI-Satz + enthaltene Umriss, mit fester Farbe statt currentColor gefuellt. Wird in + fahrzeugMarkerSVG()/tankstellenMarkerSVG() als unterste Ebene hinter dem + Original-Icon (dann weiss statt dunkel) gerendert. */ + poiCarLSil: '', + poiCarSil: '', + poiLSil: '', + poiSSil: '', selectAll: '', planRoute: '', upload: '', @@ -1157,8 +1175,6 @@ function vHome() { const statusText = g === null ? "Status unbekannt" : g ? "Sicher abgestellt" : "Nicht sicher abgestellt"; const statusDot = g === null ? "warn" : g ? "" : "bad"; const pct = CAR.tankPct; - const balkenFarbe = pct <= 10 ? "var(--bad)" : pct <= 25 ? "var(--warn)" : "var(--ok)"; - const liter = CONFIG.tankvolumen ? Math.round((CONFIG.tankvolumen * pct) / 100) : null; const t = naechsterTermin(); /* C2/C5/D1: Reihenfolge der myAudi-App - randloses Fahrzeugbild, Name und Status, große Reichweite mit farbigem Balken, dann Aktionskacheln. Die @@ -1180,8 +1196,8 @@ function vHome() {
${CAR.reichweite != null ? de(CAR.reichweite) : "–"}km
${CAR.tankBekannt ? pct + " %" : "–"}
-
- Reichweite${CAR.tankBekannt && liter != null ? ` · noch etwa ${de(liter)} l im Tank` : ""} +
+ Reichweite
Kilometerstand @@ -1262,7 +1278,7 @@ function vAudi() {
Zustand
Kilometerstand
${CAR.odoBekannt ? de(CAR.odo) + " km" : "unbekannt"}
-
Tankfüllung
${de(CONFIG.tankvolumen * CAR.tankPct / 100, 1)} l${CAR.tankPct} % von ${CONFIG.tankvolumen} l
+
Tankfüllung
${CAR.tankPct} % / ${de(CONFIG.tankvolumen * CAR.tankPct / 100, 1)} l
Batteriespannung
${CAR.batteriespannung != null ? de(CAR.batteriespannung, 1) + " V" : "unbekannt"}
@@ -1324,7 +1340,7 @@ function vAudi() { Ziehen mit einem Finger, Antippen wählt den nächstgelegenen Messpunkt. bvZeichnen() aktualisiert nur die SVG/Tooltip-Inhalte (kein render()), damit Zoom/Pan flüssig bleiben. */ -let bvVollDomain = null, bvDomain = null, bvPunkte = [], bvAusgewaehlt = null; +let bvVollDomain = null, bvDomain = null, bvPunkte = [], bvAusgewaehlt = null, bvYDomain = null; const bvZeiger = new Map(); // pointerId -> {x,y}, für Pinch (2 Finger) vs. Pan (1 Finger) let bvGestStart = null; // {type:"pan"|"pinch", ...Ausgangswerte der Geste} let bvTapKandidat = null, bvBewegtSeit = false; @@ -1345,8 +1361,12 @@ const kurzdat = (d) => d.toLocaleDateString("de-DE", { day: "2-digit", month: "2 Moment kurz nach dem Start, bevor der Alternator hochfährt, und ist damit die für den Ladezustand aussagekräftige Größe. Tage, an denen selbst das Minimum über der Grenze liegt (Fahrzeug nie im Ruhezustand beobachtet), - tauchen entsprechend nicht in der Ladezustands-Statistik auf. */ -const AGM_RUHE_MAX_V = 13.2; + tauchen entsprechend nicht in der Ladezustands-Statistik auf. Die Grenze + liegt bei 12,8 V (voller Ruhezustand laut obiger Recherche) statt z. B. + 13,2 V, weil alles darüber bereits vom Generator stammt, nicht von der + Batterie selbst - solche Werte würden den Ladezustand künstlich zu gut + aussehen lassen. */ +const AGM_RUHE_MAX_V = 12.8; const BV_SOC_TABELLE = [ [10.5, 0], [11.8, 10], [11.9, 20], [12.0, 30], [12.1, 40], [12.2, 50], [12.4, 60], [12.5, 70], [12.6, 80], [12.7, 90], [12.8, 100], @@ -1429,6 +1449,17 @@ function vBatterieverlauf() { const genug = bvPunkte.length >= 2; bvVollDomain = genug ? [bvPunkte[0].t, bvPunkte[bvPunkte.length - 1].t] : null; bvDomain = genug ? [...bvVollDomain] : null; + // Y-Achse einmalig aus allen Punkten festlegen, nicht bei jedem Zoom/Pan + // neu aus den gerade sichtbaren - sonst "streckt" sich die Achse bei jeder + // Geste neu auf den jeweils sichtbaren Min/Max-Ausschnitt. + if (genug) { + let yMin = Math.min(...bvPunkte.map((p) => p.v)), yMax = Math.max(...bvPunkte.map((p) => p.v)); + if (yMax - yMin < 0.4) { const mitte = (yMax + yMin) / 2; yMin = mitte - 0.2; yMax = mitte + 0.2; } + const pad = (yMax - yMin) * 0.15; + bvYDomain = [yMin - pad, yMax + pad]; + } else { + bvYDomain = null; + } const stufen = bvFarbstufen(); const letzter = bvPunkte.length ? bvPunkte[bvPunkte.length - 1] : null; @@ -1451,8 +1482,6 @@ function vBatterieverlauf() {
- Ziehen zum Verschieben, mit zwei Fingern oder dem Mausrad - zoomen, auf einen Punkt tippen für Datum, Uhrzeit sowie Min-/Max-Spannung ` : ` ${leerText} `} @@ -1480,9 +1509,6 @@ function vBatterieverlauf() { : `-`}
${soh.text} - Näherung auf Basis der täglich niedrigsten gemessenen Spannung (aussagekräftig für die - Entladung), keine Kapazitätsmessung - Tageswerte über ${de(AGM_RUHE_MAX_V, 1)} V (Ladevorgang während der Fahrt) fließen nicht ein. - Für eine verlässliche Aussage ist ein Lasttest an der Batterie nötig. `; } @@ -1503,12 +1529,11 @@ function bvPlotRahmen(rect) { function bvZeichnen() { const svg = $("#bvSvg"); - if (!svg || !bvDomain) return; - const sichtbar = bvPunkte.filter((p) => p.t >= bvDomain[0] && p.t <= bvDomain[1]); - const basis = sichtbar.length >= 2 ? sichtbar : bvPunkte; - let yMin = Math.min(...basis.map((p) => p.v)), yMax = Math.max(...basis.map((p) => p.v)); - if (yMax - yMin < 0.4) { const mitte = (yMax + yMin) / 2; yMin = mitte - 0.2; yMax = mitte + 0.2; } - const pad = (yMax - yMin) * 0.15; yMin -= pad; yMax += pad; + if (!svg || !bvDomain || !bvYDomain) return; + // Feste Y-Achse (siehe vBatterieverlauf) statt Neuberechnung aus dem + // gerade sichtbaren Zoom-Ausschnitt, damit die Achse beim Zoomen/Verschieben + // nicht mehr "streckt". + const [yMin, yMax] = bvYDomain; // etwas über den sichtbaren Bereich hinaus zeichnen, damit die Linie am // Rand nicht mitten in der Luft abbricht, sondern zum nächsten (Rand-)Punkt @@ -1520,12 +1545,12 @@ function bvZeichnen() { const gitter = [0, 1, 2, 3].map((i) => { const v = yMin + ((yMax - yMin) * i) / 3, y = bvSkalaY(v, yMin, yMax); return ` - ${de(v, 1)}`; + ${de(v, 1)}`; }).join(""); const xLabels = [0, 0.5, 1].map((f) => { const x = BV_ML + f * (BV_W - BV_ML - BV_MR); const t = bvDomain[0] + f * spanne; - return `${kurzdat(new Date(t))}`; }).join(""); const stufen = bvFarbstufen(); @@ -1930,10 +1955,6 @@ function csvDatei(name, kopf, zeilen) { function vEinst() { return `
Fahrzeug einrichten - - Fahrgestellnummer, Kennzeichen, Erstzulassung, Ausführung und Ölwechsel-Intervall — bei der - Ersteinrichtung oder wenn sich diese Angaben ändern. ${einrichtenOffen ? `
@@ -1957,8 +1978,7 @@ function vEinst() { ? `
Laufleistung
${de(CAR.oel.herstellerKm)} km
Zeit
${CAR.oel.herstellerMonate} Monate
-
- Aus dem Fahrzeug gelesen` + ` : `
@@ -2329,13 +2349,11 @@ function vReifen() {
` : ""} +
${k === "sommer" ? "Sommer" : "Winter"}
${t.km != null ? de(t.km) : "–"}km
-
- -
${feld(k, "marke", "Hersteller")} ${feld(k, "modell", "Modell")} diff --git a/homeassistant/www/audi-dashboard-ios.css b/homeassistant/www/audi-dashboard-ios.css index aa1114e..4312794 100644 --- a/homeassistant/www/audi-dashboard-ios.css +++ b/homeassistant/www/audi-dashboard-ios.css @@ -122,14 +122,15 @@ main#view{--seitenrand:16px;padding:0 var(--seitenrand) 30px;scroll-behavior:smo letter-spacing:0;text-transform:none;color:var(--fg2)} .seg button.on{background:var(--tile-2);color:var(--fg);box-shadow:0 1px 3px rgba(0,0,0,.25)} -/* Rot bleibt Akzent/Primäraktion/destruktiv, nicht Flächenfarbe jeder Aktion - (Design-Review 2026-08-13 §B): .aktion allein ist die neutrale - Sekundäraktion, .primaer die einzige rot gefüllte Fläche. */ +/* Aktive/Primär-Buttons sind grau, nicht rot (Nutzerwunsch 2026-08-16): Rot + bleibt nur noch für destruktive Aktionen (.loeschen). .aktion allein ist + die neutrale Sekundäraktion, .primaer die grau gefüllte Hauptaktion - + dieselbe Fläche wie die Grundauflage (var(--fg)/var(--canvas)). */ .aktion{margin-top:18px;padding:15px;border:0;border-radius:14px; background:var(--ios-fill);color:var(--fg);font-size:16px;font-weight:400; letter-spacing:0;text-transform:none} .aktion:hover{background:var(--tile-2)} -.aktion.primaer{background:var(--ios-tint);color:#fff} +.aktion.primaer{background:var(--fg);color:var(--canvas)} .aktion.primaer:hover{filter:brightness(1.08)} .aktion.loeschen{background:var(--ios-fill);color:var(--bad);border:0} .aktion.loeschen:hover{background:var(--bad);color:#fff;filter:none} @@ -151,6 +152,18 @@ main#view{--seitenrand:16px;padding:0 var(--seitenrand) 30px;scroll-behavior:smo .feld input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]), .feld select{background:var(--ios-fill);padding:8px 10px} .feld input:focus,.feld select:focus{color:var(--fg)} +/* Pull-down-Button-Optik (Apple HIG): ein einzelner Abwaerts-Chevron statt + des (durch appearance:none in audi-dashboard.css bereits entfernten) + nativen Browser-Pfeils - macht die Auswahlfelder als solche erkennbar, + ohne ein eigenes Menue-Widget nachzubauen. Farbe fix auf --ios-grau, das + ist bereits die Farbe aller anderen Chevrons (.chev) in beiden Themes. */ +.feld select{ + padding-right:28px; + background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5l3.5 3.5 3.5-3.5' fill='none' stroke='%238E8E93' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); + background-repeat:no-repeat; + background-position:right 9px center; + background-size:10px 10px; +} .notiz{background:var(--ios-fill);border:0;border-radius:12px;font-size:16px} .switch{width:51px;height:31px} @@ -201,6 +214,13 @@ main#view{--seitenrand:16px;padding:0 var(--seitenrand) 30px;scroll-behavior:smo .tab.on{color:var(--fg);border-top-color:transparent} .tab.on .tabpille{background:rgba(255,255,255,.14)} :host([data-theme="tag"]) .tab.on .tabpille{background:rgba(0,0,0,.07)} +/* Ist die Beschriftung sichtbar (nicht .tabbar.ohne), soll die graue Flaeche + Icon UND Text umschliessen statt nur die enge Pille ums Icon - die Flaeche + wandert dafuer vom Icon-Symbol auf den ganzen Tab-Knopf. Im reinen + Icon-Modus bleibt die enge Pille wie zuvor. */ +.tabbar:not(.ohne) .tab.on{background:rgba(255,255,255,.14);border-radius:14px} +:host([data-theme="tag"]) .tabbar:not(.ohne) .tab.on{background:rgba(0,0,0,.07)} +.tabbar:not(.ohne) .tab.on .tabpille{background:none} .tabbar.ohne .tab{padding:11px 2px 10px} :focus-visible{outline:2px solid var(--ios-tint);outline-offset:2px} @@ -254,9 +274,9 @@ main#view{--seitenrand:16px;padding:0 var(--seitenrand) 30px;scroll-behavior:smo .tabpille{width:auto;height:auto;border-radius:0;background:none} .tab.on .tabpille{background:none} .tab:hover{background:var(--tile)} - /* Aktive Navigation: Rot bleibt Text-/Icon-Akzent, die Fläche wird neutral - statt rosa hinterlegt (Design-Review §B - Rot nicht als Flächenfarbe). */ - .tab.on{background:var(--ios-fill);color:var(--ios-tint)} + /* Aktives Symbol: dieselbe Farbe wie die Kopfzeile (--fg), nicht mehr Rot - + Fläche bleibt neutral hinterlegt statt rosa (Design-Review §B). */ + .tab.on{background:var(--ios-fill);color:var(--fg)} .tabbar.ohne .tab span{display:block} .tabbar.ohne .tab{padding:12px 14px;gap:14px} .tabbar.ohne .tab svg{width:22px;height:22px} diff --git a/homeassistant/www/audi-dashboard.css b/homeassistant/www/audi-dashboard.css index ad1ab74..ba4b87f 100644 --- a/homeassistant/www/audi-dashboard.css +++ b/homeassistant/www/audi-dashboard.css @@ -148,7 +148,7 @@ align-items: center; gap: 6px; margin-top: 4px; - font-size: 10.5px; + font-size: 11px; color: var(--fg3); white-space: nowrap; } @@ -443,7 +443,10 @@ button.tile, .tilebtn { transition: background .15s, transform .1s; } .carfix { width: 100%; aspect-ratio: 16 / 9; } .carfix.klein { aspect-ratio: 16 / 8; } .carfix.mini { width: 78px; height: 78px; aspect-ratio: auto; } -.radbild { width: 96px; height: 96px; aspect-ratio: auto; border-radius: 50%; } +/* Reifenfoto ist oft eine breite Aufnahme; statt beide Ränder symmetrisch + wegzuschneiden (object-fit:cover-Standard), bleibt bewusst der rechte Rand + des Originalfotos erhalten - dort sitzt das Rad meist im Bild. */ +.radbild { width: 96px; height: 96px; aspect-ratio: auto; border-radius: 50%; object-position: right center; } .bildbox { position: relative; width: 100%; aspect-ratio: 4 / 3; border-radius: 12px; overflow: hidden; } .bildbox img { display: block; width: 100%; height: 100%; object-fit: cover; } @@ -521,7 +524,18 @@ button.tile, .tilebtn { transition: background .15s, transform .1s; } appearance: none; } .feld input:focus, .feld select:focus, .notiz:focus { outline: none; border-color: var(--red); } -.feld select { padding-right: 30px; background-image: none; } +/* Pull-down-Button-Optik (Apple HIG): einzelner Abwaerts-Chevron statt des + durch appearance:none oben entfernten nativen Browser-Pfeils. */ +.feld select { + padding-right: 30px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5l3.5 3.5 3.5-3.5' fill='none' stroke='%238a94a3' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 11px center; + background-size: 10px 10px; +} +:host([data-theme=tag]) .feld select { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5l3.5 3.5 3.5-3.5' fill='none' stroke='%23666666' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); +} .feld > span { flex: 0 1 auto; min-width: 0; } .mitEinheit { display: inline-flex; align-items: center; gap: var(--sp-2); max-width: 100%; } .mitEinheit input { min-width: 0; width: 96px; text-align: right; } @@ -713,16 +727,20 @@ button.tile, .tilebtn { transition: background .15s, transform .1s; } } .fahrzeug-pin-wrap { background: none; border: none; } -/* poi-car aus dem CI-Satz ist eine reine Konturform in currentColor - auf - Kartenkacheln waere sie ohne Trennung zum Untergrund kaum lesbar. Die - gestapelten weissen drop-shadows ziehen deshalb einen Halo um die Kontur, - der letzte Schatten gibt Tiefe. Feste Farbe statt Theme-Variable, damit die - Nadel in Tag- und Nachtansicht gleich aussieht. */ +/* poi-car/poi aus dem CI-Satz sind reine Konturformen (Ring aus zwei + gegenlaeufigen Randlinien + duenne Detaillinien) - eine Pixelprobe ergab + nur 13-40% gefuellte Flaeche in der eigenen Bounding-Box und war auf + Kartenkacheln praktisch unsichtbar (Nutzer-Feedback "Pin ist transparent"). + fahrzeugMarkerSVG()/tankstellenMarkerSVG() rendern deshalb zusaetzlich eine + Vollton-Silhouette (CI.*Sil, exakt der aeussere Ballon-Umriss desselben + CI-Pfads, keine Neuzeichnung) als unterste Ebene; die Iconfarbe hier ist + deshalb weiss statt dunkel, damit Umriss und Detaillinien auf der jetzt + massiven Flaeche lesbar bleiben. Feste Farben statt Theme-Variablen, damit + die Nadeln in Tag- und Nachtansicht gleich aussehen. */ .fahrzeug-pin { display: flex; align-items: center; justify-content: center; - color: #182634; - filter: drop-shadow(0 0 1px #fff) drop-shadow(0 0 1px #fff) - drop-shadow(0 0 2px #fff) drop-shadow(0 2px 4px rgba(0,0,0,.4)); + color: #fff; + filter: drop-shadow(0 2px 4px rgba(0,0,0,.4)); } .user-pin-wrap { background: none; border: none; } .user-pin { @@ -856,6 +874,30 @@ button.tile, .tilebtn { transition: background .15s, transform .1s; } .radkopf { display: flex; flex-direction: column; margin-top: var(--sp-4); } +/* Kompakte Pille statt voller Breite (Apple-HIG-Pull-down-Maß): oben rechts + in der Kachel, obere Kante auf Höhe des Radfotos, rechter Abstand + identisch zum linken Texteinzug (beides var(--sp-5), die Kachel-Innen- + polsterung). */ +.montiert { + position: absolute; top: var(--sp-5); right: var(--sp-5); + display: inline-flex; align-items: center; justify-content: center; + font-family: inherit; font-size: 12px; letter-spacing: normal; + color: var(--fg2); + background: none; + border: 1px solid var(--line-strong); + border-radius: var(--r-pill); + padding: 7px 13px; + cursor: pointer; + transition: background .15s, color .15s, border-color .15s, transform .1s; +} +/* Optisch bleibt die Pille klein, die Tippflaeche wird per unsichtbarem + Pseudo-Element auf Apple-HIG-Mindestmass 44x44pt gebracht (Klick auf die + Flaeche des ::before zaehlt als Klick auf den echten Button). */ +.montiert::before { content: ""; position: absolute; top: -8px; bottom: -8px; left: 0; right: 0; } +.montiert:hover { background: var(--shade); } +.montiert:active { transform: scale(.96); background: var(--shade); } +.montiert.on { background: var(--fg); border-color: var(--fg); color: var(--canvas); } + /* ------------------------------------------------- B4: Action Sheet Ersetzt confirm()/alert(). Von unten eingeblendet, destruktive Zeile rot, Abbrechen abgesetzt - iOS-Muster. */