Service-Seite: Prognose-Fussnote ueber volle Breite statt umgebrochen

Gemeldet: das Datum der Oelwechsel-Prognose steht in einer eigenen Zeile.
Nachgemessen: das <small> in der rechten Spalte war 29px hoch bei 217px
Breite (zwei Zeilen); .row ist ein Flex aus dt/dd, und dd bekommt nur den
Rest neben dem Titel - fuer "9.029 km, voraussichtlich am 14.04.2027"
reicht das bei 12,5px nicht.

Statt an Schriftgroesse oder Text zu drehen, haengt die Fussnote jetzt als
eigenes Element (.row-fussnote) neben dt/dd und bricht per flex:1 0 100%
auf eine eigene Zeile ueber die volle Kachelbreite um. flex-wrap:wrap ist
per :has(.row-fussnote) auf genau diese Zeilen eingegrenzt, damit die
uebrigen .row-Verwendungen zweispaltig bleiben.

Die verschachtelte fm-/nicht-fm-Verzweigung im Markup faellt dabei zu
einem hatMeldung-Zweig fuer den Wert plus einem separaten fussnote-String
zusammen; die Anzeigelogik selbst ist unveraendert.

Live geprueft bei 375px und 1280px: beide Fussnoten einzeilig (14px),
307px bzw. 636px breit; alle 17 .row auf "Mein Audi" weiterhin
zweispaltig; keine neuen Konsolenfehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-08-17 19:08:06 +02:00
co-authored by Claude Opus 5
parent 7fc378f427
commit 7319501ee6
9 changed files with 72 additions and 18 deletions
+18
View File
@@ -1327,6 +1327,24 @@ wraps the web app for iPhone; a PWA home-screen install is the accepted intermed
All five deployed to `audi_ha_test` (version `1787009000`) and synced to `installationspaket/`; All five deployed to `audi_ha_test` (version `1787009000`) and synced to `installationspaket/`;
console showed only the pre-existing service-worker/404 noise from the missing vehicle photos, console showed only the pre-existing service-worker/404 noise from the missing vehicle photos,
nothing new. nothing new.
- [x] Service-Seite: Prognose-Fussnote bricht nicht mehr um (2026-08-17) — Nutzermeldung, das Datum
der Ölwechsel-Prognose stehe in einer eigenen Zeile. Nachgemessen statt geschätzt: das
`<small>` in der rechten Spalte war 29px hoch bei 217px Breite (zwei Zeilen), die
Inspektions-Fussnote darunter mit kürzerem Text 14px (eine). Ursache ist nicht die Textlänge
allein, sondern der Platz: `.row` ist ein Flex mit `dt`/`dd`, und `dd` bekommt nur den Rest
neben dem Titel - für "9.029 km, voraussichtlich am 14.04.2027" bei 12,5px reicht das nicht.
Statt an Schriftgröße oder Text zu drehen, wandert die Fussnote jetzt als eigenes Element
(`.row-fussnote`) neben `dt`/`dd` und umbricht per `flex:1 0 100%` auf eine eigene Zeile über
die **volle** Kachelbreite - dieselbe Stelle, an der sie vorher schon optisch stand, nur ohne
die künstliche Breitenbegrenzung. Das `flex-wrap:wrap` ist bewusst mit `:has(.row-fussnote)`
auf genau diese Zeilen eingegrenzt, damit keine der übrigen `.row`-Verwendungen (17 Zeilen
allein auf "Mein Audi") ihr zweispaltiges Layout verliert. Die vorher verschachtelte
fm-/nicht-fm-Verzweigung im Markup ist dabei zu einem `hatMeldung`-Zweig für den Wert plus
einem separat berechneten `fussnote`-String zusammengefallen - die Anzeigelogik selbst
(Ölwechsel-Fussnote nur bei Fahrzeugmeldung, Inspektion immer) ist unverändert. Live geprüft
bei 375px und 1280px: beide Fussnoten 14px hoch (einzeilig), 307px bzw. 636px breit, linksbündig
auf der Kachelkante; alle 17 `.row` auf "Mein Audi" weiterhin zweispaltig; keine neuen
Konsolenfehler. Deployed als Version `1787003000`, synchron in `installationspaket/`.
- [x] **Gap found while auditing "what's needed for a real iPhone app" (2026-08-17), then closed - [x] **Gap found while auditing "what's needed for a real iPhone app" (2026-08-17), then closed
the same day:** `companion-app/src/screens/` hadn't been touched since 2026-08-11 — every the same day:** `companion-app/src/screens/` hadn't been touched since 2026-08-11 — every
panel fix and feature from the six days since (HIG audit rounds, receipt upload, trip panel fix and feature from the six days since (HIG audit rounds, receipt upload, trip
@@ -1663,21 +1663,25 @@ function vService() {
// dem Datum. Hauptuntersuchung bleibt bewusst ohne. // dem Datum. Hauptuntersuchung bleibt bewusst ohne.
const eigenOel = t.art === "Ölwechsel" ? oelwechselPrognose() : null; const eigenOel = t.art === "Ölwechsel" ? oelwechselPrognose() : null;
const eigenInsp = t.art === "Inspektion" ? inspektionPrognose() : null; const eigenInsp = t.art === "Inspektion" ? inspektionPrognose() : null;
const hatMeldung = fm.km != null || fmDatum;
// Die Prognose steht als eigene Zeile ueber die volle Kachelbreite
// unter dt/dd (.row-fussnote), nicht mehr in der rechten Spalte: dort
// standen nur ~217px zur Verfuegung, in die "9.029 km, voraussichtlich
// am 12.04.2027" zwangslaeufig zweizeilig umbrach.
const fussnote = hatMeldung && eigenOel
? `${de(eigenOel.restKm)} km, voraussichtlich am ${dedat(eigenOel.datum)}`
: eigenInsp ? `voraussichtlich am ${dedat(eigenInsp.datum)}` : "";
return `<div class="row" ${letzte}> return `<div class="row" ${letzte}>
<dt>${t.art} <dt>${t.art}
${t.vereinbart ? `<br><span style="color:var(--red);font-size:11px">Werkstatt am ${dedat(new Date(t.vereinbart))}</span>` : ""} ${t.vereinbart ? `<br><span style="color:var(--red);font-size:11px">Werkstatt am ${dedat(new Date(t.vereinbart))}</span>` : ""}
</dt> </dt>
<dd> <dd>
${iv.hersteller ? `<span class="label" style="margin-bottom:6px">Herstellervorgabe</span>` : ""} ${iv.hersteller ? `<span class="label" style="margin-bottom:6px">Herstellervorgabe</span>` : ""}
${fm.km != null || fmDatum ? ` <span class="werte">${hatMeldung
<span class="werte">${fm.km != null ? de(fm.km) + " km" : ""}${fm.km != null && fmDatum ? " / " : ""}${fmDatum || ""}</span> ? `${fm.km != null ? de(fm.km) + " km" : ""}${fm.km != null && fmDatum ? " / " : ""}${fmDatum || ""}`
${eigenOel ? `<small style="text-align:left">${de(eigenOel.restKm)} km, voraussichtlich am ${dedat(eigenOel.datum)}</small>` : ""} : (eigenOel ? de(eigenOel.restKm) + " km · " + dedat(eigenOel.datum) : (anzeige.km !== null ? de(anzeige.km) + " km · " : "") + dedat(anzeige.datum))}</span>
${eigenInsp ? `<small style="text-align:left">voraussichtlich am ${dedat(eigenInsp.datum)}</small>` : ""}
` : `
<span class="werte">${eigenOel ? de(eigenOel.restKm) + " km · " + dedat(eigenOel.datum) : (anzeige.km !== null ? de(anzeige.km) + " km · " : "") + dedat(anzeige.datum)}</span>
${eigenInsp ? `<small style="text-align:left">voraussichtlich am ${dedat(eigenInsp.datum)}</small>` : ""}
`}
</dd> </dd>
${fussnote ? `<small class="row-fussnote">${fussnote}</small>` : ""}
</div>`; }).join("")} </div>`; }).join("")}
</dl> </dl>
</div> </div>
@@ -123,6 +123,7 @@ main#view{--seitenrand:16px;padding:0 var(--seitenrand) 30px;scroll-behavior:smo
.row dt{font-size:16px;color:var(--fg)} .row dt{font-size:16px;color:var(--fg)}
.row dd{font-size:16px;color:var(--fg2)} .row dd{font-size:16px;color:var(--fg2)}
.row dd small{font-size:12.5px;margin-top:2px} .row dd small{font-size:12.5px;margin-top:2px}
.row-fussnote{font-size:12.5px}
.rows-fest dt{flex:0 0 150px} .rows-fest dt{flex:0 0 150px}
.chev{stroke:var(--ios-grau);stroke-width:1.6} .chev{stroke:var(--ios-grau);stroke-width:1.6}
@@ -1 +1 @@
{"version": 1787100000} {"version": 1787003000}
@@ -405,6 +405,19 @@ button.tile, .tilebtn { transition: background .15s, transform .1s; }
.row dd { margin: 0; font-size: 14.5px; color: var(--fg); text-align: right; } .row dd { margin: 0; font-size: 14.5px; color: var(--fg); text-align: right; }
.row dd small { display: block; font-size: 11.5px; color: var(--fg3); margin-top: 3px; } .row dd small { display: block; font-size: 11.5px; color: var(--fg3); margin-top: 3px; }
.rows-fest dd { min-width: 120px; } .rows-fest dd { min-width: 120px; }
/* Fussnote unter einer Zeile, ueber die volle Kachelbreite statt in der
rechten Spalte: dort blieben nur ~217px, in die eine Prognose wie
"9.029 km, voraussichtlich am 12.04.2027" zwangslaeufig umbrach.
:has() grenzt das Umbrechen auf genau die Zeilen ein, die eine Fussnote
fuehren - alle anderen .row bleiben unveraendert einzeilig. */
.row:has(.row-fussnote) { flex-wrap: wrap; }
.row-fussnote {
flex: 1 0 100%;
text-align: left;
font-size: 11.5px;
color: var(--fg3);
margin-top: 4px;
}
.leaf { .leaf {
display: flex; align-items: center; justify-content: space-between; display: flex; align-items: center; justify-content: space-between;
+12 -8
View File
@@ -1663,21 +1663,25 @@ function vService() {
// dem Datum. Hauptuntersuchung bleibt bewusst ohne. // dem Datum. Hauptuntersuchung bleibt bewusst ohne.
const eigenOel = t.art === "Ölwechsel" ? oelwechselPrognose() : null; const eigenOel = t.art === "Ölwechsel" ? oelwechselPrognose() : null;
const eigenInsp = t.art === "Inspektion" ? inspektionPrognose() : null; const eigenInsp = t.art === "Inspektion" ? inspektionPrognose() : null;
const hatMeldung = fm.km != null || fmDatum;
// Die Prognose steht als eigene Zeile ueber die volle Kachelbreite
// unter dt/dd (.row-fussnote), nicht mehr in der rechten Spalte: dort
// standen nur ~217px zur Verfuegung, in die "9.029 km, voraussichtlich
// am 12.04.2027" zwangslaeufig zweizeilig umbrach.
const fussnote = hatMeldung && eigenOel
? `${de(eigenOel.restKm)} km, voraussichtlich am ${dedat(eigenOel.datum)}`
: eigenInsp ? `voraussichtlich am ${dedat(eigenInsp.datum)}` : "";
return `<div class="row" ${letzte}> return `<div class="row" ${letzte}>
<dt>${t.art} <dt>${t.art}
${t.vereinbart ? `<br><span style="color:var(--red);font-size:11px">Werkstatt am ${dedat(new Date(t.vereinbart))}</span>` : ""} ${t.vereinbart ? `<br><span style="color:var(--red);font-size:11px">Werkstatt am ${dedat(new Date(t.vereinbart))}</span>` : ""}
</dt> </dt>
<dd> <dd>
${iv.hersteller ? `<span class="label" style="margin-bottom:6px">Herstellervorgabe</span>` : ""} ${iv.hersteller ? `<span class="label" style="margin-bottom:6px">Herstellervorgabe</span>` : ""}
${fm.km != null || fmDatum ? ` <span class="werte">${hatMeldung
<span class="werte">${fm.km != null ? de(fm.km) + " km" : ""}${fm.km != null && fmDatum ? " / " : ""}${fmDatum || ""}</span> ? `${fm.km != null ? de(fm.km) + " km" : ""}${fm.km != null && fmDatum ? " / " : ""}${fmDatum || ""}`
${eigenOel ? `<small style="text-align:left">${de(eigenOel.restKm)} km, voraussichtlich am ${dedat(eigenOel.datum)}</small>` : ""} : (eigenOel ? de(eigenOel.restKm) + " km · " + dedat(eigenOel.datum) : (anzeige.km !== null ? de(anzeige.km) + " km · " : "") + dedat(anzeige.datum))}</span>
${eigenInsp ? `<small style="text-align:left">voraussichtlich am ${dedat(eigenInsp.datum)}</small>` : ""}
` : `
<span class="werte">${eigenOel ? de(eigenOel.restKm) + " km · " + dedat(eigenOel.datum) : (anzeige.km !== null ? de(anzeige.km) + " km · " : "") + dedat(anzeige.datum)}</span>
${eigenInsp ? `<small style="text-align:left">voraussichtlich am ${dedat(eigenInsp.datum)}</small>` : ""}
`}
</dd> </dd>
${fussnote ? `<small class="row-fussnote">${fussnote}</small>` : ""}
</div>`; }).join("")} </div>`; }).join("")}
</dl> </dl>
</div> </div>
+1
View File
@@ -123,6 +123,7 @@ main#view{--seitenrand:16px;padding:0 var(--seitenrand) 30px;scroll-behavior:smo
.row dt{font-size:16px;color:var(--fg)} .row dt{font-size:16px;color:var(--fg)}
.row dd{font-size:16px;color:var(--fg2)} .row dd{font-size:16px;color:var(--fg2)}
.row dd small{font-size:12.5px;margin-top:2px} .row dd small{font-size:12.5px;margin-top:2px}
.row-fussnote{font-size:12.5px}
.rows-fest dt{flex:0 0 150px} .rows-fest dt{flex:0 0 150px}
.chev{stroke:var(--ios-grau);stroke-width:1.6} .chev{stroke:var(--ios-grau);stroke-width:1.6}
@@ -1 +1 @@
{"version": 1787100000} {"version": 1787003000}
+13
View File
@@ -405,6 +405,19 @@ button.tile, .tilebtn { transition: background .15s, transform .1s; }
.row dd { margin: 0; font-size: 14.5px; color: var(--fg); text-align: right; } .row dd { margin: 0; font-size: 14.5px; color: var(--fg); text-align: right; }
.row dd small { display: block; font-size: 11.5px; color: var(--fg3); margin-top: 3px; } .row dd small { display: block; font-size: 11.5px; color: var(--fg3); margin-top: 3px; }
.rows-fest dd { min-width: 120px; } .rows-fest dd { min-width: 120px; }
/* Fussnote unter einer Zeile, ueber die volle Kachelbreite statt in der
rechten Spalte: dort blieben nur ~217px, in die eine Prognose wie
"9.029 km, voraussichtlich am 12.04.2027" zwangslaeufig umbrach.
:has() grenzt das Umbrechen auf genau die Zeilen ein, die eine Fussnote
fuehren - alle anderen .row bleiben unveraendert einzeilig. */
.row:has(.row-fussnote) { flex-wrap: wrap; }
.row-fussnote {
flex: 1 0 100%;
text-align: left;
font-size: 11.5px;
color: var(--fg3);
margin-top: 4px;
}
.leaf { .leaf {
display: flex; align-items: center; justify-content: space-between; display: flex; align-items: center; justify-content: space-between;