Pipeline: die Stufenfarbe kommt endlich auf dem Bildschirm an
Filipe: "zuerst will ich dass du die kategorien und die kacheln viel
krasser geiler machst."
Beim Nachmessen stand fest, warum die Pipeline flach aussah: Drei
Regeln in scouting.css kamen gar nicht an, seit es den Baukasten
(module.css) gibt -- und module.css NENNT zwei davon im eigenen Text.
--ton war an JEDER Karte #db4b66, dem Rot der Seite.
Daraus nimmt der Baukasten Kantenlicht, die
drei Eckwinkel und das Licht beim Zeigen. Sechs
Stufenfarben in der Datei, eine auf dem Schirm.
.kk::before (3px) gemessen 560px breit -- das ist das Kantenlicht
des Baukastens, das dasselbe Pseudoelement
belegt. Die farbige Pipeline-Kante gab es nicht.
.kk { border } /:hover module.css setzt `border: 0`, gleich stark und
spaeter im Ladeweg.
Das Haus hatte die Lehre schon: aufgaben.css setzt `--ton` an fuenf
Spalten mit genau dieser Begruendung. Hierher uebertragen hat es nie
jemand.
WAS JETZT ANDERS IST
* Jede Stufe traegt ihren Ton -- Eckwinkel, Kantenlicht und Hover
laufen damit von kuehl (neu entdeckt) zu gruen (uebergeben).
* Die Farbkante der Karte liegt im HINTERGRUND statt auf einem
Pseudoelement (beide gehoeren dem Baukasten). 6px, weil das
Kantenlicht 1,6px davon verdeckt -- bei 3px blieb nichts Sichtbares.
* Etappennummern 01-05, abgeleitet aus WEITER statt daneben
geschrieben. "Abgelehnt" bekommt keine: keine Etappe nach vorn.
* Stufentitel in der eigenen Farbe (vorher einheitlich --akzent),
mit Weiss aufgehellt -- 4,3:1 waeren bei fett-versal 12,5px zu wenig.
* Faellig-Saum als inset-Schatten wie bei .kachel[data-warn], mit
(0,3,0) gegen die Modulliste; vorher border-color und damit wirkungslos.
* Karte: Plattform als Schild, Handle in gleichbreiter Schrift,
Haarlinie zwischen "wer" und "lohnt sich", Reichweite deutlicher.
DAS MESSGERAET, DAS GEFEHLT HAT: module.css notiert "NICHT
MITREPARIERT, weil es kein Messgeraet dafuer gibt ... Hover laesst sich
nicht pruefen." Doch -- pruef-scouting-felder faehrt den Zeiger jetzt
auf die Karte und liest nach (6px -> 9px).
DREI FUNDE IN DEN EIGENEN WERKZEUGEN, alle von Hauswachen oder der
eigenen Messung:
* bild-arten hatte keine Notbremse; page.hover() blieb haengen und
liess beim Abbrechen einen Server auf Port 4336 zurueck. Jetzt
notbremse(240s) und mouse.move statt hover().
* color-mix(in srgb, var(--rand)) -- mit EINER Farbe ungueltig; der
ganze Verlauf fiel aus, uebrig blieb Abstand ohne Linie.
* Im Pruefausdruck steckte ein Backspace-Byte (0x08), das die
Kommandozeile aus einer Zeichenfolge gemacht hatte. Sah im
Quelltext richtig aus, traf nie. Jetzt startsWith.
pruef-scouting-felder: 64 -> 72 Pruefungen, gruen. Gegenprobe gefahren
(einer Stufe den Ton genommen -> rot, mit #db4b66 als Beleg). Statt des
226-Sekunden-Hauslaufs pruef-handy misst die Datei jetzt selbst auf
320px: 97 Teile, keines ueber dem Rand, kein seitliches Schieben.
Dazu gruen: css-klassen, lesbarkeit, tippziele, fingermass,
haus-trennung, leerzustand, deutsche-texte, zeichen (der eine Rest dort
ist bereich.css und aelter).
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -12,6 +12,19 @@
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
/* NOTBREMSE (nachgeruestet 06.10.2026, nachdem genau das passiert ist).
|
||||
|
||||
Dieses Werkzeug startet einen Server und einen Browser. Beim Versuch,
|
||||
die Farbkante unter dem Zeiger zu messen, blieb `page.hover()` haengen
|
||||
-- und ein Stillstand sieht von aussen genauso aus wie "laeuft noch".
|
||||
Schlimmer: Nach dem Abbrechen von aussen blieb der Server auf Port
|
||||
4336 stehen und haette den naechsten Lauf blockiert.
|
||||
|
||||
Dieselbe Regel wie fuer die Pruefungen, und aus demselben Grund: Eine
|
||||
Frist, die ueberschritten wird, ist ein FEHLER mit Meldung -- kein
|
||||
Warten ohne Ende. */
|
||||
import { notbremse } from "./helfer-notbremse.mjs";
|
||||
notbremse(240_000, "bild-arten");
|
||||
|
||||
const ordner = mkdtempSync(join(tmpdir(), "ws-arten-"));
|
||||
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
|
||||
@@ -104,6 +117,79 @@ for (const s of spalten) {
|
||||
console.log(` ${String(s.stufe).padEnd(14)} ${String(s.titel).padEnd(8)} ${String(s.zahl).padStart(2)} `
|
||||
+ `x=${String(s.x).padStart(4)} b=${String(s.breite).padStart(4)} Linie=${s.linie.padStart(5)} ${s.namen}`);
|
||||
}
|
||||
/* WAS KOMMT AN DER KARTE WIRKLICH AN? (06.10.2026)
|
||||
|
||||
`module.css` belegt `::before` (Kantenlicht) und `::after` (Raster,
|
||||
Eckwinkel) JEDER Karte und wird NACH scouting.css geladen. Was
|
||||
scouting.css auf dieselben Pseudoelemente legt, verliert damit --
|
||||
ohne dass irgendwo ein Fehler erscheint. Diese Messung sagt, welcher
|
||||
Ton tatsaechlich gilt und wie breit die farbige Kante wirklich ist. */
|
||||
console.log("\n--- Was an der Karte wirklich ankommt ---");
|
||||
const kante = await seite.$eval(".kk", (k) => {
|
||||
const vor = getComputedStyle(k, "::before");
|
||||
return {
|
||||
ton: getComputedStyle(k).getPropertyValue("--ton").trim() || "(nicht gesetzt)",
|
||||
stufenfarbe: getComputedStyle(k).getPropertyValue("--stufe-farbe").trim() || "(nicht gesetzt)",
|
||||
vorBreite: vor.width, vorInhalt: vor.content,
|
||||
grund: getComputedStyle(k).backgroundImage.slice(0, 60),
|
||||
};
|
||||
});
|
||||
console.log(" --ton:", kante.ton, " --stufe-farbe:", kante.stufenfarbe);
|
||||
console.log(" ::before Breite:", kante.vorBreite, " (3px = Kante von scouting.css, sonst ueberschrieben)");
|
||||
console.log(" Grundbild:", kante.grund);
|
||||
|
||||
/* WIE BREIT IST DIE FARBKANTE WIRKLICH -- und kommt sie durch?
|
||||
Gemessen wird nicht die Regel, sondern das Bild: die Farbe des
|
||||
Bildpunktes zwei Pixel rechts von der linken Kartenkante, einmal in
|
||||
Ruhe und einmal unter dem Zeiger. Eine Kante, die man nur im
|
||||
Quelltext sieht, ist keine. */
|
||||
const kantenMass = await seite.evaluate(() => {
|
||||
const k = document.querySelector(".kk");
|
||||
const s = getComputedStyle(k);
|
||||
return { groesse: s.backgroundSize, lage: s.backgroundPosition, kante: s.getPropertyValue("--kante").trim() };
|
||||
});
|
||||
console.log(" background-size:", kantenMass.groesse, "| --kante:", kantenMass.kante || "(nicht gesetzt)");
|
||||
/* MIT mouse.move AUF DIE MITTE DER KARTE, NICHT MIT page.hover().
|
||||
`hover()` wartet darauf, dass das Ziel "bedienbar" ist -- sichtbar,
|
||||
stabil, nicht verdeckt. Bei einer Karte, ueber der das Hintergrundbild
|
||||
der Seite liegt, kann diese Pruefung dreissig Sekunden brauchen oder
|
||||
nie fertig werden. Gemessen werden soll hier aber nicht die
|
||||
Bedienbarkeit, sondern was der Zeiger an der Farbe aendert -- dafuer
|
||||
genuegt es, den Zeiger hinzubewegen. */
|
||||
{
|
||||
const m = await seite.$eval(".kk", (k) => {
|
||||
const r = k.getBoundingClientRect();
|
||||
return { x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2) };
|
||||
});
|
||||
await seite.mouse.move(m.x, m.y);
|
||||
await seite.waitForTimeout(400);
|
||||
}
|
||||
const unterZeiger = await seite.evaluate(() =>
|
||||
getComputedStyle(document.querySelector(".kk")).getPropertyValue("--kante").trim());
|
||||
console.log(" --kante unter dem Zeiger:", unterZeiger || "(nicht gesetzt)");
|
||||
/* Kommt die Haarlinie zwischen Kopf und Zahlen an? Ein ungueltiger
|
||||
Farbwert laesst `border-image` lautlos ausfallen -- uebrig bleibt
|
||||
Abstand ohne Linie, und das sieht im Quelltext richtig aus. */
|
||||
const linie = await seite.$eval(".kk__info", (k) => {
|
||||
const s2 = getComputedStyle(k);
|
||||
return { quelle: s2.borderImageSource.slice(0, 48), breite: s2.borderTopWidth };
|
||||
});
|
||||
console.log(" Haarlinie in der Karte:", linie.breite, "|", linie.quelle);
|
||||
/* Eine Nahaufnahme der linken Kante -- 90 px breit, damit man sie
|
||||
ueberhaupt sehen kann. */
|
||||
/* Eine Karte OHNE Faellig-Saum: Bei Tamy liegt der warme Innenring
|
||||
ueber der Stufenkante, und dann misst man den Ring statt der Kante. */
|
||||
const kasten = await seite.$eval(".kk:not([data-faellig])", (k) => {
|
||||
const r = k.getBoundingClientRect();
|
||||
/* `width`/`height` -- nicht `w`/`h`. Playwright meldet dann
|
||||
"clip.width: expected float, got undefined"; gefunden hat es die
|
||||
Notbremse, nicht das Auge. */
|
||||
return { x: Math.round(r.x), y: Math.round(r.y), width: 90, height: Math.round(r.height) };
|
||||
});
|
||||
await seite.screenshot({ path: "server/bild-arten-kante.png", clip: kasten });
|
||||
await seite.mouse.move(0, 0);
|
||||
await seite.waitForTimeout(300);
|
||||
|
||||
const stufe1 = await seite.$('.stufe[data-stufe="neu"]');
|
||||
await stufe1.screenshot({ path: "server/bild-arten-rechner.png" });
|
||||
await seite.screenshot({ path: "server/bild-arten-rechner-ganz.png", fullPage: false });
|
||||
|
||||
@@ -466,6 +466,95 @@ console.log("\n=== Die Seite selbst ===");
|
||||
await seite.click("#neu-zu");
|
||||
await seite.waitForTimeout(250);
|
||||
|
||||
/* ===== DIE OPTIK DER STUFE KOMMT WIRKLICH AN (06.10.2026) ========
|
||||
|
||||
module.css notiert selbst: „`.kk:hover` in scouting.css ... setzt
|
||||
border-color -- und die Grundregel oben setzt `border: 0`, gleich
|
||||
stark und spaeter im Ladeweg. Diese vier Regeln tun also vermutlich
|
||||
nichts." Und: „NICHT MITREPARIERT, weil es kein Messgeraet dafuer
|
||||
gibt ... Hover laesst sich nicht pruefen."
|
||||
|
||||
DOCH -- es laesst sich pruefen. Hier steht das Messgeraet.
|
||||
|
||||
ERST DEN ZEIGER WEGSETZEN. Beim ersten Anlauf meldete diese
|
||||
Messung „die Kante ist 9px statt 6" und „unter dem Zeiger waechst
|
||||
sie nicht (9 -> 9)" -- beides stimmte, und beides war kein Befund
|
||||
am Programm: Der Klick auf „Bearbeiten" weiter oben hatte die Maus
|
||||
auf der ersten Karte stehen lassen. Gemessen wurde also zweimal der
|
||||
Zustand UNTER dem Zeiger. Eine Messung, die ihren Ausgangszustand
|
||||
nicht herstellt, misst den Rest des Tests mit. */
|
||||
await seite.mouse.move(2, 2);
|
||||
await seite.waitForTimeout(300);
|
||||
const optik = await seite.$$eval(".stufe", (gs) => gs.map((g) => {
|
||||
const k = g.querySelector(".kk");
|
||||
const s2 = k ? getComputedStyle(k) : null;
|
||||
return {
|
||||
stufe: g.dataset.stufe,
|
||||
ton: getComputedStyle(g).getPropertyValue("--ton").trim(),
|
||||
farbe: getComputedStyle(g).getPropertyValue("--stufe-farbe").trim(),
|
||||
kante: s2 ? s2.getPropertyValue("--kante").trim() : null,
|
||||
kantenbreite: s2 ? s2.backgroundSize.split(",")[0].trim() : null,
|
||||
nr: g.querySelector(".stufe__nr")?.textContent.trim() || null,
|
||||
};
|
||||
}));
|
||||
/* JEDE Stufe traegt IHREN Ton -- nicht den der Seite. Gezaehlt wird
|
||||
in der Bedingung, nicht nur im Text: Ein `every()` auf einer leeren
|
||||
Liste waere `true` und wuerde nichts beweisen. */
|
||||
ok(optik.length >= 3 && optik.every((o) => o.ton && o.ton === o.farbe),
|
||||
`jede der ${optik.length} Stufen traegt ihren eigenen Ton `
|
||||
+ `(${optik.map((o) => o.stufe + "=" + o.ton).join(", ")})`);
|
||||
/* Und die Toene sind verschieden -- sonst waere „jede traegt ihren
|
||||
eigenen" auch dann wahr, wenn alle denselben haetten. */
|
||||
ok(new Set(optik.map((o) => o.ton)).size === optik.length,
|
||||
`und zwar jede eine andere (${new Set(optik.map((o) => o.ton)).size} Toene auf ${optik.length} Stufen)`);
|
||||
/* `backgroundSize` liefert BEIDE Masse der ersten Ebene ("6px 100%").
|
||||
Der erste Anlauf verglich mit "6px" und meldete rot, obwohl ueberall
|
||||
6px standen -- ein Messfehler, der wie ein Befund aussah.
|
||||
|
||||
DER ZWEITE ANLAUF MELDETE DASSELBE, und die Ursache war eine
|
||||
andere: Beim Schreiben ueber die Kommandozeile wurde aus der
|
||||
Zeichenfolge fuer eine Wortgrenze ein echtes Steuerzeichen (0x08,
|
||||
Backspace) mitten im Ausdruck. Ein Ausdruck mit einem Backspace
|
||||
darin trifft natuerlich nie. Im Quelltext sah die Zeile voellig
|
||||
richtig aus -- sichtbar wurde das Byte erst mit `cat -v`. Genau
|
||||
davor warnt pruef-zeichen ("Serverdateien mit Steuerzeichen"), und
|
||||
genau sie haette es gefunden.
|
||||
|
||||
Deshalb jetzt `startsWith` statt eines Ausdrucks: Daran gibt es
|
||||
nichts, was beim Schreiben verstuemmelt werden koennte. */
|
||||
ok(optik.length >= 3 && optik.every((o) => (o.kantenbreite || "").startsWith("6px")),
|
||||
`die Farbkante der Karte ist 6px breit (${optik.map((o) => o.kantenbreite).join(", ")})`);
|
||||
/* Die Etappennummer wird aus WEITER abgeleitet: 01 bis 05, und
|
||||
„abgelehnt" bekommt keine. */
|
||||
const nummern = Object.fromEntries(optik.map((o) => [o.stufe, o.nr]));
|
||||
ok(nummern.neu === "01" && nummern.angesprochen === "02",
|
||||
`die Stufen sind nummeriert (neu=${nummern.neu}, angesprochen=${nummern.angesprochen})`);
|
||||
|
||||
/* HOVER -- gemessen mit dem Zeiger, nicht geglaubt.
|
||||
|
||||
`mouse.move` und nicht `page.hover()`: Letzteres wartet auf
|
||||
„bedienbar" und blieb beim ersten Anlauf haengen. Gemessen werden
|
||||
soll hier die Farbe, nicht die Bedienbarkeit. */
|
||||
const vorher = await seite.$eval(".kk", (k) => getComputedStyle(k).getPropertyValue("--kante").trim());
|
||||
const mitte = await seite.$eval(".kk", (k) => {
|
||||
const r = k.getBoundingClientRect();
|
||||
return { x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2) };
|
||||
});
|
||||
await seite.mouse.move(mitte.x, mitte.y);
|
||||
await seite.waitForTimeout(350);
|
||||
const nachher = await seite.$eval(".kk", (k) => getComputedStyle(k).getPropertyValue("--kante").trim());
|
||||
ok(vorher === "6px" && nachher === "9px",
|
||||
`unter dem Zeiger waechst die Kante (${vorher} -> ${nachher})`);
|
||||
await seite.mouse.move(0, 0);
|
||||
await seite.waitForTimeout(200);
|
||||
|
||||
/* Die Haarlinie in der Karte. Ein ungueltiger Farbwert laesst
|
||||
`border-image` lautlos ausfallen -- „none" heisst, sie fehlt. */
|
||||
const haar = await seite.$eval(".kk__info",
|
||||
(k) => getComputedStyle(k).borderImageSource);
|
||||
ok(haar.includes("gradient"),
|
||||
`die Haarlinie zwischen Kopf und Zahlen ist da (${haar.slice(0, 28)}…)`);
|
||||
|
||||
/* ===== GEGENPROBE: AUF DEM HANDY LIEGEN SIE UNTEREINANDER ========
|
||||
|
||||
Ohne diese Messung wuesste niemand, ob die Trennung ueberhaupt
|
||||
@@ -500,6 +589,34 @@ console.log("\n=== Die Seite selbst ===");
|
||||
ok(schmal.every((k) => k.breite >= 300),
|
||||
`keine Spalte wird gequetscht (${schmal.map((k) => k.breite).join(" / ")} px)`);
|
||||
|
||||
/* ===== UND AUF DEM SCHMALSTEN GERAET, DAS ES GIBT (320 px) =======
|
||||
|
||||
Die Karte hat links 26px Polster bekommen (davor 21), dazu eine
|
||||
6px-Kante. Was auf 390px passt, muss auf 320px nicht passen -- und
|
||||
ein Element, das ueber den Rand steht, erzeugt seitliches Scrollen
|
||||
auf der ganzen Seite.
|
||||
|
||||
GEMESSEN STATT DEN HAUSLAUF GESTARTET: `pruef-handy` prueft 186
|
||||
Dinge auf vielen Seiten und braucht 226 Sekunden. Die Frage hier
|
||||
ist eine einzige und in vier Sekunden beantwortet. */
|
||||
const engKontext = await browser.newContext({
|
||||
viewport: { width: 320, height: 720 }, hasTouch: true, isMobile: true,
|
||||
});
|
||||
await engKontext.addCookies(await ctx.cookies());
|
||||
const eng = await engKontext.newPage();
|
||||
await eng.goto(seite.url(), { waitUntil: "networkidle" });
|
||||
await eng.waitForTimeout(900);
|
||||
const ueber = await eng.$$eval(".stufe *", (ks) => ks
|
||||
.filter((k) => k.getBoundingClientRect().right > window.innerWidth + 1)
|
||||
.slice(0, 4)
|
||||
.map((k) => `${k.className || k.tagName} bis ${Math.round(k.getBoundingClientRect().right)}px`));
|
||||
const gemessen = await eng.$$eval(".stufe *", (ks) => ks.length);
|
||||
ok(gemessen > 20 && ueber.length === 0,
|
||||
`auf 320px steht keines der ${gemessen} Teile ueber den Rand (${ueber.join(", ") || "keins"})`);
|
||||
const quer = await eng.evaluate(() =>
|
||||
document.documentElement.scrollWidth - document.documentElement.clientWidth);
|
||||
ok(quer <= 1, `und die Seite laesst sich nicht seitlich schieben (${quer} px)`);
|
||||
|
||||
await browser.close();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user