Zeitleiste: Karte je Eintrag mit Bearbeiten, Pausieren/Fortsetzen, Loeschen

Ein Klick auf einen Eintrag oeffnete bisher gleich den Editor - pausieren
und loeschen ging nur in der Liste. Jetzt oeffnet sich eine kleine Karte:
was die Automatik tut, wann, wie sie heute steht, die Bedingung, und die
Knoepfe Bearbeiten, Pausieren bzw. Fortsetzen und Loeschen. Auch die
Eintraege in den Baendern "Jederzeit" und "Pausiert" oeffnen sie.

Pausieren und Loeschen gehen ueber toggleAutomation und deleteAutomation
aus autoActionFuncs.js - dieselben Wege wie in der Liste, samt Rueckfrage
bei abhaengigen Automatiken. Die Karte schliesst per Kreuz, Esc oder Klick
daneben; solange sie offen ist, leuchtet die Kette des Eintrags.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:43:11 +02:00
co-authored by Claude Opus 5
parent d291f063f5
commit 2aadb667fb
2 changed files with 161 additions and 1 deletions
+58
View File
@@ -3100,6 +3100,64 @@ input[type='range']::-webkit-slider-runnable-track {
.zl-l-balken { width: 22px; height: 7px; border-radius: 4px; background: rgba(95, 176, 220, .22); border: 1px solid rgba(95, 176, 220, .4); }
.zl-l-kette { width: 22px; border-top: 1.2px dashed rgba(154, 166, 173, .7); }
/* Karte zu einem Eintrag: schwebt ueber der Zeitleiste, Akzent der Bahn. */
.zl { position: relative; }
.zl-karte {
position: absolute;
z-index: 20;
width: min(22rem, 100%);
padding: .7rem .85rem .75rem;
border-radius: var(--ton-radius-klein, .5rem);
border: 1px solid rgba(var(--zl-farbe-rgb), .45);
border-top: 3px solid var(--zl-farbe);
background: var(--ton-flaeche-2, #2b3237);
box-shadow: 0 10px 28px rgba(0, 0, 0, .45);
font-size: .8rem;
}
.zl-karte-kopf {
display: flex;
align-items: center;
gap: .45rem;
margin-bottom: .45rem;
}
.zl-karte-kopf .bi { color: var(--zl-farbe); }
.zl-karte-name {
flex: 1 1 auto;
font: 500 .92rem var(--font-anzeige, inherit);
color: var(--ton-schrift, #e8ede9);
}
.zl-karte .btn-close.zl-karte-zu { font-size: .6rem; opacity: .6; }
.zl-karte-zeile {
display: flex;
gap: .5rem;
align-items: baseline;
padding: .12rem 0;
color: var(--ton-schrift, #e8ede9);
}
.zl-karte-zeile .bi { color: var(--ton-schrift-3, #6f7a81); flex: none; }
.zl-karte-stand.gut, .zl-karte-stand.gut .bi { color: var(--ton-gut, #4caf7d); }
.zl-karte-stand.leise { color: var(--ton-schrift-2, #9aa6ad); }
.zl-karte-wenn {
margin-top: .35rem;
padding-top: .35rem;
border-top: 1px solid var(--zl-linie);
color: var(--ton-schrift-3, #6f7a81);
font-size: .72rem;
line-height: 1.4;
max-height: 5.6em;
overflow: auto;
}
.zl-karte-knoepfe {
display: flex;
gap: .35rem;
margin-top: .65rem;
}
.zl-karte-knoepfe .btn.zl-karte-weg {
margin-left: auto;
color: var(--ton-schrift-3, #6f7a81);
}
.zl-karte-knoepfe .btn.zl-karte-weg:hover { color: var(--ton-schlecht, #e06060); }
/* Ansicht umschalten: eine Klasse mehr als Bootstrap (solar.css laedt vorher). */
.zl-ansicht .btn.active {
background: rgba(0, 120, 143, .25);
+103 -1
View File
@@ -438,6 +438,94 @@ function zlKetteHervorheben(id, an) {
.forEach(el => el.classList.toggle("hell", an));
}
/* --- Karte zu einem Eintrag ---------------------------------------------- */
/**
* Ein Klick auf einen Eintrag öffnet eine kleine Karte statt gleich den
* Editor: was die Automatik tut, wann, wie sie heute steht - und die drei
* Dinge, die man damit tun will. Pausieren und Löschen gab es vorher nur in
* der Liste.
*
* Pausieren und Löschen gehen über dieselben Funktionen wie dort
* (toggleAutomation, deleteAutomation in autoActionFuncs.js) - samt der
* Rückfrage, was mit abhängigen Automatiken geschieht. Beide rufen danach
* refreshAutomations(), und das lädt die Zeitleiste mit.
*/
function zlKarteOeffnen(anker, id) {
const ziel = document.getElementById("zeitleiste");
const d = zeitleiste.daten;
const a = d && d.automatiken.find(x => x.id === Number(id));
if (!ziel || !a) return;
zlKarteSchliessen();
const zustand = a.enabled ? zlZustand(a, d) : "pausiert";
const bahn = d.bahnen[a.bahn] || d.bahnen.sonstiges;
const wann = a.art === "fenster"
? zlUhr(a.von) + "" + zlUhr(a.bis) + (a.punkt !== null && a.punkt > a.von ? ", frühestens " + zlUhr(a.punkt) : "")
: a.art === "jederzeit" ? "jederzeit, wenn die Bedingung eintritt"
: (a.art === "kette" || a.wartet ? "frühestens " : "um ") + zlUhr(a.punkt) + (a.sonne ? " (Sonnenstand)" : "");
const stand = {
gelaufen: ["bi-check2-circle", "gut", "gelaufen um " + a.laeufe.join(", ")],
nichtdran: ["bi-calendar-x", "leise", "nicht dran: " + a.grund],
vorbei: ["bi-dash-circle", "leise", "nicht gelaufen" + (a.wartet ? " Bedingung war nicht erfüllt" : "")],
aktiv: ["bi-hourglass-split", "", a.wartet ? "wartet auf die Bedingung" : "steht an"],
kommt: ["bi-clock", "", "kommt noch"],
pausiert: ["bi-pause-circle", "leise", "pausiert"],
}[zustand];
const karte = document.createElement("div");
karte.className = "zl-karte zl-bahn-" + a.bahn;
karte.setAttribute("role", "dialog");
karte.innerHTML =
'<div class="zl-karte-kopf"><i class="bi ' + bahn.symbol + '"></i>'
+ '<span class="zl-karte-name">' + zlText(a.name) + "</span>"
+ '<span class="zl-band-etage">' + zlText(a.floor) + "</span>"
+ '<button type="button" class="btn-close btn-close-white zl-karte-zu" aria-label="Schließen"></button></div>'
+ '<div class="zl-karte-zeile"><i class="bi bi-lightning-charge"></i>' + zlText(a.satz) + "</div>"
+ '<div class="zl-karte-zeile"><i class="bi bi-clock-history"></i>' + zlText(wann) + "</div>"
+ '<div class="zl-karte-zeile zl-karte-stand ' + stand[1] + '"><i class="bi ' + stand[0] + '"></i>' + zlText(stand[2]) + "</div>"
+ (a.wenn ? '<div class="zl-karte-wenn">Wenn: ' + zlText(a.wenn) + "</div>" : "")
+ '<div class="zl-karte-knoepfe">'
+ '<button type="button" class="btn btn-sm btn-outline-secondary" data-tun="bearbeiten"><i class="bi bi-pencil-square me-1"></i>Bearbeiten</button>'
+ (a.enabled
? '<button type="button" class="btn btn-sm btn-outline-secondary" data-tun="umschalten"><i class="bi bi-pause-fill me-1"></i>Pausieren</button>'
: '<button type="button" class="btn btn-sm btn-success" data-tun="umschalten"><i class="bi bi-play-fill me-1"></i>Fortsetzen</button>')
+ '<button type="button" class="btn btn-sm zl-karte-weg" data-tun="loeschen" title="Löschen"><i class="bi bi-trash3"></i></button>'
+ "</div>";
karte.dataset.id = a.id;
ziel.appendChild(karte);
// Unter den Eintrag, sonst darüber; waagerecht in der Karte der Zeitleiste halten.
const hoch = ziel.getBoundingClientRect();
const r = anker.getBoundingClientRect();
const breit = karte.offsetWidth, hoehe = karte.offsetHeight;
let links = r.left - hoch.left;
links = Math.max(0, Math.min(links, ziel.clientWidth - breit));
let oben = r.bottom - hoch.top + 6;
if (r.bottom + hoehe + 12 > window.innerHeight && r.top - hoehe - 6 > 0) oben = r.top - hoch.top - hoehe - 6;
karte.style.left = links + "px";
karte.style.top = oben + "px";
zlKetteHervorheben(a.id, true);
karte.addEventListener("click", function (ereignis) {
const knopf = ereignis.target.closest("[data-tun]");
if (ereignis.target.closest(".zl-karte-zu")) { zlKarteSchliessen(); return; }
if (!knopf) return;
const tun = knopf.dataset.tun;
zlKarteSchliessen();
if (tun === "bearbeiten") openAutoActionModal("?action=editor&id=" + a.id);
if (tun === "umschalten") toggleAutomation(a.id);
if (tun === "loeschen") deleteAutomation(a.id, a.name);
});
}
function zlKarteSchliessen() {
document.querySelectorAll("#zeitleiste .zl-karte").forEach(k => {
zlKetteHervorheben(k.dataset.id, false);
k.remove();
});
}
/* --- Laden und Bedienen -------------------------------------------------- */
async function zeitleisteLaden() {
@@ -510,11 +598,15 @@ document.addEventListener("DOMContentLoaded", function () {
ziel.addEventListener("click", function (ereignis) {
const t = ereignis.target;
if (t.closest(".zl-karte")) return; // die Karte bedient sich selbst
const ding = t.closest("[data-id]");
if (ding) {
openAutoActionModal("?action=editor&id=" + ding.dataset.id);
const offen = ziel.querySelector(".zl-karte");
if (offen && offen.dataset.id === ding.dataset.id) { zlKarteSchliessen(); return; }
zlKarteOeffnen(ding, ding.dataset.id);
return;
}
zlKarteSchliessen();
const tag = t.closest("[data-tag]");
if (tag) {
const schritt = Number(tag.dataset.tag);
@@ -550,9 +642,19 @@ document.addEventListener("DOMContentLoaded", function () {
["mouseover", "mouseout"].forEach(typ => ziel.addEventListener(typ, function (ereignis) {
const ding = ereignis.target.closest(".zl-ding");
if (!ding || (ereignis.relatedTarget && ding.contains(ereignis.relatedTarget))) return;
const offen = ziel.querySelector(".zl-karte");
if (offen && offen.dataset.id === ding.dataset.id) return; // die offene Karte haelt ihre Kette hell
zlKetteHervorheben(ding.dataset.id, typ === "mouseover");
}));
// Ausserhalb der Zeitleiste geklickt oder Esc: Karte zu.
document.addEventListener("click", function (ereignis) {
if (!ziel.contains(ereignis.target)) zlKarteSchliessen();
});
document.addEventListener("keydown", function (ereignis) {
if (ereignis.key === "Escape") zlKarteSchliessen();
});
// Neu zeichnen, wenn sich die Breite ändert - Stapeln und Ketten hängen daran.
let warte = null;
if (typeof ResizeObserver !== "undefined") {