4395ff6ac6
Xcode ist vorhanden, die Huelle liess sich also wirklich bauen statt nur vorzubereiten: Capacitor 8 fuer iOS und Android, Build fuer den Simulator erfolgreich, App laeuft und zeigt echte Daten vom Server. CapacitorHttp eingeschaltet. Das ist keine Feinheit: die native Huelle liefert die Oberflaeche unter eigenem Ursprung aus, jede Anfrage an Home Assistant ist damit ursprungsuebergreifend, und die WebView lehnt sie ohne CORS-Freigabe ab. Nativ gestellte Anfragen kennen keine CORS-Pruefung - die App braucht dadurch keine CORS-Einstellung am Server. Drei Fehler, die erst die Bildschirmfotos zeigten: 1. Der Fahrzeug-Block auf der Uebersicht war unsichtbar. Ursache war der Flexbox-Fallstrick: "overflow: hidden" setzt die automatische Mindesthoehe auf 0, und sobald die Seite laenger ist als der Bildschirm, quetscht flex-shrink den Block auf Hoehe 0. Modellname, Typenschild und Kennzeichen waren damit schlicht weg. 2. Neben dem Typenschild stand der Modellname noch einmal komplett, obwohl das Schild ihn bereits zeigt. Das alte Panel loest das laengst richtig - nur der Zusatz gehoert daneben. Nachgezogen, samt Entdopplung, wenn die Ausfuehrung schon im Namen steckt. 3. In der Fotogalerie liefen die Dateinamen ueber den Rand der Miniaturen. Dazu: Datumszeile in Listen bricht um statt abzuschneiden, Statistik nutzt auf der Flaeche mehrere Spalten. Im Backend war das Kilometerstand-Screening kaputt: es rief urlopen direkt auf, was Home Assistant seit 2026.8 als blockierenden Aufruf abbricht. Jede Fahrt blieb dadurch ohne Strecke - sichtbar nur als Warnung im Protokoll. Laeuft jetzt ueber task.executor und rechnet an der Testinstanz wieder echte Strecken aus dem Verlauf. Die CORS-Freigabe fuer die Web-Fassung ist in der Testkonfiguration hinterlegt. Sie greift in Home Assistant 2026.8 allerdings nicht - deshalb wird die App aus Home Assistant selbst ausgeliefert (gleicher Ursprung, kein CORS), was ohnehin der geplante Weg ist. Die erzeugten Ordner ios/ und android/ bleiben ungetrackt; sie entstehen jederzeit neu aus dem Webbuendel.
596 lines
10 KiB
CSS
596 lines
10 KiB
CSS
/*
|
|
* Screen-übergreifende Bausteine: Eingabefelder, Hinweisleiste,
|
|
* Ersteinrichtung, Leerzustände, Ladeanzeige.
|
|
*/
|
|
|
|
/* -------------------------------------------------------- Eingabefelder */
|
|
|
|
.dm-eingabe,
|
|
.dm-auswahl {
|
|
font: inherit;
|
|
font-weight: 300;
|
|
font-size: 16px;
|
|
color: var(--fg);
|
|
background: none;
|
|
border: 0;
|
|
text-align: right;
|
|
outline: none;
|
|
min-width: 120px;
|
|
max-width: 60%;
|
|
padding: 0;
|
|
}
|
|
|
|
.dm-eingabe::placeholder {
|
|
color: var(--fg3);
|
|
}
|
|
|
|
.dm-auswahl {
|
|
text-align: right;
|
|
appearance: none;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.dm-auswahl option {
|
|
color: var(--fg);
|
|
background: var(--tile);
|
|
}
|
|
|
|
.dm-notiz {
|
|
font: inherit;
|
|
font-weight: 300;
|
|
font-size: 16px;
|
|
color: var(--fg);
|
|
background: var(--tile-2);
|
|
border: 0;
|
|
border-radius: var(--r-func);
|
|
padding: 10px 12px;
|
|
width: 100%;
|
|
min-height: 88px;
|
|
resize: vertical;
|
|
outline: none;
|
|
}
|
|
|
|
/* --------------------------------------------------------- Hinweisleiste */
|
|
|
|
.dm-hinweis {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--sp-2);
|
|
padding: 9px var(--sp-5);
|
|
padding-top: calc(env(safe-area-inset-top, 0px) + 9px);
|
|
font-size: 12.5px;
|
|
font-weight: 300;
|
|
color: var(--fg);
|
|
background: var(--tile-2);
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
|
|
.dm-hinweis--offline {
|
|
color: var(--warn);
|
|
}
|
|
|
|
.dm-hinweis svg {
|
|
flex: none;
|
|
}
|
|
|
|
/* -------------------------------------------------------- Ersteinrichtung */
|
|
|
|
.dm-einrichtung {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 32px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.dm-einrichtung__karte {
|
|
width: 100%;
|
|
max-width: 420px;
|
|
}
|
|
|
|
.dm-einrichtung__titel {
|
|
font-size: 28px;
|
|
font-weight: 300;
|
|
letter-spacing: -0.02em;
|
|
margin: 10px 0 12px;
|
|
}
|
|
|
|
.dm-einrichtung__text {
|
|
font-size: 14px;
|
|
font-weight: 300;
|
|
line-height: 1.55;
|
|
color: var(--fg2);
|
|
margin: 0 0 22px;
|
|
text-wrap: pretty;
|
|
}
|
|
|
|
.dm-einrichtung__fehler {
|
|
font-size: 13px;
|
|
font-weight: 300;
|
|
line-height: 1.5;
|
|
color: var(--bad);
|
|
margin: 14px 0 0;
|
|
}
|
|
|
|
.dm-einrichtung__knoepfe {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10px;
|
|
margin-top: var(--sp-4);
|
|
}
|
|
|
|
.dm-einrichtung__hinweis {
|
|
font-size: 11.5px;
|
|
font-weight: 300;
|
|
line-height: 1.5;
|
|
color: var(--fg3);
|
|
margin: 18px 0 0;
|
|
}
|
|
|
|
/* ------------------------------------------------- Leer- und Ladezustände */
|
|
|
|
.dm-leer {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
text-align: center;
|
|
gap: var(--sp-2);
|
|
padding: 44px 24px;
|
|
color: var(--fg2);
|
|
}
|
|
|
|
.dm-leer__titel {
|
|
font-size: 16px;
|
|
font-weight: 300;
|
|
color: var(--fg);
|
|
}
|
|
|
|
.dm-leer__text {
|
|
font-size: 13.5px;
|
|
font-weight: 300;
|
|
line-height: 1.55;
|
|
max-width: 34ch;
|
|
margin: 0;
|
|
text-wrap: pretty;
|
|
}
|
|
|
|
.dm-laden {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: var(--sp-2);
|
|
padding: 44px 24px;
|
|
color: var(--fg2);
|
|
font-size: 13.5px;
|
|
font-weight: 300;
|
|
}
|
|
|
|
/* ------------------------------------------------------------ Übersicht */
|
|
|
|
.dm-szene {
|
|
position: relative;
|
|
border-radius: var(--r-tile);
|
|
overflow: hidden;
|
|
background: var(--tile);
|
|
}
|
|
|
|
.dm-szene .ads-bild,
|
|
.dm-szene img {
|
|
width: 100%;
|
|
display: block;
|
|
}
|
|
|
|
.dm-szene__text {
|
|
padding: var(--sp-4) var(--sp-4) var(--sp-5);
|
|
}
|
|
|
|
.dm-tanktext {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: var(--sp-3);
|
|
margin-top: var(--sp-2);
|
|
font-size: 12.5px;
|
|
font-weight: 300;
|
|
color: var(--fg2);
|
|
}
|
|
|
|
.dm-navikachel__wert {
|
|
margin-top: var(--sp-1);
|
|
font-size: 15px;
|
|
font-weight: 300;
|
|
color: var(--fg);
|
|
}
|
|
|
|
.dm-navikachel__zahl {
|
|
font-size: 20px;
|
|
font-weight: 300;
|
|
}
|
|
|
|
.dm-navikachel__wert small,
|
|
.dm-wertzeile small {
|
|
display: block;
|
|
margin-top: 2px;
|
|
font-size: 11.5px;
|
|
color: var(--fg3);
|
|
}
|
|
|
|
.dm-aktionen {
|
|
display: flex;
|
|
justify-content: center;
|
|
padding: var(--sp-2) 0 var(--sp-4);
|
|
}
|
|
|
|
.dm-textknopf {
|
|
border: 0;
|
|
background: transparent;
|
|
color: var(--fg2);
|
|
font-size: 13px;
|
|
font-weight: 300;
|
|
padding: 10px 14px;
|
|
border-radius: var(--r-pill);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.dm-textknopf:hover:not(:disabled) {
|
|
background: var(--shade);
|
|
color: var(--fg);
|
|
}
|
|
|
|
.dm-textknopf:disabled {
|
|
opacity: 0.5;
|
|
cursor: default;
|
|
}
|
|
|
|
/* --------------------------------------------------------- Werteliste */
|
|
|
|
.dm-werteliste {
|
|
margin: var(--sp-3) 0 0;
|
|
}
|
|
|
|
.dm-wertzeile {
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
gap: var(--sp-4);
|
|
padding: 10px 0;
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
|
|
.dm-wertzeile:last-child {
|
|
border-bottom: 0;
|
|
}
|
|
|
|
.dm-wertzeile dt {
|
|
font-size: 13px;
|
|
font-weight: 300;
|
|
color: var(--fg2);
|
|
}
|
|
|
|
.dm-wertzeile dd {
|
|
margin: 0;
|
|
font-size: 14px;
|
|
font-weight: 300;
|
|
text-align: right;
|
|
}
|
|
|
|
.dm-abschnitt {
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
gap: var(--sp-3);
|
|
padding: var(--sp-3) 2px 0;
|
|
}
|
|
|
|
.dm-fussnote {
|
|
margin: var(--sp-3) 0 0;
|
|
font-size: 11.5px;
|
|
font-weight: 300;
|
|
line-height: 1.5;
|
|
color: var(--fg3);
|
|
text-wrap: pretty;
|
|
}
|
|
|
|
/* ------------------------------------------------------ Fahrzeugstatus */
|
|
|
|
.dm-pruefliste {
|
|
list-style: none;
|
|
margin: var(--sp-3) 0 0;
|
|
padding: 0;
|
|
}
|
|
|
|
.dm-pruefliste__zeile {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--sp-3);
|
|
padding: 10px 0;
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
|
|
.dm-pruefliste__zeile:last-child {
|
|
border-bottom: 0;
|
|
}
|
|
|
|
.dm-pruefliste__label {
|
|
flex: 1;
|
|
font-size: 14px;
|
|
font-weight: 300;
|
|
}
|
|
|
|
.dm-pruefliste__wert {
|
|
font-size: 12.5px;
|
|
font-weight: 300;
|
|
color: var(--fg2);
|
|
}
|
|
|
|
.dm-punkt {
|
|
flex: none;
|
|
width: 9px;
|
|
height: 9px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.dm-punkt--ok {
|
|
background: var(--ok);
|
|
}
|
|
|
|
.dm-punkt--offen {
|
|
background: var(--bad);
|
|
}
|
|
|
|
/* Unbekannt bewusst als hohler Ring: sichtbar anders als grün und als rot,
|
|
damit "keine Meldung" nie wie eine Aussage aussieht. */
|
|
.dm-punkt--unbekannt {
|
|
border: 1.5px solid var(--fg3);
|
|
}
|
|
|
|
/* ------------------------------------------------------------ Galerie */
|
|
|
|
.dm-galerie {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
|
|
gap: var(--sp-2);
|
|
margin-top: var(--sp-3);
|
|
}
|
|
|
|
/* ------------------------------------------------------- Listenzeilen */
|
|
|
|
.dm-zeile {
|
|
display: flex;
|
|
align-items: stretch;
|
|
gap: 2px;
|
|
}
|
|
|
|
.dm-zeile__wisch {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
/* Immer sichtbarer Zugang zu denselben Aktionen wie die Wischgeste — ohne ihn
|
|
waere Loeschen fuer Sprachausgabe und Schaltersteuerung unerreichbar. */
|
|
.dm-zeile__menue {
|
|
flex: none;
|
|
width: 44px;
|
|
border: 0;
|
|
background: transparent;
|
|
color: var(--fg3);
|
|
border-radius: var(--r-func);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.dm-zeile__menue:hover {
|
|
background: var(--shade);
|
|
color: var(--fg);
|
|
}
|
|
|
|
.dm-listenzeile {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--sp-3);
|
|
width: 100%;
|
|
padding: 12px 2px;
|
|
border: 0;
|
|
background: transparent;
|
|
color: inherit;
|
|
text-align: left;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.dm-listenzeile__haupt {
|
|
flex: 1;
|
|
min-width: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 3px;
|
|
}
|
|
|
|
.dm-listenzeile__titel {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: var(--sp-2);
|
|
font-size: 16px;
|
|
font-weight: 300;
|
|
}
|
|
|
|
.dm-listenzeile__neben {
|
|
font-size: 13px;
|
|
color: var(--fg2);
|
|
}
|
|
|
|
.dm-listenzeile__unter {
|
|
font-size: 12px;
|
|
font-weight: 300;
|
|
color: var(--fg3);
|
|
/* Umbrechen statt abschneiden: Datum, Uhrzeit und Dauer sind alle drei
|
|
wichtig, und "11.08.2026 · 12:27 Uhr · 3…" verliert genau die Angabe,
|
|
die man sucht. */
|
|
line-height: 1.4;
|
|
}
|
|
|
|
/* -------------------------------------------------------- Detailseiten */
|
|
|
|
.dm-detail__kopf {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: var(--sp-3);
|
|
margin: var(--sp-2) 0 var(--sp-3);
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.dm-detail__zahl {
|
|
font-size: 40px;
|
|
font-weight: 300;
|
|
line-height: 1;
|
|
letter-spacing: -0.02em;
|
|
}
|
|
|
|
.dm-detail__einheit {
|
|
font-size: 15px;
|
|
color: var(--fg2);
|
|
margin-left: 6px;
|
|
}
|
|
|
|
.dm-detail__marken {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 6px;
|
|
align-items: center;
|
|
}
|
|
|
|
.dm-karte {
|
|
height: 240px;
|
|
width: 100%;
|
|
border-radius: var(--r-func);
|
|
overflow: hidden;
|
|
margin-top: var(--sp-3);
|
|
background: var(--tile-2);
|
|
}
|
|
|
|
/* ------------------------------------------------------------ Meldungen */
|
|
|
|
.dm-fehler {
|
|
margin: var(--sp-3) 0 0;
|
|
font-size: 13px;
|
|
font-weight: 300;
|
|
line-height: 1.5;
|
|
color: var(--bad);
|
|
}
|
|
|
|
.dm-erfolg {
|
|
margin: var(--sp-3) 0 0;
|
|
font-size: 13px;
|
|
font-weight: 300;
|
|
line-height: 1.5;
|
|
color: var(--ok);
|
|
}
|
|
|
|
.dm-fussnote--warnung {
|
|
color: var(--warn);
|
|
}
|
|
|
|
/* --------------------------------------------------------- Listen, Text */
|
|
|
|
.dm-liste {
|
|
list-style: none;
|
|
margin: var(--sp-2) 0 0;
|
|
padding: 0;
|
|
font-size: 13.5px;
|
|
font-weight: 300;
|
|
line-height: 1.7;
|
|
}
|
|
|
|
.dm-liste li {
|
|
padding-left: 14px;
|
|
position: relative;
|
|
}
|
|
|
|
.dm-liste li::before {
|
|
content: "";
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0.72em;
|
|
width: 4px;
|
|
height: 4px;
|
|
border-radius: 50%;
|
|
background: var(--fg3);
|
|
}
|
|
|
|
.dm-liste__serie {
|
|
color: var(--fg2);
|
|
}
|
|
|
|
.dm-diagramm {
|
|
width: 100%;
|
|
height: 120px;
|
|
margin: var(--sp-3) 0;
|
|
display: block;
|
|
}
|
|
|
|
.dm-knopfreihe {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--sp-2);
|
|
margin-top: var(--sp-4);
|
|
}
|
|
|
|
.dm-waehlen {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--sp-2);
|
|
margin-top: var(--sp-3);
|
|
}
|
|
|
|
.dm-waehlen__knopf {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
padding: 10px 16px;
|
|
border: 1px solid var(--line-strong);
|
|
border-radius: var(--r-pill);
|
|
font-size: 13.5px;
|
|
font-weight: 300;
|
|
color: var(--fg);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.dm-waehlen__knopf:hover {
|
|
background: var(--shade);
|
|
}
|
|
|
|
/* Bleibt beim Scrollen unten stehen, damit ungespeicherte Aenderungen nicht
|
|
aus dem Blick geraten. */
|
|
.dm-speicherleiste {
|
|
position: sticky;
|
|
bottom: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--sp-3);
|
|
padding: var(--sp-3) 0;
|
|
background: var(--canvas);
|
|
border-top: 1px solid var(--line);
|
|
}
|
|
|
|
.dm-szene__zusatz {
|
|
min-width: 0;
|
|
}
|
|
|
|
/* Der Zusatz neben dem Typenschild darf umbrechen — abgeschnittener Text mit
|
|
Auslassungspunkten sieht nach Fehler aus, ein Umbruch nicht. */
|
|
.dm-szene__zusatz {
|
|
min-width: 0;
|
|
white-space: normal;
|
|
overflow: visible;
|
|
text-overflow: clip;
|
|
font-size: 19px;
|
|
line-height: 1.2;
|
|
}
|
|
|
|
/* Die Galerie richtet sich nach der festen Kachelbreite der Bibliothek (78px),
|
|
damit die Kacheln nicht auseinandergezogen werden und ihre Beschriftung
|
|
innerhalb des Rahmens bleibt. */
|
|
.dm-galerie {
|
|
grid-template-columns: repeat(auto-fill, 78px);
|
|
justify-content: space-between;
|
|
gap: var(--sp-3);
|
|
}
|