Files
Smart-Dashboard/css/solar.css
T
adminandClaude Opus 5 08e8e68a61 Raum-Modal: Solltemperatur wirkt sofort, kein Speichern-Knopf mehr
Im Raum-Modal wirkt jedes Bedienelement sofort - der Rollladen faehrt, der
Schalter schaltet, die Lampe leuchtet. Nur die Solltemperatur wartete auf
"Save changes". Sie schickt jetzt beim Loslassen des Reglers, wie die
Rollladenregler daneben, und der Knopf ist im Raum-Modal weg. Einer, der
nur fuer einen der Reiter gilt, waere in allen anderen eine Falle.

Das Modal bleibt nach dem Schicken offen; frueher schloss es sich, weil
der Knopf das Ende der Bedienung war. Wer dreimal nachjustiert, will nicht
dreimal neu aufmachen. Die Heizungskarte traegt dafuer dieselbe Sperre wie
die Geraetekarten - waehrend das Kommando unterwegs ist, ist sie gesperrt.

Dabei einen Fehler mitgenommen: der Speichern-Knopf gehoert allen Modals
gemeinsam, und wer ihn versteckt, versteckt ihn fuer alle. Ein Raum ohne
Thermostat liess ihn schon bisher verschwinden - danach hatten der
AutoAction-Editor und die Raumzuordnung bis zum Neuladen keinen
Speichern-Knopf mehr. Beide holen ihn jetzt wieder hervor. Nachgemessen:
im Raum-Modal versteckt, im Editor und in der Raumzuordnung sichtbar.

Die Fahrknoepfe sind von 34 auf 50 Pixel gewachsen - sie sind das, was man
im Vorbeigehen antippt, die Regler daneben braucht man seltener.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 22:20:15 +02:00

378 lines
11 KiB
CSS

