Gui Fixes
This commit is contained in:
@@ -48,3 +48,11 @@ Arbeitsweise:
|
||||
- Nach dem Kopieren muss das Home-Assistant-Frontend hart neu geladen werden, damit kein alter Browser-Cache im Weg ist.
|
||||
- Für das Kopieren gibt es im Repo-Root den Helfer `deploy-test.ps1`.
|
||||
- Aufruf aus dem Repo-Root: `.\deploy-test.ps1`
|
||||
|
||||
Wichtige Besonderheiten der Sternwarten-Card:
|
||||
|
||||
- Der Dämmerungsbalken arbeitet auf einer lokalen `12:00 → 12:00`-Achse.
|
||||
- Die Dämmerungsphasen werden direkt aus der Sonnenhöhe bestimmt, nicht nur aus einzelnen Dawn-/Dusk-Zeitpunkten.
|
||||
- Das ist wichtig für Sommerfälle ohne astronomische Nacht.
|
||||
- Die Marker `Öffnen geplant` und `Schließen geplant` werden für diese Achse nach lokaler Uhrzeit eingeordnet.
|
||||
- Wenn diese Marker fehlen, ist die erste Prüffrage: Wurde versehentlich wieder gegen ein echtes Datumsfenster statt gegen die `12 → 12`-Achse gerechnet?
|
||||
|
||||
@@ -12,6 +12,28 @@ dist/
|
||||
|
||||
`sternwarte-card.js` lädt `astronomy.browser.min.js` automatisch nach, um Dämmerungszeiten und Mondposition präziser zu berechnen.
|
||||
|
||||
## Dämmerungsbalken
|
||||
|
||||
Der Dämmerungsbalken in `dist/sternwarte-card.js` arbeitet bewusst nicht nur mit einzelnen Dawn-/Dusk-Zeitpunkten, sondern mit einem lokalen `12:00 → 12:00`-Fenster.
|
||||
|
||||
Wichtige Punkte:
|
||||
|
||||
- Die Phasen `Tag`, `bürgerliche Dämmerung`, `nautische Dämmerung`, `astronomische Dämmerung` und `Nacht` werden direkt aus der Sonnenhöhe bestimmt.
|
||||
- Dafür wird das komplette lokale 24-Stunden-Fenster in kleinen Schritten durchgerechnet.
|
||||
- Diese Logik ist robuster für Sommerfälle, in denen es keine astronomische Nacht mehr gibt.
|
||||
|
||||
Marker im Balken:
|
||||
|
||||
- `Öffnen geplant` wird grün dargestellt.
|
||||
- `Schließen geplant` wird rot dargestellt.
|
||||
- Der Marker `Jetzt` ist bewusst hell/weiß, damit er nicht mit `Schließen` verwechselt wird.
|
||||
|
||||
Wichtig für spätere Änderungen:
|
||||
|
||||
- Die Balkenachse ist eine Uhrzeitachse `12 → 12`, keine reine Datumsachse.
|
||||
- Die Marker für `Öffnen geplant` und `Schließen geplant` müssen daher anhand der lokalen Uhrzeit auf diese Achse gelegt werden, nicht anhand eines festen Datumsfensters.
|
||||
- Wenn die Marker verschwinden, zuerst prüfen, ob versehentlich wieder mit einem echten Zeitfenster statt mit der `12 → 12`-Achse gerechnet wird.
|
||||
|
||||
## Für HACS
|
||||
|
||||
Dieser Ordner ist als Root eines späteren HACS-Dashboard-Repositorys vorbereitet.
|
||||
|
||||
+42
-22
@@ -330,12 +330,29 @@ class SternwarteCard extends HTMLElement {
|
||||
}
|
||||
}
|
||||
|
||||
_parseEntityDate(rawValue) {
|
||||
if (!rawValue || rawValue === "unknown" || rawValue === "unavailable") return null;
|
||||
if (rawValue instanceof Date) {
|
||||
return Number.isNaN(rawValue.getTime()) ? null : rawValue;
|
||||
}
|
||||
if (typeof rawValue !== "string") {
|
||||
const value = new Date(rawValue);
|
||||
return Number.isNaN(value.getTime()) ? null : value;
|
||||
}
|
||||
|
||||
const normalized = rawValue.trim().replace(" ", "T");
|
||||
const hasTimezone = /(?:Z|[+-]\d{2}:\d{2})$/.test(normalized);
|
||||
const localCandidate = hasTimezone ? normalized : normalized;
|
||||
const value = new Date(localCandidate);
|
||||
return Number.isNaN(value.getTime()) ? null : value;
|
||||
}
|
||||
|
||||
_isoForInput(state) {
|
||||
if (!state || !state.state || state.state === "unknown" || state.state === "unavailable") {
|
||||
return "";
|
||||
}
|
||||
const value = new Date(state.state);
|
||||
if (Number.isNaN(value.getTime())) return "";
|
||||
const value = this._parseEntityDate(state.state);
|
||||
if (!value) return "";
|
||||
const pad = (n) => String(n).padStart(2, "0");
|
||||
return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}T${pad(value.getHours())}:${pad(value.getMinutes())}`;
|
||||
}
|
||||
@@ -344,8 +361,8 @@ class SternwarteCard extends HTMLElement {
|
||||
if (!state || !state.state || state.state === "unknown" || state.state === "unavailable") {
|
||||
return "\u2014";
|
||||
}
|
||||
const value = new Date(state.state);
|
||||
if (Number.isNaN(value.getTime())) return "\u2014";
|
||||
const value = this._parseEntityDate(state.state);
|
||||
if (!value) return "\u2014";
|
||||
const pad = (n) => String(n).padStart(2, "0");
|
||||
return `${pad(value.getDate())}.${pad(value.getMonth() + 1)}. ${pad(value.getHours())}:${pad(value.getMinutes())}`;
|
||||
}
|
||||
@@ -783,13 +800,12 @@ class SternwarteCard extends HTMLElement {
|
||||
|
||||
segments.sort((a, b) => a.start - b.start);
|
||||
|
||||
const toWindowHour = (state) => {
|
||||
const toChartHour = (state) => {
|
||||
if (!state?.state || state.state === "unknown" || state.state === "unavailable") return null;
|
||||
const value = new Date(state.state);
|
||||
if (Number.isNaN(value.getTime())) return null;
|
||||
const hour = (value.getTime() - windowStart.getTime()) / 3600000;
|
||||
if (hour < 0 || hour > 24) return null;
|
||||
return hour;
|
||||
const value = this._parseEntityDate(state.state);
|
||||
if (!value) return null;
|
||||
const localHour = value.getHours() + value.getMinutes() / 60 + value.getSeconds() / 3600;
|
||||
return (localHour - 12 + 24) % 24;
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -800,8 +816,8 @@ class SternwarteCard extends HTMLElement {
|
||||
color: segment.color,
|
||||
})),
|
||||
markerLeft: `${(nowLocal / 24) * 100}%`,
|
||||
openMarkerLeft: toWindowHour(this._state(this._scheduleOpenEntityId())),
|
||||
closeMarkerLeft: toWindowHour(this._state(this._scheduleCloseEntityId())),
|
||||
openMarkerLeft: toChartHour(this._state(this._scheduleOpenEntityId())),
|
||||
closeMarkerLeft: toChartHour(this._state(this._scheduleCloseEntityId())),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1084,24 +1100,28 @@ class SternwarteCard extends HTMLElement {
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
bottom: -4px;
|
||||
width: 4px;
|
||||
width: 3px;
|
||||
margin-left: -1px;
|
||||
background: #d32f2f;
|
||||
box-shadow: 0 0 8px rgba(211, 47, 47, 0.55);
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
box-shadow: 0 0 8px rgba(255, 255, 255, 0.45);
|
||||
z-index: 5;
|
||||
}
|
||||
.astro-marker {
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
bottom: -3px;
|
||||
width: 4px;
|
||||
margin-left: -1px;
|
||||
box-shadow: 0 0 6px rgba(255, 255, 255, 0.25);
|
||||
top: -4px;
|
||||
bottom: -4px;
|
||||
width: 6px;
|
||||
margin-left: -2px;
|
||||
border-radius: 999px;
|
||||
z-index: 4;
|
||||
}
|
||||
.astro-marker.open {
|
||||
background: #4caf50;
|
||||
background: #20c45a;
|
||||
box-shadow: 0 0 10px rgba(32, 196, 90, 0.7);
|
||||
}
|
||||
.astro-marker.close {
|
||||
background: #ffb300;
|
||||
background: #e53935;
|
||||
box-shadow: 0 0 10px rgba(229, 57, 53, 0.72);
|
||||
}
|
||||
.astro-moon-track {
|
||||
position: absolute;
|
||||
|
||||
Reference in New Issue
Block a user