Ladefenster neu: Zustand zuerst, Modus als Karten, Aenderungen sofort

Nach dem abgestimmten Entwurf: Ladestand als Ring mit Ziel, Leistung,
Sonnenanteil und fertig um; ein grosser Knopf, der sich nach der gemeldeten
Freigabe (frc) richtet - "Laden stoppen", "Ladung freigeben" (zurueck zum
Modus statt dauerhaft gesperrt), "Jetzt laden", ohne Auto ausgegraut.
Modus als Karten (Sofort, Sonne, Geplant), Planung nur bei "Geplant": mit
Ladestand des Autos als Ziel-Ladestand, sonst als zusaetzliche Prozent;
Abfahrt per Schnellwahl. Ladestrom als Segmente mit kW.

Jede Aenderung geht sofort als JSON an carSteuerung.php (frc, modus, strom,
plan) statt ueber "Save changes"; die Logik steht in js/solar/ladefenster.js.
Am 800er-Display zweispaltig ohne Scrollen.

Nebenbei: die Uebersicht las die Restladezeit aus carRemChrg, das der
Manager nicht mehr schickt - jetzt evRemChrgTime.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 20:40:29 +02:00
co-authored by Claude Opus 5
parent 2e66bdeff5
commit b0bac3d3ba
9 changed files with 564 additions and 237 deletions
+105
View File
@@ -3949,6 +3949,111 @@ body.anzeige-ohne-maus * { cursor: none !important; }
.anzeige-ruhig .enf.enf-pause .enf-strom { animation: none !important; }
.anzeige-ruhig .enf .enf-koerper { transition: none; }
/* ==========================================================================
Ladefenster der Wallboxen (ajax/carForm.php, js/solar/ladefenster.js).
Oben der Zustand, dann ein Knopf, darunter Modus, Planung, Strom.
========================================================================== */
.lade { display: grid; gap: 1rem; padding: 1rem 1.1rem 1.1rem; --lade-wallbox: #60afbf; }
.lade .lade-links,
.lade .lade-rechts { display: grid; gap: .9rem; align-content: start; min-width: 0; }
.lade .lade-status { display: grid; grid-template-columns: 7.5rem minmax(0, 1fr); gap: .9rem; align-items: center; }
.lade .lade-ring { position: relative; width: 7.5rem; height: 7.5rem; }
.lade .lade-ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.lade .lade-spur { fill: none; stroke: #2b3237; stroke-width: 12; }
.lade .lade-ist { fill: none; stroke: #6cbe58; stroke-width: 12; stroke-linecap: round; stroke-dasharray: 0 100; transition: stroke-dasharray .7s cubic-bezier(.2, .7, .2, 1); }
.lade .lade-ziel { fill: none; stroke: var(--lade-wallbox); stroke-width: 12; opacity: .45; stroke-dasharray: 0 100; transition: stroke-dasharray .7s, stroke-dashoffset .7s; }
.lade .lade-ring-mitte { position: absolute; inset: 0; display: grid; place-content: center; text-align: center; }
.lade .lade-ring-mitte b { font-size: 1.55rem; font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums; }
.lade .lade-ring-mitte span { font-size: .7rem; color: var(--lade-wallbox); font-weight: 600; margin-top: .25rem; }
.lade .lade-text { display: grid; gap: .25rem; min-width: 0; }
.lade .lade-auto { font-size: .8rem; color: var(--ton-schrift-2, #9aa6ad); display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.lade .lade-pille { font-size: .68rem; font-weight: 600; border-radius: 99px; padding: .05rem .5rem; background: rgba(255, 255, 255, .06); color: var(--ton-schrift-2, #9aa6ad); }
.lade .lade-pille:empty { display: none; }
.lade .lade-pille.an { color: #6cbe58; background: rgba(108, 190, 88, .14); }
.lade .lade-gross { font-size: 1.45rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.lade .lade-gross small { font-size: .8rem; font-weight: 400; color: var(--ton-schrift-2, #9aa6ad); margin-left: .35rem; }
.lade .lade-zeile { font-size: .82rem; color: var(--ton-schrift-2, #9aa6ad); }
.lade .lade-zeile:empty { display: none; }
.lade .lade-start {
all: unset; box-sizing: border-box; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: .6rem;
height: 3.1rem; border-radius: .9rem; font-weight: 600; font-size: 1rem;
background: linear-gradient(180deg, #6cbe58, #57a646); color: #0f1a0c; box-shadow: 0 .35rem 1rem rgba(108, 190, 88, .22);
transition: transform .15s, filter .2s;
}
.lade .lade-start:hover { filter: brightness(1.06); }
.lade .lade-start:active { transform: scale(.98); }
.lade .lade-start:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.lade .lade-start.laeuft { background: linear-gradient(180deg, #3a4147, #30363b); color: var(--ton-schrift, #e8ede9); box-shadow: none; border: 1px solid var(--ton-linie, rgba(138, 148, 158, .2)); }
.lade .lade-start.aus { background: #2b3237; color: var(--ton-schrift-3, #6f7a81); box-shadow: none; cursor: default; }
.lade .lade-start.aus .lade-punkt { display: none; }
.lade .lade-start.gesperrt { background: linear-gradient(180deg, #e8a33a, #cf8f2c); color: #1d1406; box-shadow: 0 .35rem 1rem rgba(232, 163, 58, .2); }
.lade .lade-punkt { width: .55rem; height: .55rem; border-radius: 50%; background: currentColor; }
.lade .lade-start.laeuft .lade-punkt { background: #6cbe58; animation: lade-puls 1.6s infinite; }
@keyframes lade-puls { 0% { box-shadow: 0 0 0 0 rgba(108, 190, 88, .6); } 70%, 100% { box-shadow: 0 0 0 .5rem rgba(108, 190, 88, 0); } }
.lade .lade-erklaerung { padding: .5rem .7rem; border-radius: .6rem; background: rgba(96, 175, 191, .1); color: #bfe3ea; font-size: .8rem; }
.lade .lade-erklaerung:empty { display: none; }
.lade .lade-abschnitt { display: grid; gap: .45rem; }
.lade h3 { margin: 0; font-size: .7rem; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--ton-schrift-2, #9aa6ad); }
.lade .lade-modi { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .45rem; }
.lade .lade-modus {
all: unset; box-sizing: border-box; cursor: pointer; display: grid; gap: .2rem; justify-items: start; padding: .6rem .65rem;
border-radius: .75rem; background: var(--ton-flaeche-2, #2b3237); border: 1.5px solid transparent; transition: border-color .2s, background .2s;
}
.lade .lade-modus:hover { background: #333b41; }
.lade .lade-modus:focus-visible { outline: 2px solid var(--lade-wallbox); outline-offset: 1px; }
.lade .lade-modus b { font-weight: 600; font-size: .88rem; }
.lade .lade-modus > span:last-child { font-size: .7rem; color: var(--ton-schrift-2, #9aa6ad); line-height: 1.3; }
.lade .lade-sym { width: 1.7rem; height: 1.7rem; border-radius: .5rem; display: grid; place-items: center; background: rgba(255, 255, 255, .06); }
.lade .lade-sym svg { width: 1.1rem; height: 1.1rem; stroke: var(--c); fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.lade .lade-modus[aria-checked="true"] { border-color: var(--c); background: color-mix(in srgb, var(--c) 12%, var(--ton-flaeche-2, #2b3237)); }
.lade .lade-modus[aria-checked="true"] .lade-sym { background: color-mix(in srgb, var(--c) 25%, transparent); }
.lade .lade-planung { display: grid; gap: .7rem; padding: .7rem .75rem; border-radius: .75rem; background: var(--ton-flaeche-2, #2b3237); animation: lade-auf .3s cubic-bezier(.2, .7, .2, 1); }
.lade .lade-planung[hidden] { display: none; }
@keyframes lade-auf { from { opacity: 0; transform: translateY(-.35rem); } }
.lade .lade-plan-zeile { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; }
.lade .lade-plan-zeile label { font-size: .82rem; color: var(--ton-schrift-2, #9aa6ad); margin: 0; }
.lade .lade-plan-zeile output { font-weight: 600; font-variant-numeric: tabular-nums; }
.lade .lade-plan-zeile output small { color: var(--ton-schrift-2, #9aa6ad); font-weight: 400; margin-left: .3rem; }
.lade input[type="range"] { -webkit-appearance: none; appearance: none; width: 100%; height: 1.9rem; background: transparent; margin: 0; }
.lade input[type="range"]::-webkit-slider-runnable-track { height: .5rem; border-radius: .25rem; background: linear-gradient(90deg, #6cbe58 0 var(--ist, 0%), var(--lade-wallbox) var(--ist, 0%) var(--wert, 0%), #394046 var(--wert, 0%)); }
.lade input[type="range"]::-moz-range-track { height: .5rem; border-radius: .25rem; background: linear-gradient(90deg, #6cbe58 0 var(--ist, 0%), var(--lade-wallbox) var(--ist, 0%) var(--wert, 0%), #394046 var(--wert, 0%)); }
.lade input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 1.6rem; height: 1.6rem; margin-top: -.55rem; border-radius: 50%; background: #fff; border: 4px solid var(--lade-wallbox); box-shadow: 0 .15rem .5rem rgba(0, 0, 0, .4); }
.lade input[type="range"]::-moz-range-thumb { width: 1.1rem; height: 1.1rem; border-radius: 50%; background: #fff; border: 4px solid var(--lade-wallbox); }
.lade input[type="range"]:focus-visible { outline: 2px solid var(--lade-wallbox); outline-offset: 4px; }
.lade .lade-marken { display: flex; justify-content: space-between; font-size: .68rem; color: var(--ton-schrift-3, #6f7a81); margin-top: -.2rem; }
.lade .lade-chips { display: flex; flex-wrap: wrap; gap: .35rem; }
.lade .lade-chip { all: unset; cursor: pointer; padding: .35rem .7rem; border-radius: 99px; background: #363d43; font-size: .8rem; font-weight: 500; font-variant-numeric: tabular-nums; }
.lade .lade-chip[aria-pressed="true"] { background: var(--lade-wallbox); color: #0c1a1d; font-weight: 600; }
.lade .lade-chip:focus-visible { outline: 2px solid var(--lade-wallbox); outline-offset: 1px; }
.lade .lade-chip input { all: unset; width: 4.6ch; font: inherit; color: inherit; }
.lade .lade-strom { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .3rem; padding: .25rem; border-radius: .75rem; background: var(--ton-flaeche-2, #2b3237); }
.lade .lade-strom button { all: unset; cursor: pointer; text-align: center; padding: .45rem .2rem; border-radius: .55rem; display: grid; gap: .05rem; }
.lade .lade-strom button b { font-weight: 600; }
.lade .lade-strom button span { font-size: .68rem; color: var(--ton-schrift-2, #9aa6ad); }
.lade .lade-strom button[aria-checked="true"] { background: #363d43; box-shadow: inset 0 0 0 1.5px var(--lade-wallbox); }
.lade .lade-strom button:focus-visible { outline: 2px solid var(--lade-wallbox); }
.lade .lade-meldung { font-size: .76rem; color: var(--ton-schrift-3, #6f7a81); }
.lade .lade-meldung.gut { color: #6cbe58; }
.lade .lade-meldung.fehler { color: #e5624f; }
@media (max-width: 420px) { .lade .lade-modus > span:last-child { display: none; } }
/* Am 800er-Display zweispaltig ohne Scrollen. */
.anzeige #modalEV .modal-dialog:has(.lade) { max-width: 46rem; }
.anzeige .lade { grid-template-columns: 15rem minmax(0, 1fr); gap: 1rem; padding: .7rem .9rem; }
.anzeige .lade .lade-status { grid-template-columns: 1fr; justify-items: center; text-align: center; gap: .5rem; }
.anzeige .lade .lade-auto { justify-content: center; }
.anzeige .lade .lade-modus > span:last-child { display: none; }
.anzeige .lade .lade-rechts,
.anzeige .lade .lade-links { gap: .6rem; }
.anzeige #modalEV .modal-body:has(.lade) { max-height: none; overflow: visible; }
.anzeige #modalEV .modal-content:has(.lade) .modal-footer { display: none; }
.anzeige #modalEV .modal-content:has(.lade) .modal-header { padding: .45rem .9rem; }
/* --- Karte: Umschalter Übersicht / Anlage -------------------------------- */
.enf-umschalter { display: inline-flex; gap: 2px; padding: 3px; border-radius: var(--ton-radius-klein, .5rem); background: var(--ton-grund, #191d20); }
.enf-umschalter .btn.btn-sm { border: 0; color: var(--ton-schrift-2, #9aa6ad); font-weight: 600; padding: .2rem .8rem; }