.winddir {
position:absolute;
left:60%;
width:25%;
height:40%;
padding: 0;
background-image: url('../assets/img/arrow.svg');
background-size:contain;
background-repeat: no-repeat;
background-position: center;
}
/* Schieberegler in den Modals (Autoladung, Heizstab, Thermostat).
Der gefuellte Anteil kommt aus --background-size, gesetzt von
bindModalSlider() in js/solar/common.js. */
input[type='range']::-webkit-slider-runnable-track {
background: linear-gradient(to right, #00788F, #00788F), #D7D7D7;
background-size: var(--background-size, 0%) 100%;
background-repeat: no-repeat;
}
/* Diagramme (Chart.js). Die Hoehe kommt aus diesem Container, nicht aus dem
canvas - die Charts laufen mit maintainAspectRatio: false. Auf dem Handy
ist der Container nur rund 300 px breit; mit 400 px Hoehe wird aus einer
Zeitreihe ein Hochformat, in dem die Zeitachse die kurze Seite ist. */
.chart-container {
position: relative;
width: 100%;
height: 400px;
}
@media (max-width: 767.98px) {
.chart-container {
height: 250px;
}
}
/* Statistik-Kacheln (ajax/getStats.php). Sie lagen in nackten .col ohne
Breitenangabe - Bootstrap laesst sie dann nach Textlaenge umbrechen, mal
zwei, mal drei je Zeile und unterschiedlich breit. Die Breite kommt jetzt
aus row-cols-* in getStats.php; hier sorgt die volle Kartenhoehe dafuer,
dass die Werte trotz ein- oder zweizeiliger Titel auf einer Linie
stehen. */
.card.stats {
height: 100%;
}
.card.stats .card-body {
flex: 1 1 auto;
}
/* Auf dem Handy gehen von 375 px rund 75 an Innenabstaende verloren, und
zwischen den Karten stehen 24 px. Beides wird hier enger gefasst - nur
im Inhaltsbereich, damit Seitenleiste, Kopfzeile und Modals unberuehrt
bleiben. Die Abstandsklassen von Bootstrap (mb-4) tragen !important,
deshalb steht es auch hier. */
@media (max-width: 767.98px) {
.app-content {
padding: 0 .25rem;
}
.app-content-header {
padding: .5rem .25rem;
}
.app-content .row {
--bs-gutter-x: .5rem;
}
.app-content .card {
margin-bottom: .75rem !important;
}
/* Nur der Standardwert wird kleiner; eigene Angaben im Markup (p-0 fuer
das Realtime-SVG, p-2 fuer die Statistik) gelten weiter. */
.app-content .card-body {
padding: .5rem;
}
/* Eine Kachel ist auf dem Handy rund 150 px breit. In voller Schrift
passt "Verbrauchsersparnis" dort nicht in eine Zeile und wird mitten
im Wort umbrochen. */
.card.stats .card-body {
font-size: .8rem;
}
}
/* Editor der Automatiken. Eine Bedingungszeile traegt Geraet, Messwert,
Vergleich, Wert, Einheit und den Papierkorb nebeneinander - auf einem
Handy bleiben davon "Therm OG Bad" und "te" uebrig, weil die Felder in
der input-group einfach mitschrumpfen. Unter 576 px bekommen deshalb
Geraet und Messwert je eine eigene Zeile; Vergleich, Wert und Einheit
sind kurz genug, um zusammen in die naechste zu passen. */
@media (max-width: 575.98px) {
/* Die input-group-Klasse muss mit in den Selektor: solar.css wird vor
AdminLTE geladen, und Bootstraps ".input-group > .form-select" haette
sonst dasselbe Gewicht und wuerde als spaeteres Blatt gewinnen. */
.input-group.auto-zeile > .auto-geraet,
.input-group.auto-zeile > .auto-messwert {
flex: 1 1 100%;
width: auto;
}
}
/* Raum-Modal. Ein Kommando mit mehreren Parametern ("Position+Neigung")
traegt Beschriftung, zwei Zahlenfelder und den Ausloeseknopf in einer
input-group - auf einem Handy schrumpfen die Felder dabei auf Nullbreite.
Eine Mindestbreite laesst die Zeile stattdessen umbrechen. */
.input-group.raum-cmd > .form-control,
.input-group.raum-cmd > .form-select {
min-width: 5rem;
}
/* --------------------------------------------------------------------------
Raum-Modal: Bedienelemente
Erzeugt von restricted/roomControls.php, verdrahtet in js/solar/homeMQTT.js.
-------------------------------------------------------------------------- */
/* Die Geraetegruppen als Reiter. Auf einem Handy passen fuenf
Beschriftungen nicht nebeneinander - dann scrollt die Leiste seitwaerts,
statt die Namen umzubrechen. Die durchgehende Linie unter den Reitern
darf dabei nicht mitscrollen, sie gehoert an den unteren Rand. */
.raum-tabs {
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: none;
flex-wrap: nowrap;
}
.raum-tabs::-webkit-scrollbar {
display: none;
}
.raum-tabs .nav-link {
padding: 0.3rem 0.7rem;
font-size: 0.8rem;
white-space: nowrap;
border-bottom-color: transparent;
}
/* Waehrend ein Kommando unterwegs ist. Ein "Zu" an einer Jalousie dauert
ueber eine Minute; ohne sichtbare Sperre tippt man in der Zeit nach. */
.raum-geraet.raum-warte {
opacity: 0.55;
pointer-events: none;
}
.raum-geraet.raum-warte::after {
content: "";
position: absolute;
top: 0.5rem;
right: 0.5rem;
width: 0.9rem;
height: 0.9rem;
border: 2px solid currentColor;
border-right-color: transparent;
border-radius: 50%;
animation: raum-dreht 0.8s linear infinite;
}
.raum-geraet {
position: relative;
}
@keyframes raum-dreht {
to { transform: rotate(360deg); }
}
/* --------------------------------------------------------------------------
Regler im Raum-Modal
Eigenes Aussehen statt des Bootstrap-Standards: dessen weisse Bahn mit dem
blauen Griff sticht auf den dunklen Karten heraus, und in einem Raum mit
drei Jalousien sind das sechs helle Balken. Bahn und Griff tragen deshalb
dasselbe Blaugruen wie der Temperaturregler, und der ungefuellte Teil ist
ein Grau, das in beiden Themes traegt.
Bewusst nur innerhalb von #roomView: die Regler in den Modals fuer
Autoladung und Heizstab bleiben, wie sie sind.
-------------------------------------------------------------------------- */
#roomView input[type='range'] {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 1.5rem;
padding: 0;
margin: 0;
background: transparent;
}
#roomView input[type='range']:focus {
outline: 0;
}
/* Getrennt notiert, nicht als Liste: einen Selektor, den er nicht kennt,
wirft der Browser samt der ganzen Regel weg - und dann bliebe die Bahn
ungestaltet. */
#roomView input[type='range']::-webkit-slider-runnable-track {
height: 0.375rem;
border: 0;
border-radius: 0.375rem;
background: linear-gradient(to right, #00788F, #00788F), rgba(128, 128, 128, 0.32);
background-size: var(--background-size, 0%) 100%;
background-repeat: no-repeat;
}
#roomView input[type='range']::-moz-range-track {
height: 0.375rem;
border: 0;
border-radius: 0.375rem;
background: linear-gradient(to right, #00788F, #00788F), rgba(128, 128, 128, 0.32);
background-size: var(--background-size, 0%) 100%;
background-repeat: no-repeat;
}
#roomView input[type='range']::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 1.05rem;
height: 1.05rem;
/* (Bahnhoehe - Griffhoehe) / 2, damit der Griff auf der Bahn sitzt. */
margin-top: -0.34rem;
border: 2px solid #fff;
border-radius: 50%;
background: #00788F;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}
#roomView input[type='range']::-moz-range-thumb {
width: 1.05rem;
height: 1.05rem;
border: 2px solid #fff;
border-radius: 50%;
background: #00788F;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}
/* Schieberegler stehen dicht untereinander (Helligkeit, Farbe). Ohne den
Abstand kleben Beschriftung und Bahn aneinander.
Die senkrechten Spalten stehen dagegen nebeneinander - dort wuerde der
Abstand die zweite Spalte um genau diese 0,35 rem tiefer setzen. */
.raum-regler + .raum-regler:not(.raum-spalte) {
margin-top: 0.35rem;
}
/* Messwerte als Gitter statt als Textwurst: ein Stromzaehler hat sechzehn
Werte, die in einer Zeile niemand findet. auto-fill statt fester Spalten,
damit auf dem Handy zwei und auf dem Schirm vier nebeneinander passen. */
.raum-werte {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
gap: 0.4rem;
}
.raum-wert {
background: rgba(128, 128, 128, 0.08);
border-radius: 0.35rem;
padding: 0.3rem 0.45rem;
overflow: hidden;
}
.raum-wert-zahl {
font-size: 0.95rem;
font-weight: 600;
line-height: 1.2;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.raum-wert-einheit {
font-size: 0.7rem;
font-weight: 400;
opacity: 0.6;
}
.raum-wert-name {
font-size: 0.68rem;
opacity: 0.6;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* --------------------------------------------------------------------------
Raum-Modal: Jalousien
-------------------------------------------------------------------------- */
/* Fahrknoepfe, Hoehe und Neigung nebeneinander. Die Neigung nimmt den Rest -
sie ist die einzige der drei Spalten, die von Breite profitiert. */
.raum-jalousie {
display: flex;
align-items: stretch;
justify-content: space-between;
gap: 0.4rem;
}
/* Das Fensterbild steht zwischen Knoepfen und Reglern - schmal, mit Luft
zu beiden Seiten. Der uebrige Platz verteilt sich auf die Zwischenraeume
(space-between an .raum-jalousie), statt das Bild breitzuziehen. */
.raum-jalousie .raum-lamellen {
flex: 0 1 5rem;
min-width: 2.2rem;
margin: 0 0.4rem;
}
.raum-jalousie .dropdown {
align-self: flex-start;
}
/* Auf, Stop, Zu untereinander - die Knoepfe zeigen in die Richtung, in die
sie fahren. Breit genug fuer einen Daumen: sie sind das, was man im
Vorbeigehen antippt, die Regler daneben braucht man seltener. */
.raum-fahrt {
flex: 0 0 3.1rem;
}
.raum-fahrt .btn {
padding: 0.3rem 0;
line-height: 1.5;
}
/* Eine Spalte mit senkrechtem Regler: Name, oberes Wort, Bahn, unteres
Wort, Zahl. Breit genug fuer "Position" in der kleinen Schrift. */
.raum-spalte {
flex: 0 0 3.4rem;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.raum-name {
font-size: 0.62rem;
opacity: 0.8;
white-space: nowrap;
line-height: 1.2;
}
/* Der Kasten, in dem ein gewoehnlicher Regler auf der Seite liegt.
Gedreht statt writing-mode: so gebaute Regler lassen sich am Handy kaum
anfassen - das Ziehen wird als Wischen gelesen und blaettert die Seite.
Gedreht bewegt sich der Regler in seinen eigenen Koordinaten waagerecht,
und touch-action haelt die Seite still, solange der Finger auf ihm liegt.
rotate(90deg) legt den kleinen Wert nach oben: "oben" ist 0 %. */
.raum-senkrecht {
position: relative;
width: 1.6rem;
height: 6.5rem;
margin: 0.1rem 0;
}
#roomView .raum-senkrecht input[type='range'] {
position: absolute;
top: 50%;
left: 50%;
width: 6.5rem; /* = Hoehe des Kastens, die Laenge der Bahn */
height: 1.6rem; /* = Breite des Kastens, die Flaeche zum Treffen */
transform: translate(-50%, -50%) rotate(90deg);
touch-action: none;
}
/* Die Endstellungen in Worten statt in Prozent. */
.raum-ende {
font-size: 0.68rem;
opacity: 0.65;
line-height: 1.1;
}
/* Die Lamellen zur Neigung. Ihre Hoehe setzt lamellenZeichnen() in
js/solar/homeMQTT.js - schmal mit Luft dazwischen heisst offen,
aneinanderliegend heisst geschlossen. */
.raum-lamellen {
display: block;
align-self: center;
height: 6.9rem;
/* Der Rahmen macht aus dem Streifen ein Fenster - ohne ihn liest sich das
geschlossene Bild wie eine zweite Reglerbahn. */
background: rgba(0, 120, 143, 0.14);
border: 1px solid rgba(128, 128, 128, 0.35);
border-radius: 0.2rem;
}
.raum-lamelle {
fill: currentColor;
opacity: 0.6;
stroke: rgba(0, 0, 0, 0.35);
stroke-width: 0.6;
vector-effect: non-scaling-stroke;
}
.raum-endschiene {
fill: currentColor;
opacity: 0.85;
}