Nichts verschwindet mehr ohne eine Nachfrage, die sagt was passiert
Filipe: "Es darf vor allem keine Stellen geben, an denen ein Benutzer
etwas falsch machen kann, nur weil die Seite es nicht verstaendlich
genug erklaert."
Gemessen: 30 Stellen in 16 Dateien benutzten confirm() oder prompt().
Das Haus hatte die richtige Bauweise laengst -- einen <dialog>, in
aufgaben.html sogar ausfuehrlich begruendet -- aber sie stand IN EINER
SEITE. Wer anderswo etwas loeschen liess, hatte sie nicht.
confirm('Wirklich loeschen?') stellt die falsche Frage: Es fragt, ob
man sicher ist, und nennt nicht, WAS passiert, was BLEIBT und ob es
ZURUECK geht. Jetzt beantwortet jeder der 41 Dialoge alle drei.
Neu: workspace/assets/js/nachfrage.js -- window.frageNach() mit
Pflichtgrund, Zahlenfeld, einzeiliger Eingabe und Abtippsicherung.
Drei Ausgaenge: <dialog> / confirm()-Notnagel fuer Safari vor 15.4 /
Abbruch (Esc, Klick daneben, "Doch nicht" -- immer false).
DREIMAL DERSELBE FALLSTRICK, dreimal nachgemessen statt vermutet:
.dialog stand in aufgaben.css und leistung.css -> auf dateien.html
waere der Dialog ein weisser Systemkasten gewesen. 14 Regeln
klammergenau nach module.css verschoben (Klammern gezaehlt, nicht
per Muster geschnitten -- heute frueh hat ein nicht-gieriges
Muster schon einmal CSS zerrissen).
Das Formular trug .neu neu--blank -- und .neu gibt seine Abstaende
nur in aufgaben.css. Gemessen: padding 0px, und die Felder
verloren ihre height:44px. Jetzt steht alles unter
.nachfrage__form in module.css; der Dialog borgt nichts mehr.
Die erste Fassung der Pruefung zaehlte nachfrage.js SELBST als
Nutzer -- damit war jede Seite trivialerweise "Nutzer" und die
Pruefung gruen ohne Inhalt. Jetzt ausdruecklich ausgenommen.
ZWEI FUNDE NEBENBEI:
hilfeAufraeumen() wird im Betrieb NIE aufgerufen. Der Kommentar
behauptete "wird beim Start aufgerufen (siehe index.js)" -- das
war nie wahr; einziger Aufrufer ist die eigene Pruefung. Folge:
geschlossene vertrauliche Faelle bleiben unbegrenzt stehen. NICHT
eingeschaltet (das loescht echte Daten und ist Filipes
Entscheidung), sondern der Kommentar richtiggestellt.
Einen Hilfe-Fall zu schliessen ist endgueltig -- es gibt keine
Route, die ihn wieder oeffnet. Vorher stand darueber nur die
Frage nach einem Schlusswort. Jetzt sagt der Dialog es.
pruef-struktur hat meine eigene Pruefung von heute Nachmittag
erwischt: Sie bildete ihr Datum aus UTC. Beim Beheben erst
heuteLokal(datum) genommen -- die Funktion nimmt gar kein Argument
und haette still "heute" statt "+3 Tage" geliefert. Jetzt tagLokal(3),
nachgerechnet: Abstand 3 Tage.
Am Bildschirm angesehen (Rechner 1280, Handy 390): passt rein, Esc
ergibt false, Fokus liegt auf dem harmlosen Knopf, Knoepfe 44px auf
Touch. Der Platzhalter im Abtippfeld zeigte den erwarteten Namen --
das sah aus wie ein schon ausgefuelltes Feld, entfernt.
Neu: server/pruef-nachfrage.mjs -- 17/0, mit sechs Gegenproben und
beiden Richtungen (wer fragt, laedt die Datei; wer nie fragt, laedt
sie nicht -- sonst truege die Anmeldewand 4,8 KB fuer nichts).
pruef-meldungen 8/0, pruef-css-klassen gruen, pruef-struktur gruen,
pruef-leistung gruen.
This commit is contained in:
@@ -559,3 +559,259 @@
|
||||
der Rundgang sechsmal gemeldet hat. */
|
||||
.filterreihe__knopf, .k-chip { min-width: 44px; }
|
||||
}
|
||||
|
||||
|
||||
/* =====================================================================
|
||||
DER DIALOG — hierher verschoben am 19.09.2026
|
||||
|
||||
Er stand in `aufgaben.css` und `leistung.css`. Das war richtig,
|
||||
solange nur diese zwei Seiten einen Dialog hatten. Seit es
|
||||
`nachfrage.js` gibt, kann JEDE Seite nachfragen, bevor etwas weg
|
||||
ist -- und auf einer Seite, die `aufgaben.css` nicht laedt, waere
|
||||
der Dialog ungestaltet gewesen: weisser Kasten, Systemschrift,
|
||||
mitten auf einer dunklen Seite.
|
||||
|
||||
`module.css` laedt auf jeder Seite (vorletzte Datei, direkt vor
|
||||
`haus.css`). Was mehr als eine Seite benutzt, gehoert hierher.
|
||||
|
||||
In `aufgaben.css` bleibt genau eine Regel: `.dialog__knoepfe
|
||||
#b-loeschen` -- die haengt an einer ID, die es nur dort gibt.
|
||||
===================================================================== */
|
||||
/* =====================================================================
|
||||
DIALOGE (07.09.2026 überarbeitet)
|
||||
|
||||
Filipe zu zwei davon: "lass alles in dieser kachel viel spezieller und
|
||||
geiler aussehen" und "dass soll auch viel besser aussehen".
|
||||
|
||||
Er hatte recht, und der Grund war nicht Geschmack: Ein Dialog war
|
||||
bisher ein grauer Kasten (`background: #0b1018`, ein Rand, fertig) --
|
||||
während die Seite dahinter aus beleuchteten Platten mit Schienen,
|
||||
Körnung und Glanz besteht. Beim Öffnen fiel man aus dem einen
|
||||
Material ins andere.
|
||||
|
||||
Jetzt trägt er dieselbe Sprache wie alles übrige:
|
||||
- Leuchtschiene links, im Hausakzent
|
||||
- Kopfzeile abgesetzt mit einer feinen Fuge
|
||||
- Körnung und ein fester Glanz von links oben
|
||||
- Materialstärke: Licht oben, Schatten unten
|
||||
Und er ist deutlich TIEFER als vorher (#0b1018 war ein helles Grau
|
||||
gegen das, was jetzt hinter ihm liegt) -- ein Dialog muss sich vom
|
||||
Untergrund abheben, sonst schwimmt er darin.
|
||||
|
||||
Der Hintergrund dahinter wird STÄRKER abgedunkelt und weicher
|
||||
gezeichnet: Ein Dialog ist der einzige Ort, an dem ein Weichzeichner
|
||||
richtig ist -- er soll das Dahinter ausdrücklich zurücktreten
|
||||
lassen. Genau dafür ist er gemacht, und genau deshalb war er unter
|
||||
den Kacheln falsch.
|
||||
===================================================================== */
|
||||
.dialog {
|
||||
position: relative;
|
||||
width: min(580px, calc(100vw - 32px));
|
||||
padding: 0;
|
||||
border: 1px solid rgba(150, 186, 220, .16);
|
||||
/* DIE FASE STATT RUNDER ECKEN (08.09.2026).
|
||||
|
||||
Filipe: "alles was sie sehen soll dan auch nach der neuen struktur
|
||||
aufgebaut sein" -- und ein Dialog ist das, was man am genauesten
|
||||
ansieht, weil er alles andere verdeckt.
|
||||
|
||||
Er kann NICHT in die Modulliste von module.css: Die belegt
|
||||
`::before` und `::after` fuer die Eckwinkel, und beide sind hier
|
||||
schon vergeben -- an die Leuchtschiene links und den Lichtsaum.
|
||||
Beides gegen zwei Winkel zu tauschen waere ein Rueckschritt.
|
||||
Deshalb hier nur der Zuschnitt, von Hand, mit derselben Groesse
|
||||
`--fase` wie ueberall. Wer die Fase spaeter aendert, aendert sie
|
||||
hier mit. */
|
||||
clip-path: polygon(var(--fase, 18px) 0, 100% 0, 100% 100%, 0 100%, 0 var(--fase, 18px));
|
||||
border-radius: 0;
|
||||
background:
|
||||
linear-gradient(90deg,
|
||||
color-mix(in srgb, var(--akzent) 16%, transparent) 0%,
|
||||
color-mix(in srgb, var(--akzent) 5%, transparent) 14%,
|
||||
transparent 40%),
|
||||
linear-gradient(163deg, #141c29 0%, #0a0e17 58%, #070a11 100%);
|
||||
color: var(--text);
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 255, 255, .10),
|
||||
inset 0 -1px 0 rgba(0, 0, 0, .55),
|
||||
inset 2px 0 0 -1px color-mix(in srgb, var(--akzent) 34%, transparent),
|
||||
0 30px 70px -24px rgba(0, 0, 0, .92),
|
||||
0 4px 12px -6px rgba(0, 0, 0, .7);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Die Leuchtschiene -- dieselbe wie an jeder Kachel. */
|
||||
.dialog::before {
|
||||
content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
|
||||
border-radius: 4px 0 0 4px;
|
||||
background: linear-gradient(180deg,
|
||||
color-mix(in srgb, var(--akzent) 55%, #fff) 0%,
|
||||
var(--akzent) 26%,
|
||||
color-mix(in srgb, var(--akzent) 48%, transparent) 100%);
|
||||
box-shadow:
|
||||
0 0 9px 0 color-mix(in srgb, var(--akzent) 55%, transparent),
|
||||
3px 0 20px -3px color-mix(in srgb, var(--akzent) 42%, transparent);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Glanz und Körnung. `pointer-events: none` ist Pflicht: Ohne das läge
|
||||
eine unsichtbare Fläche über dem ganzen Formular, und kein einziges
|
||||
Feld wäre anklickbar. */
|
||||
.dialog::after {
|
||||
content: ""; position: absolute; inset: 0; pointer-events: none;
|
||||
border-radius: inherit;
|
||||
background:
|
||||
linear-gradient(122deg,
|
||||
rgba(255, 255, 255, .075) 0%,
|
||||
rgba(255, 255, 255, .020) 15%,
|
||||
transparent 34%);
|
||||
/* Ohne Körnung -- siehe die Begründung in automation.css: Auf einer
|
||||
Ebene mit der Spiegelung erbt sie deren Deckkraft und wird zum
|
||||
grauen Schleier. */
|
||||
opacity: .55;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.dialog > * { position: relative; z-index: 2; }
|
||||
|
||||
.dialog::backdrop {
|
||||
background: rgba(2, 4, 8, .78);
|
||||
backdrop-filter: blur(6px) saturate(80%);
|
||||
}
|
||||
|
||||
/* Der Kopf steht auf einer eigenen Stufe: Überschrift, darunter der
|
||||
erklärende Satz, darunter eine feine Fuge. Ohne diese Trennung
|
||||
verschwimmt die Ansage mit dem ersten Feld -- und genau die Ansage
|
||||
ist das, was den Dialog erklärt. */
|
||||
.dialog__titel {
|
||||
margin: 0 0 4px;
|
||||
font-size: 1.24rem; font-weight: 700; letter-spacing: -.015em;
|
||||
color: #f2f7fd;
|
||||
}
|
||||
|
||||
.dialog__unter {
|
||||
margin: 0 0 16px; padding-bottom: 16px;
|
||||
border-bottom: 1px solid rgba(150, 186, 220, .12);
|
||||
font-size: .87rem; line-height: 1.55;
|
||||
color: var(--text-leise);
|
||||
}
|
||||
|
||||
/* Hat ein Dialog keine Erklärung, muss die Fuge trotzdem da sein --
|
||||
sonst hängt die Überschrift am ersten Feld. */
|
||||
.dialog__titel:last-of-type,
|
||||
.dialog__unter:empty { border-bottom: 0; }
|
||||
|
||||
.dialog__unter:empty {
|
||||
margin: 0 0 16px; padding-bottom: 16px;
|
||||
border-bottom: 1px solid rgba(150, 186, 220, .12);
|
||||
}
|
||||
|
||||
.dialog__knoepfe { display: flex; gap: 10px; align-items: center; margin-top: 16px; flex-wrap: wrap; }
|
||||
|
||||
/* ---------- Der Dialog --------------------------------------------------- */
|
||||
|
||||
.dialog__unter {
|
||||
margin: -4px 0 14px;
|
||||
font-size: .85rem; color: var(--text-still);
|
||||
max-width: 60ch; line-height: 1.5;
|
||||
}
|
||||
|
||||
/* ---------- Der Import --------------------------------------------------- */
|
||||
|
||||
.dialog--breit { max-width: 720px; }
|
||||
|
||||
.dialog__unter--still { font-size: .8rem; color: var(--text-still); }
|
||||
|
||||
/* Ein Fenster, das laenger ist als der Bildschirm, versteckt seine
|
||||
eigenen Knoepfe. Gerollt wird INNEN, damit "Uebernehmen" immer
|
||||
erreichbar bleibt. */
|
||||
.dialog--breit .neu { max-height: min(86vh, 900px); overflow-y: auto; }
|
||||
|
||||
/* ---- Die zwei Zeilen, die confirm() nicht kann ---------------------
|
||||
`nachfrage.js` baut den Dialog; diese beiden Teile gibt es nur dort.
|
||||
|
||||
Die Endgueltig-Zeile ist der wichtigste Satz im ganzen Dialog --
|
||||
sie beantwortet die einzige Frage, die vor einem Loeschen zaehlt.
|
||||
Deshalb bekommt sie eine eigene Farbe UND ein Zeichen davor: Farbe
|
||||
allein traegt keine Aussage (Rot-Gruen-Schwaeche, Kontrastmodus),
|
||||
und im Kontrastmodus wird `color` ohnehin ersetzt. Das Zeichen
|
||||
bleibt in jedem Fall. */
|
||||
.nachfrage__endgueltig {
|
||||
margin: 0 0 4px;
|
||||
padding: 8px 10px;
|
||||
font-size: .86rem;
|
||||
line-height: 1.45;
|
||||
color: #ffd9d2;
|
||||
background: rgba(190, 74, 60, .13);
|
||||
border-left: 3px solid rgba(214, 96, 80, .62);
|
||||
}
|
||||
.nachfrage__endgueltig::before { content: "! "; font-weight: 800; }
|
||||
|
||||
/* Der Fehler IM Dialog (z. B. fehlender Grund). Er darf nicht
|
||||
aussehen wie der Fehlerstreifen der Seite dahinter -- der ist
|
||||
verdeckt, dieser hier gehoert zum Formular. Leer nimmt er keinen
|
||||
Platz weg, sonst rutschten die Knoepfe beim ersten Fehler. */
|
||||
.nachfrage__fehler { margin: 0; font-size: .86rem; color: #ffb4a8; }
|
||||
.nachfrage__fehler:empty { display: none; }
|
||||
|
||||
/* Am Handy klebt der Dialog sonst am oberen Rand und die Knoepfe
|
||||
liegen unter der Tastatur. Er waechst von unten, wie ein Blatt,
|
||||
das hochgezogen wird -- das ist dort die gewohnte Richtung. */
|
||||
@media (max-width: 560px) {
|
||||
.nachfrage { margin: auto auto 0; width: 100vw; max-width: 100vw; }
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.nachfrage__endgueltig { border-left: 3px solid CanvasText; background: Canvas; }
|
||||
}
|
||||
|
||||
/* Der kleine Hinweis unter einem Feld im Nachfrage-Dialog ("Du kannst
|
||||
bis zu 14 Tage geben"). Er steht UNTER dem Feld, nicht daneben:
|
||||
daneben rutscht er am Handy weg, und dort liest ihn niemand. */
|
||||
.nachfrage__hinweis { margin: 4px 0 0; font-size: .8rem; color: var(--text-still); }
|
||||
.nachfrage__hinweis:empty { display: none; }
|
||||
|
||||
/* ---- Der Dialog steht auf eigenen Füßen ---------------------------
|
||||
NACHGEMESSEN AM 19.09.2026, und es war genau derselbe Fehler wie
|
||||
bei `.dialog` selbst: Das Formular trug erst die Klassen
|
||||
`neu neu--blank` — und `.neu` gibt seine Abstände NUR in
|
||||
`aufgaben.css`. Gemessen auf einer Seite ohne diese Datei:
|
||||
`padding: 0px`. Der Text klebte am Rand, und die Eingabefelder
|
||||
verloren ihre `height: 44px` — also ausgerechnet die Größe, die
|
||||
ein Daumen trifft.
|
||||
|
||||
Am Bildschirm sah es trotzdem "irgendwie richtig" aus, weil die
|
||||
Schrift und die Farben aus `gate.css` kamen. Solche Abhängigkeiten
|
||||
sieht man nicht, man misst sie.
|
||||
|
||||
Deshalb steht hier alles, was der Dialog braucht — er borgt nichts
|
||||
mehr aus einer Seitendatei. `.knopf`, `.abmelden` und `.feld-schild`
|
||||
bleiben: die stehen in `gate.css` bzw. `start.css`, und die lädt
|
||||
jede Seite. */
|
||||
.nachfrage__form { margin: 0; padding: 20px; display: grid; gap: 10px; }
|
||||
.nachfrage__zeile { display: grid; gap: 5px; }
|
||||
.nachfrage__form input,
|
||||
.nachfrage__form textarea {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
font: inherit;
|
||||
color: var(--text);
|
||||
background: var(--tinte);
|
||||
border: 1px solid var(--rand);
|
||||
border-radius: var(--radius, 10px);
|
||||
padding: 8px 10px;
|
||||
}
|
||||
/* 44 Pixel, weil ein Daumen weniger nicht sicher trifft. Dieselbe Zahl
|
||||
wie überall im Haus -- sie steht hier, damit sie nicht davon abhängt,
|
||||
welche Seitendatei zufällig geladen ist. */
|
||||
.nachfrage__form input { height: 44px; }
|
||||
.nachfrage__form textarea { min-height: 62px; resize: vertical; }
|
||||
.nachfrage__form input:focus,
|
||||
.nachfrage__form textarea:focus {
|
||||
outline: none;
|
||||
box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, .75),
|
||||
0 0 0 3px rgba(63, 189, 245, .16);
|
||||
}
|
||||
/* Die Knöpfe unten bekommen Luft nach oben -- sonst sitzt "Löschen"
|
||||
direkt unter dem Satz, der davor warnt. */
|
||||
.nachfrage .dialog__knoepfe { margin-top: 6px; }
|
||||
|
||||
Reference in New Issue
Block a user