UI polish batch + fix genuinely-invisible map pins, Apple HIG audit
Battery voltage stat cutoff 13.2V -> 12.8V (values above that are already alternator output, not the battery); fixed the battery chart's Y-axis "stretching" on zoom by computing it once from the full dataset; removed two explanatory paragraphs from the battery detail view; Tankfuellung now shows "X % / X l"; removed the "noch etwa X l im Tank" suffix; fuel bar color now matches the headline instead of a red/yellow/green gradient; active/primary buttons are grey again, not red (destructive stays red per HIG); select fields gained an Apple-HIG pull-down chevron (appearance:none had removed the native one with nothing replacing it); selected menu icon is white on desktop, matching mobile; Reifenfoto crops from the right edge; "Montiert" button rebuilt as a compact top-right pill with a 44px invisible tap target; tab-bar active highlight now covers icon+label, not just the icon; removed two leftover explanatory texts from Einstellungen. Root-caused the map pins looking "transparent": the CI poi-car/poi icons are pure contour forms (nonzero-fill-rule ring + thin detail lines, only 13-40% of their own bounding box actually filled). Fixed by extracting each icon's own first sub-path (the true outer balloon silhouette, verified by rasterizing it in isolation) as a solid-filled layer behind the original icon, applied to both the vehicle and station markers. Read Color/Typography/Layout/Buttons/Materials on developer.apple.com and applied the user-approved subset (11px text floor, 44px tap targets); declined items (font weight, materials) documented with rationale. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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) **`<select>` fields now carry an Apple-HIG pull-down chevron.** They already had
|
||||
`appearance:none` (native arrow removed) but no replacement indicator at all — a real gap, not
|
||||
cosmetic. Added a CSS `background-image` chevron (light/dark variants) in both stylesheets;
|
||||
base `audi-dashboard.css` kept independently correct (own light/dark variant via
|
||||
`:host([data-theme=tag])`) per this repo's "purely additive overlay" convention for the ios
|
||||
file.
|
||||
(9) **Apple HIG research round.** Read Color/Typography/Layout/Buttons/Materials directly off
|
||||
developer.apple.com (the WebFetch tool returned only page titles for this JS-rendered site: the
|
||||
in-app Browser tool's `get_page_text` worked and was used instead) and cross-checked against
|
||||
actual measurements in this codebase, then asked the user via `AskUserQuestion` which findings
|
||||
to apply. Accepted: text below the 11pt iOS legibility minimum (battery-chart axis labels were
|
||||
8px, the header's "Sync" line was 10.5px) raised to 11px; the new compact "Montiert" pill's
|
||||
*invisible* hit area (not its visual size) expanded to the 44×44pt minimum via a `::before`
|
||||
with negative insets, same technique applied to future compact controls. Declined, deliberately:
|
||||
switching the app's few weight-300 ("Light") text spots to 400 — Audi Type only ships 300/400,
|
||||
and the user chose to keep Audi CI's own weight over HIG's general "avoid Light" guidance;
|
||||
making popups/sheets translucent to match the Materials guidance — the app already restricts
|
||||
translucency to the nav layer only (tab bar), which *is* the HIG-correct pattern, and popups
|
||||
were deliberately made opaque on 2026-08-16 earlier the same day to fix a real see-through bug,
|
||||
so translucency there would be a regression, not an improvement.
|
||||
(10) Removed "Aus dem Fahrzeug gelesen" and the Einrichten intro paragraph ("Fahrgestellnummer,
|
||||
Kennzeichen, Erstzulassung…") from `vEinst()`, both per explicit request.
|
||||
(11) **Fuel bar color now matches the headline** (`var(--fg)`) instead of a red/yellow/green
|
||||
status gradient in `vHome()`; the `balkenFarbe` local was removed with it.
|
||||
(12) **Selected menu icon is white (headline color), not red**, in the desktop side-nav
|
||||
(`.tab.on` inside the `@container (min-width:860px)` block in `audi-dashboard-ios.css`) — the
|
||||
mobile tab bar already used `var(--fg)` there, this brought the desktop variant in line.
|
||||
(13) **Reifenfoto (Sommerrad/Winterrad) now crops from the right edge**, not the center —
|
||||
`.radbild` gained `object-position: right center`; the photo is typically wider than the 96px
|
||||
square slot and the wheel itself tends to sit toward the right of the source photo.
|
||||
(14) **"Montiert" button rebuilt as a compact top-right pill** (new `.montiert` class,
|
||||
replacing the old full-width `.seg`-wrapped button) per explicit layout instructions: top edge
|
||||
aligned with the wheel photo's top (`top:var(--sp-5)`, same offset the photo already has from
|
||||
the tile's own padding), right inset equal to the tile's standard left content inset (both
|
||||
`var(--sp-5)`) so left/right margins match. Markup reordered so the button renders before
|
||||
`.radkopf` (position is absolute either way, but keeps DOM order sensible).
|
||||
(15) **Tab-bar active highlight now covers icon *and* label when the label is visible**, not
|
||||
just a tight pill behind the icon — `.tabbar:not(.ohne) .tab.on` gets the highlight background
|
||||
directly (whole button), with the inner `.tabpille` background suppressed in that case; the
|
||||
icon-only mode (`.tabbar.ohne`) keeps the original tight icon-pill unchanged.
|
||||
Deployed to `audi_ha_test` (version `1786901000`); pin fix visually confirmed live (solid
|
||||
teardrop pin with white car glyph, clearly over the map's "Obergurgl" label text) and the
|
||||
tab-bar highlight confirmed covering both icon and "Übersicht" label.
|
||||
- [ ] Fix remaining documentation drift (statistics claim, README gaps, obsolete TODO comment) —
|
||||
text-only changes; INSTALL.md's WLAN/TommiG1 drift and stale variable names were fixed
|
||||
2026-08-12 (see section B); `DESIGN_REVIEW_2026-08-13.md` and `REVIEW_main_2026-08-13.md`
|
||||
|
||||
@@ -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 `<svg viewBox="0 0 ${box} ${box}" width="${px}" height="${px}" fill="none" aria-hidden="true">${gross ? CI.poiCarL : CI.poiCar}</svg>`;
|
||||
const sil = gross ? CI.poiCarLSil : CI.poiCarSil;
|
||||
const icon = gross ? CI.poiCarL : CI.poiCar;
|
||||
return `<svg viewBox="0 0 ${box} ${box}" width="${px}" height="${px}" fill="none" aria-hidden="true">${sil}${icon}</svg>`;
|
||||
}
|
||||
|
||||
/* 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 `<svg viewBox="0 0 ${box} ${box}" width="${px}" height="${px}" fill="none" aria-hidden="true">${gross ? CI.poiL : CI.poiS}</svg>`;
|
||||
const sil = gross ? CI.poiLSil : CI.poiSSil;
|
||||
const icon = gross ? CI.poiL : CI.poiS;
|
||||
return `<svg viewBox="0 0 ${box} ${box}" width="${px}" height="${px}" fill="none" aria-hidden="true">${sil}${icon}</svg>`;
|
||||
}
|
||||
|
||||
/* Fahrzustand fürs Menü: "fährt" solange die aktuelle Fahrt noch offen ist
|
||||
@@ -928,6 +932,20 @@ const CI = {
|
||||
poiL: '<path fill="currentColor" d="M9 17.5C9 9.52 15.52 3 23.5 3S38 9.52 38 17.5c0 2.04-.92 4.78-2.23 7.67a90 90 0 0 1-4.84 8.98 170 170 0 0 1-6.98 10.59l-.03.04-.01.01-.41-.29-.4.3-.02-.02-.03-.04a66 66 0 0 1-.56-.8 166 166 0 0 1-6.42-9.8 90 90 0 0 1-4.84-8.97C9.92 22.27 9 19.54 9 17.5m14.5 27-.4.3.4.55.4-.56zm0-.86a132 132 0 0 0 1.77-2.56 170 170 0 0 0 4.8-7.45 89 89 0 0 0 4.79-8.87c1.3-2.89 2.14-5.45 2.14-7.26C37 10.08 30.92 4 23.5 4S10 10.08 10 17.5c0 1.8.83 4.37 2.14 7.26a89 89 0 0 0 4.79 8.87 170 170 0 0 0 6.57 10.01M16 17.5a7.5 7.5 0 1 1 15 0 7.5 7.5 0 0 1-15 0m7.5-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13"/>',
|
||||
poiS: '<path fill="currentColor" d="M4 8.5C4 4.32 7.32 1 11.5 1S19 4.32 19 8.5c0 1.09-.48 2.53-1.14 4.03a49 49 0 0 1-2.43 4.68A92 92 0 0 1 12 22.67l-.06.08-.01.03-.42-.28-.41.28-.02-.03-.06-.08A66 66 0 0 1 10 21.13a92 92 0 0 1-2.42-3.92 49 49 0 0 1-2.43-4.68C4.48 11.03 4 9.6 4 8.5m7.5 14-.41.28.41.6.41-.6zm0-.89a92 92 0 0 0 3.07-4.9c.87-1.5 1.73-3.1 2.38-4.58A10.4 10.4 0 0 0 18 8.5C18 4.88 15.12 2 11.5 2A6.46 6.46 0 0 0 5 8.5c0 .86.4 2.14 1.05 3.63a48 48 0 0 0 2.38 4.58 91 91 0 0 0 3.07 4.9M8 8.5a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0M11.5 6a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5"/>',
|
||||
poiCarL: '<path fill="currentColor" d="M9 17.5C9 9.52 15.52 3 23.5 3S38 9.52 38 17.5c0 2.04-.92 4.78-2.23 7.67a90 90 0 0 1-4.84 8.98 170 170 0 0 1-6.98 10.59l-.03.04-.01.01-.41-.29-.4.3-.02-.02-.03-.04a66 66 0 0 1-.56-.8 166 166 0 0 1-6.42-9.8 90 90 0 0 1-4.84-8.97C9.92 22.27 9 19.54 9 17.5m14.5 27-.4.3.4.55.4-.56zm0-.86a132 132 0 0 0 1.77-2.56 170 170 0 0 0 4.8-7.45 89 89 0 0 0 4.79-8.87c1.3-2.89 2.14-5.45 2.14-7.26C37 10.08 30.92 4 23.5 4S10 10.08 10 17.5c0 1.8.83 4.37 2.14 7.26a89 89 0 0 0 4.79 8.87 170 170 0 0 0 6.57 10.01M17.96 7.98A63.3 63.3 0 0 1 29.05 8l.2.02.13.16c.6.7 1.1 1.36 1.46 1.94l1.31 2.08L34 14.31v7.19c0 .83-.67 1.5-1.5 1.5h-2a1.5 1.5 0 0 1-1.5-1.5V21H18v.5c0 .83-.67 1.5-1.5 1.5h-2a1.5 1.5 0 0 1-1.5-1.5v-7.19l1.85-2.11 1.3-2.08c.37-.58.86-1.24 1.47-1.96l.13-.16.2-.02ZM15.48 13 14 14.69V15h3v1h-3v5.5c0 .28.22.5.5.5h2a.5.5 0 0 0 .5-.5V20h13v1.5c0 .28.22.5.5.5h2a.5.5 0 0 0 .5-.5V16h-3v-1h3v-.31L31.52 13zm15.36-1L30 10.65a16 16 0 0 0-1.25-1.67 62.4 62.4 0 0 0-10.5-.02 17 17 0 0 0-1.25 1.7L16.16 12zM19.3 15h8.42l1.4 1.4-.16.31c-.34.74-.65 1.32-.92 1.72-.14.2-.28.38-.42.5a.92.92 0 0 1-.61.27h-7a.92.92 0 0 1-.6-.27 2.4 2.4 0 0 1-.43-.5c-.27-.4-.58-.98-.92-1.72l-.15-.32zm.42 1-.6.6c.26.57.5.99.69 1.27.11.17.2.27.26.32l.01.01h6.86v-.01c.07-.05.16-.15.27-.32.2-.28.43-.7.7-1.27l-.6-.6h-7.6Z"/>',
|
||||
/* 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: '<path fill="#182634" d="M9 17.5C9 9.52 15.52 3 23.5 3S38 9.52 38 17.5c0 2.04-.92 4.78-2.23 7.67a90 90 0 0 1-4.84 8.98 170 170 0 0 1-6.98 10.59l-.03.04-.01.01-.41-.29-.4.3-.02-.02-.03-.04a66 66 0 0 1-.56-.8 166 166 0 0 1-6.42-9.8 90 90 0 0 1-4.84-8.97C9.92 22.27 9 19.54 9 17.5"/>',
|
||||
poiCarSil: '<path fill="#182634" d="M3.8 8.6C3.8 4.33 7.32.8 11.5.8s7.7 3.53 7.7 7.8c0 1.11-.5 2.58-1.17 4.1a48 48 0 0 1-2.5 4.7 90 90 0 0 1-3.54 5.47l-.06.09-.02.02V23l-.41-.29-.4.29h-.01l-.02-.03-.06-.09a70 70 0 0 1-1.05-1.53 90 90 0 0 1-2.49-3.93 48 48 0 0 1-2.5-4.72C4.29 11.18 3.8 9.71 3.8 8.6"/>',
|
||||
poiLSil: '<path fill="#182634" d="M9 17.5C9 9.52 15.52 3 23.5 3S38 9.52 38 17.5c0 2.04-.92 4.78-2.23 7.67a90 90 0 0 1-4.84 8.98 170 170 0 0 1-6.98 10.59l-.03.04-.01.01-.41-.29-.4.3-.02-.02-.03-.04a66 66 0 0 1-.56-.8 166 166 0 0 1-6.42-9.8 90 90 0 0 1-4.84-8.97C9.92 22.27 9 19.54 9 17.5"/>',
|
||||
poiSSil: '<path fill="#182634" d="M4 8.5C4 4.32 7.32 1 11.5 1S19 4.32 19 8.5c0 1.09-.48 2.53-1.14 4.03a49 49 0 0 1-2.43 4.68A92 92 0 0 1 12 22.67l-.06.08-.01.03-.42-.28-.41.28-.02-.03-.06-.08A66 66 0 0 1 10 21.13a92 92 0 0 1-2.42-3.92 49 49 0 0 1-2.43-4.68C4.48 11.03 4 9.6 4 8.5"/>',
|
||||
selectAll: '<path fill="currentColor" d="M2.8 2H5v1H3v2H2V2.8a.76.76 0 0 1 .43-.71.9.9 0 0 1 .35-.09zv.5zM9 3H7V2h2zm4 0h-2V2h2zm4 0h-2V2h2zm4 0h-2V2h2.2v.5V2h.02a1 1 0 0 1 .1.01c.07.01.16.03.25.08a.76.76 0 0 1 .43.71V5h-1zM6 6h12v12H6zm1 1v10h10V7zM3 7v2H2V7zm19 0v2h-1V7zM3 11v2H2v-2zm19 0v2h-1v-2zM3 15v2H2v-2zm19 0v2h-1v-2zM3 21v-2H2v2.2a.76.76 0 0 0 .43.71.9.9 0 0 0 .35.09h.01l.01-.5v.5H5v-1zm19-2v2.2a.76.76 0 0 1-.43.71.9.9 0 0 1-.35.09h-.01l-.01-.49V22H19v-1h2v-2zM9 22H7v-1h2zm4 0h-2v-1h2zm4 0h-2v-1h2z"/>',
|
||||
planRoute: '<path fill="currentColor" d="m18.3 7-3.65-3.65.7-.7 4.86 4.85-4.86 4.85-.7-.7L18.29 8H9.5C8.67 8 8 8.67 8 9.5V21H7V9.5A2.5 2.5 0 0 1 9.5 7z"/>',
|
||||
upload: '<path fill="currentColor" d="M13 20h-1V9.7l-3.65 3.65-.7-.7 4.85-4.86 4.85 4.86-.7.7L13 9.71zM6 5V4h13v1z"/>',
|
||||
@@ -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() {
|
||||
<div class="fig" style="font-size:60px">${CAR.reichweite != null ? de(CAR.reichweite) : "–"}<span class="unit">km</span></div>
|
||||
<span class="pct">${CAR.tankBekannt ? pct + " %" : "–"}</span>
|
||||
</div>
|
||||
<div class="balken"><i style="width:${pct}%;background:${balkenFarbe}"></i></div>
|
||||
<span class="label" style="margin-top:12px">Reichweite${CAR.tankBekannt && liter != null ? ` · noch etwa ${de(liter)} l im Tank` : ""}</span>
|
||||
<div class="balken"><i style="width:${pct}%;background:var(--fg)"></i></div>
|
||||
<span class="label" style="margin-top:12px">Reichweite</span>
|
||||
</div>
|
||||
<div class="duo">
|
||||
<div class="tile"><span class="label">Kilometerstand</span>
|
||||
@@ -1262,7 +1278,7 @@ function vAudi() {
|
||||
</dl></button>
|
||||
<div class="tile"><span class="label">Zustand</span><dl class="rows">
|
||||
<div class="row"><dt>Kilometerstand</dt><dd>${CAR.odoBekannt ? de(CAR.odo) + " km" : "unbekannt"}</dd></div>
|
||||
<div class="row"><dt>Tankfüllung</dt><dd>${de(CONFIG.tankvolumen * CAR.tankPct / 100, 1)} l<small>${CAR.tankPct} % von ${CONFIG.tankvolumen} l</small></dd></div>
|
||||
<div class="row"><dt>Tankfüllung</dt><dd>${CAR.tankPct} % / ${de(CONFIG.tankvolumen * CAR.tankPct / 100, 1)} l</dd></div>
|
||||
<div class="row" style="border-bottom:0;cursor:pointer" data-go="battverlauf:x"><dt>Batteriespannung</dt>
|
||||
<dd style="display:flex;align-items:center;gap:6px;justify-content:flex-end">${CAR.batteriespannung != null ? de(CAR.batteriespannung, 1) + " V" : "unbekannt"}
|
||||
<svg class="chev" viewBox="0 0 6 10"><polyline points="1,1 5,5 1,9"/></svg></dd></div></dl></div>
|
||||
@@ -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() {
|
||||
<button class="aktion" data-bvreset style="padding:8px 16px;font-size:11px;width:auto;margin-top:0">Zoom zurücksetzen</button>
|
||||
</div>
|
||||
<div id="bvTooltip" style="display:none;margin-top:12px;font-size:13px;color:var(--fg2)"></div>
|
||||
<span class="label" style="margin-top:16px">Ziehen zum Verschieben, mit zwei Fingern oder dem Mausrad
|
||||
zoomen, auf einen Punkt tippen für Datum, Uhrzeit sowie Min-/Max-Spannung</span>
|
||||
` : `
|
||||
<span class="label" style="margin-top:14px;color:var(--fg3)">${leerText}</span>
|
||||
`}
|
||||
@@ -1480,9 +1509,6 @@ function vBatterieverlauf() {
|
||||
: `<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 class="label" style="margin-top:12px">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.</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@@ -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 `<line x1="${BV_ML}" y1="${y.toFixed(1)}" x2="${BV_W - BV_MR}" y2="${y.toFixed(1)}" stroke="var(--line)" stroke-width="0.5"/>
|
||||
<text x="${BV_ML - 6}" y="${(y + 3).toFixed(1)}" font-size="8" fill="var(--fg3)" text-anchor="end">${de(v, 1)}</text>`;
|
||||
<text x="${BV_ML - 6}" y="${(y + 3).toFixed(1)}" font-size="11" fill="var(--fg3)" text-anchor="end">${de(v, 1)}</text>`;
|
||||
}).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 `<text x="${x.toFixed(1)}" y="${BV_H - 6}" font-size="8" fill="var(--fg3)"
|
||||
return `<text x="${x.toFixed(1)}" y="${BV_H - 6}" font-size="11" fill="var(--fg3)"
|
||||
text-anchor="${f === 0 ? "start" : f === 1 ? "end" : "middle"}">${kurzdat(new Date(t))}</text>`;
|
||||
}).join("");
|
||||
const stufen = bvFarbstufen();
|
||||
@@ -1930,10 +1955,6 @@ function csvDatei(name, kopf, zeilen) {
|
||||
function vEinst() {
|
||||
return `
|
||||
<div class="tile"><span class="label">Fahrzeug einrichten</span>
|
||||
<span style="display:block;margin-top:10px;color:var(--fg2);
|
||||
font-size:13.5px;line-height:1.6">
|
||||
Fahrgestellnummer, Kennzeichen, Erstzulassung, Ausführung und Ölwechsel-Intervall — bei der
|
||||
Ersteinrichtung oder wenn sich diese Angaben ändern.</span>
|
||||
${einrichtenOffen ? `
|
||||
<div class="feld" style="margin-top:16px"><label for="einFin">Fahrgestellnummer (FIN)</label>
|
||||
<input id="einFin" value="${esc(CAR.fin || "")}" data-einrichten="fin"></div>
|
||||
@@ -1957,8 +1978,7 @@ function vEinst() {
|
||||
? `<dl class="rows" style="margin-top:16px">
|
||||
<div class="row"><dt>Laufleistung</dt><dd>${de(CAR.oel.herstellerKm)} km</dd></div>
|
||||
<div class="row" style="border-bottom:0"><dt>Zeit</dt><dd>${CAR.oel.herstellerMonate} Monate</dd></div>
|
||||
</dl>
|
||||
<span class="label" style="margin-top:14px">Aus dem Fahrzeug gelesen</span>`
|
||||
</dl>`
|
||||
: `<div class="feld" style="margin-top:6px"><label for="oelKm">Nach Laufleistung</label>
|
||||
<select id="oelKm" data-oelkm>${[5000, 10000, 15000, 20000].map((k) => `<option value="${k}" ${k === CAR.oel.km ? "selected" : ""}>${de(k)} km</option>`).join("")}</select></div>
|
||||
<div class="feld" style="border-bottom:0"><label for="oelM">Nach Zeit</label>
|
||||
@@ -2329,13 +2349,11 @@ function vReifen() {
|
||||
<button type="button" data-bildersetzen="${radDatei}">Foto ersetzen</button>
|
||||
<button type="button" class="loeschen" data-bildloeschen="${radDatei}">Löschen</button>
|
||||
</div>` : ""}
|
||||
<button data-satz="${k === "sommer" ? "Sommer" : "Winter"}" class="montiert ${aktiv ? "on" : ""}">Montiert</button>
|
||||
<div class="radkopf">
|
||||
<span class="label">${k === "sommer" ? "Sommer" : "Winter"}</span>
|
||||
<div class="fig" style="font-size:32px;margin-top:14px">${t.km != null ? de(t.km) : "–"}<span class="unit">km</span></div>
|
||||
</div>
|
||||
<div class="seg" style="margin-top:16px">
|
||||
<button data-satz="${k === "sommer" ? "Sommer" : "Winter"}" class="${aktiv ? "on" : ""}">Montiert</button>
|
||||
</div>
|
||||
<div style="margin-top:22px">
|
||||
${feld(k, "marke", "Hersteller")}
|
||||
${feld(k, "modell", "Modell")}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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 `<svg viewBox="0 0 ${box} ${box}" width="${px}" height="${px}" fill="none" aria-hidden="true">${gross ? CI.poiCarL : CI.poiCar}</svg>`;
|
||||
const sil = gross ? CI.poiCarLSil : CI.poiCarSil;
|
||||
const icon = gross ? CI.poiCarL : CI.poiCar;
|
||||
return `<svg viewBox="0 0 ${box} ${box}" width="${px}" height="${px}" fill="none" aria-hidden="true">${sil}${icon}</svg>`;
|
||||
}
|
||||
|
||||
/* 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 `<svg viewBox="0 0 ${box} ${box}" width="${px}" height="${px}" fill="none" aria-hidden="true">${gross ? CI.poiL : CI.poiS}</svg>`;
|
||||
const sil = gross ? CI.poiLSil : CI.poiSSil;
|
||||
const icon = gross ? CI.poiL : CI.poiS;
|
||||
return `<svg viewBox="0 0 ${box} ${box}" width="${px}" height="${px}" fill="none" aria-hidden="true">${sil}${icon}</svg>`;
|
||||
}
|
||||
|
||||
/* Fahrzustand fürs Menü: "fährt" solange die aktuelle Fahrt noch offen ist
|
||||
@@ -928,6 +932,20 @@ const CI = {
|
||||
poiL: '<path fill="currentColor" d="M9 17.5C9 9.52 15.52 3 23.5 3S38 9.52 38 17.5c0 2.04-.92 4.78-2.23 7.67a90 90 0 0 1-4.84 8.98 170 170 0 0 1-6.98 10.59l-.03.04-.01.01-.41-.29-.4.3-.02-.02-.03-.04a66 66 0 0 1-.56-.8 166 166 0 0 1-6.42-9.8 90 90 0 0 1-4.84-8.97C9.92 22.27 9 19.54 9 17.5m14.5 27-.4.3.4.55.4-.56zm0-.86a132 132 0 0 0 1.77-2.56 170 170 0 0 0 4.8-7.45 89 89 0 0 0 4.79-8.87c1.3-2.89 2.14-5.45 2.14-7.26C37 10.08 30.92 4 23.5 4S10 10.08 10 17.5c0 1.8.83 4.37 2.14 7.26a89 89 0 0 0 4.79 8.87 170 170 0 0 0 6.57 10.01M16 17.5a7.5 7.5 0 1 1 15 0 7.5 7.5 0 0 1-15 0m7.5-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13"/>',
|
||||
poiS: '<path fill="currentColor" d="M4 8.5C4 4.32 7.32 1 11.5 1S19 4.32 19 8.5c0 1.09-.48 2.53-1.14 4.03a49 49 0 0 1-2.43 4.68A92 92 0 0 1 12 22.67l-.06.08-.01.03-.42-.28-.41.28-.02-.03-.06-.08A66 66 0 0 1 10 21.13a92 92 0 0 1-2.42-3.92 49 49 0 0 1-2.43-4.68C4.48 11.03 4 9.6 4 8.5m7.5 14-.41.28.41.6.41-.6zm0-.89a92 92 0 0 0 3.07-4.9c.87-1.5 1.73-3.1 2.38-4.58A10.4 10.4 0 0 0 18 8.5C18 4.88 15.12 2 11.5 2A6.46 6.46 0 0 0 5 8.5c0 .86.4 2.14 1.05 3.63a48 48 0 0 0 2.38 4.58 91 91 0 0 0 3.07 4.9M8 8.5a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0M11.5 6a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5"/>',
|
||||
poiCarL: '<path fill="currentColor" d="M9 17.5C9 9.52 15.52 3 23.5 3S38 9.52 38 17.5c0 2.04-.92 4.78-2.23 7.67a90 90 0 0 1-4.84 8.98 170 170 0 0 1-6.98 10.59l-.03.04-.01.01-.41-.29-.4.3-.02-.02-.03-.04a66 66 0 0 1-.56-.8 166 166 0 0 1-6.42-9.8 90 90 0 0 1-4.84-8.97C9.92 22.27 9 19.54 9 17.5m14.5 27-.4.3.4.55.4-.56zm0-.86a132 132 0 0 0 1.77-2.56 170 170 0 0 0 4.8-7.45 89 89 0 0 0 4.79-8.87c1.3-2.89 2.14-5.45 2.14-7.26C37 10.08 30.92 4 23.5 4S10 10.08 10 17.5c0 1.8.83 4.37 2.14 7.26a89 89 0 0 0 4.79 8.87 170 170 0 0 0 6.57 10.01M17.96 7.98A63.3 63.3 0 0 1 29.05 8l.2.02.13.16c.6.7 1.1 1.36 1.46 1.94l1.31 2.08L34 14.31v7.19c0 .83-.67 1.5-1.5 1.5h-2a1.5 1.5 0 0 1-1.5-1.5V21H18v.5c0 .83-.67 1.5-1.5 1.5h-2a1.5 1.5 0 0 1-1.5-1.5v-7.19l1.85-2.11 1.3-2.08c.37-.58.86-1.24 1.47-1.96l.13-.16.2-.02ZM15.48 13 14 14.69V15h3v1h-3v5.5c0 .28.22.5.5.5h2a.5.5 0 0 0 .5-.5V20h13v1.5c0 .28.22.5.5.5h2a.5.5 0 0 0 .5-.5V16h-3v-1h3v-.31L31.52 13zm15.36-1L30 10.65a16 16 0 0 0-1.25-1.67 62.4 62.4 0 0 0-10.5-.02 17 17 0 0 0-1.25 1.7L16.16 12zM19.3 15h8.42l1.4 1.4-.16.31c-.34.74-.65 1.32-.92 1.72-.14.2-.28.38-.42.5a.92.92 0 0 1-.61.27h-7a.92.92 0 0 1-.6-.27 2.4 2.4 0 0 1-.43-.5c-.27-.4-.58-.98-.92-1.72l-.15-.32zm.42 1-.6.6c.26.57.5.99.69 1.27.11.17.2.27.26.32l.01.01h6.86v-.01c.07-.05.16-.15.27-.32.2-.28.43-.7.7-1.27l-.6-.6h-7.6Z"/>',
|
||||
/* 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: '<path fill="#182634" d="M9 17.5C9 9.52 15.52 3 23.5 3S38 9.52 38 17.5c0 2.04-.92 4.78-2.23 7.67a90 90 0 0 1-4.84 8.98 170 170 0 0 1-6.98 10.59l-.03.04-.01.01-.41-.29-.4.3-.02-.02-.03-.04a66 66 0 0 1-.56-.8 166 166 0 0 1-6.42-9.8 90 90 0 0 1-4.84-8.97C9.92 22.27 9 19.54 9 17.5"/>',
|
||||
poiCarSil: '<path fill="#182634" d="M3.8 8.6C3.8 4.33 7.32.8 11.5.8s7.7 3.53 7.7 7.8c0 1.11-.5 2.58-1.17 4.1a48 48 0 0 1-2.5 4.7 90 90 0 0 1-3.54 5.47l-.06.09-.02.02V23l-.41-.29-.4.29h-.01l-.02-.03-.06-.09a70 70 0 0 1-1.05-1.53 90 90 0 0 1-2.49-3.93 48 48 0 0 1-2.5-4.72C4.29 11.18 3.8 9.71 3.8 8.6"/>',
|
||||
poiLSil: '<path fill="#182634" d="M9 17.5C9 9.52 15.52 3 23.5 3S38 9.52 38 17.5c0 2.04-.92 4.78-2.23 7.67a90 90 0 0 1-4.84 8.98 170 170 0 0 1-6.98 10.59l-.03.04-.01.01-.41-.29-.4.3-.02-.02-.03-.04a66 66 0 0 1-.56-.8 166 166 0 0 1-6.42-9.8 90 90 0 0 1-4.84-8.97C9.92 22.27 9 19.54 9 17.5"/>',
|
||||
poiSSil: '<path fill="#182634" d="M4 8.5C4 4.32 7.32 1 11.5 1S19 4.32 19 8.5c0 1.09-.48 2.53-1.14 4.03a49 49 0 0 1-2.43 4.68A92 92 0 0 1 12 22.67l-.06.08-.01.03-.42-.28-.41.28-.02-.03-.06-.08A66 66 0 0 1 10 21.13a92 92 0 0 1-2.42-3.92 49 49 0 0 1-2.43-4.68C4.48 11.03 4 9.6 4 8.5"/>',
|
||||
selectAll: '<path fill="currentColor" d="M2.8 2H5v1H3v2H2V2.8a.76.76 0 0 1 .43-.71.9.9 0 0 1 .35-.09zv.5zM9 3H7V2h2zm4 0h-2V2h2zm4 0h-2V2h2zm4 0h-2V2h2.2v.5V2h.02a1 1 0 0 1 .1.01c.07.01.16.03.25.08a.76.76 0 0 1 .43.71V5h-1zM6 6h12v12H6zm1 1v10h10V7zM3 7v2H2V7zm19 0v2h-1V7zM3 11v2H2v-2zm19 0v2h-1v-2zM3 15v2H2v-2zm19 0v2h-1v-2zM3 21v-2H2v2.2a.76.76 0 0 0 .43.71.9.9 0 0 0 .35.09h.01l.01-.5v.5H5v-1zm19-2v2.2a.76.76 0 0 1-.43.71.9.9 0 0 1-.35.09h-.01l-.01-.49V22H19v-1h2v-2zM9 22H7v-1h2zm4 0h-2v-1h2zm4 0h-2v-1h2z"/>',
|
||||
planRoute: '<path fill="currentColor" d="m18.3 7-3.65-3.65.7-.7 4.86 4.85-4.86 4.85-.7-.7L18.29 8H9.5C8.67 8 8 8.67 8 9.5V21H7V9.5A2.5 2.5 0 0 1 9.5 7z"/>',
|
||||
upload: '<path fill="currentColor" d="M13 20h-1V9.7l-3.65 3.65-.7-.7 4.85-4.86 4.85 4.86-.7.7L13 9.71zM6 5V4h13v1z"/>',
|
||||
@@ -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() {
|
||||
<div class="fig" style="font-size:60px">${CAR.reichweite != null ? de(CAR.reichweite) : "–"}<span class="unit">km</span></div>
|
||||
<span class="pct">${CAR.tankBekannt ? pct + " %" : "–"}</span>
|
||||
</div>
|
||||
<div class="balken"><i style="width:${pct}%;background:${balkenFarbe}"></i></div>
|
||||
<span class="label" style="margin-top:12px">Reichweite${CAR.tankBekannt && liter != null ? ` · noch etwa ${de(liter)} l im Tank` : ""}</span>
|
||||
<div class="balken"><i style="width:${pct}%;background:var(--fg)"></i></div>
|
||||
<span class="label" style="margin-top:12px">Reichweite</span>
|
||||
</div>
|
||||
<div class="duo">
|
||||
<div class="tile"><span class="label">Kilometerstand</span>
|
||||
@@ -1262,7 +1278,7 @@ function vAudi() {
|
||||
</dl></button>
|
||||
<div class="tile"><span class="label">Zustand</span><dl class="rows">
|
||||
<div class="row"><dt>Kilometerstand</dt><dd>${CAR.odoBekannt ? de(CAR.odo) + " km" : "unbekannt"}</dd></div>
|
||||
<div class="row"><dt>Tankfüllung</dt><dd>${de(CONFIG.tankvolumen * CAR.tankPct / 100, 1)} l<small>${CAR.tankPct} % von ${CONFIG.tankvolumen} l</small></dd></div>
|
||||
<div class="row"><dt>Tankfüllung</dt><dd>${CAR.tankPct} % / ${de(CONFIG.tankvolumen * CAR.tankPct / 100, 1)} l</dd></div>
|
||||
<div class="row" style="border-bottom:0;cursor:pointer" data-go="battverlauf:x"><dt>Batteriespannung</dt>
|
||||
<dd style="display:flex;align-items:center;gap:6px;justify-content:flex-end">${CAR.batteriespannung != null ? de(CAR.batteriespannung, 1) + " V" : "unbekannt"}
|
||||
<svg class="chev" viewBox="0 0 6 10"><polyline points="1,1 5,5 1,9"/></svg></dd></div></dl></div>
|
||||
@@ -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() {
|
||||
<button class="aktion" data-bvreset style="padding:8px 16px;font-size:11px;width:auto;margin-top:0">Zoom zurücksetzen</button>
|
||||
</div>
|
||||
<div id="bvTooltip" style="display:none;margin-top:12px;font-size:13px;color:var(--fg2)"></div>
|
||||
<span class="label" style="margin-top:16px">Ziehen zum Verschieben, mit zwei Fingern oder dem Mausrad
|
||||
zoomen, auf einen Punkt tippen für Datum, Uhrzeit sowie Min-/Max-Spannung</span>
|
||||
` : `
|
||||
<span class="label" style="margin-top:14px;color:var(--fg3)">${leerText}</span>
|
||||
`}
|
||||
@@ -1480,9 +1509,6 @@ function vBatterieverlauf() {
|
||||
: `<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 class="label" style="margin-top:12px">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.</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@@ -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 `<line x1="${BV_ML}" y1="${y.toFixed(1)}" x2="${BV_W - BV_MR}" y2="${y.toFixed(1)}" stroke="var(--line)" stroke-width="0.5"/>
|
||||
<text x="${BV_ML - 6}" y="${(y + 3).toFixed(1)}" font-size="8" fill="var(--fg3)" text-anchor="end">${de(v, 1)}</text>`;
|
||||
<text x="${BV_ML - 6}" y="${(y + 3).toFixed(1)}" font-size="11" fill="var(--fg3)" text-anchor="end">${de(v, 1)}</text>`;
|
||||
}).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 `<text x="${x.toFixed(1)}" y="${BV_H - 6}" font-size="8" fill="var(--fg3)"
|
||||
return `<text x="${x.toFixed(1)}" y="${BV_H - 6}" font-size="11" fill="var(--fg3)"
|
||||
text-anchor="${f === 0 ? "start" : f === 1 ? "end" : "middle"}">${kurzdat(new Date(t))}</text>`;
|
||||
}).join("");
|
||||
const stufen = bvFarbstufen();
|
||||
@@ -1930,10 +1955,6 @@ function csvDatei(name, kopf, zeilen) {
|
||||
function vEinst() {
|
||||
return `
|
||||
<div class="tile"><span class="label">Fahrzeug einrichten</span>
|
||||
<span style="display:block;margin-top:10px;color:var(--fg2);
|
||||
font-size:13.5px;line-height:1.6">
|
||||
Fahrgestellnummer, Kennzeichen, Erstzulassung, Ausführung und Ölwechsel-Intervall — bei der
|
||||
Ersteinrichtung oder wenn sich diese Angaben ändern.</span>
|
||||
${einrichtenOffen ? `
|
||||
<div class="feld" style="margin-top:16px"><label for="einFin">Fahrgestellnummer (FIN)</label>
|
||||
<input id="einFin" value="${esc(CAR.fin || "")}" data-einrichten="fin"></div>
|
||||
@@ -1957,8 +1978,7 @@ function vEinst() {
|
||||
? `<dl class="rows" style="margin-top:16px">
|
||||
<div class="row"><dt>Laufleistung</dt><dd>${de(CAR.oel.herstellerKm)} km</dd></div>
|
||||
<div class="row" style="border-bottom:0"><dt>Zeit</dt><dd>${CAR.oel.herstellerMonate} Monate</dd></div>
|
||||
</dl>
|
||||
<span class="label" style="margin-top:14px">Aus dem Fahrzeug gelesen</span>`
|
||||
</dl>`
|
||||
: `<div class="feld" style="margin-top:6px"><label for="oelKm">Nach Laufleistung</label>
|
||||
<select id="oelKm" data-oelkm>${[5000, 10000, 15000, 20000].map((k) => `<option value="${k}" ${k === CAR.oel.km ? "selected" : ""}>${de(k)} km</option>`).join("")}</select></div>
|
||||
<div class="feld" style="border-bottom:0"><label for="oelM">Nach Zeit</label>
|
||||
@@ -2329,13 +2349,11 @@ function vReifen() {
|
||||
<button type="button" data-bildersetzen="${radDatei}">Foto ersetzen</button>
|
||||
<button type="button" class="loeschen" data-bildloeschen="${radDatei}">Löschen</button>
|
||||
</div>` : ""}
|
||||
<button data-satz="${k === "sommer" ? "Sommer" : "Winter"}" class="montiert ${aktiv ? "on" : ""}">Montiert</button>
|
||||
<div class="radkopf">
|
||||
<span class="label">${k === "sommer" ? "Sommer" : "Winter"}</span>
|
||||
<div class="fig" style="font-size:32px;margin-top:14px">${t.km != null ? de(t.km) : "–"}<span class="unit">km</span></div>
|
||||
</div>
|
||||
<div class="seg" style="margin-top:16px">
|
||||
<button data-satz="${k === "sommer" ? "Sommer" : "Winter"}" class="${aktiv ? "on" : ""}">Montiert</button>
|
||||
</div>
|
||||
<div style="margin-top:22px">
|
||||
${feld(k, "marke", "Hersteller")}
|
||||
${feld(k, "modell", "Modell")}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user