diff --git a/server/pruef-backstage-import.mjs b/server/pruef-backstage-import.mjs index a9c10f43..70070e71 100644 --- a/server/pruef-backstage-import.mjs +++ b/server/pruef-backstage-import.mjs @@ -742,7 +742,7 @@ console.log("\n=== Die Seite ==="); const spannenBild = await seite.evaluate(() => ({ sichtbar: document.getElementById("spannen-block")?.hidden === false, karten: document.querySelectorAll(".spanne").length, - zeit: document.querySelector(".spanne__zeit")?.textContent || "", + zeit: document.querySelector(".spanne__spanne")?.textContent || "", tage: document.querySelector(".spanne__tage")?.textContent || "", schnitt: document.querySelector(".spanne__schnitt")?.textContent || "", satz: document.querySelector(".spannen__satz")?.textContent || "", @@ -758,6 +758,99 @@ console.log("\n=== Die Seite ==="); ok(/nicht für einen Tag/.test(spannenBild.satz), "und darueber steht, dass es kein Tageswert ist"); + /* ---- DIE HAUPTZAHL IST GROSS (14.09.2026) ----------------------- + Filipe zur ersten Fassung: "das muss viel geiler aussehen und viel + klarer." Sie war eine Liste ohne Rangfolge -- alles gleich gross, + nichts sprang heraus. + + GEMESSEN IN PIXELN, NICHT NACH GEFUEHL: Die Diamantenzahl muss + deutlich groesser sein als die Nebenwerte, sonst ist es wieder + eine Liste. */ + const groessen = await seite.evaluate(() => { + const g = (s) => { + const e = document.querySelector(s); + return e ? Math.round(parseFloat(getComputedStyle(e).fontSize)) : 0; + }; + return { haupt: g(".spanne__haupt-zahl"), neben: g(".spanne__zahl"), + spanne: g(".spanne__spanne"), + text: document.querySelector(".spanne__haupt-zahl")?.textContent || "" }; + }); + ok(groessen.haupt >= groessen.neben * 1.6, + `die Hauptzahl ist deutlich groesser als die Nebenwerte ` + + `(${groessen.haupt} px zu ${groessen.neben} px)`); + ok(groessen.spanne > groessen.neben, + `und die Spanne groesser als ein Nebenwert (${groessen.spanne} px)`); + ok(/\d/.test(groessen.text), `die Hauptzahl traegt Diamanten ("${groessen.text}")`); + + /* ---- EINE WOCHE OHNE EINEN EINZIGEN TAG (14.09.2026) ------------ + Filipe: "wieso werden die zahlen oben nicht ausgefuellt von der + excel datei?" + + Genau sein Fall: ein Zeitraum ist da, Tageszahlen gibt es keine. + Vorher standen dort sieben Karten mit "0" und "wie in der + Vorwoche" -- das sieht aus wie ein Fehler und beantwortet die + Frage nicht. + + HERGESTELLT WIRD DER FALL, nicht abgewartet: Kiros Tageszeilen + fallen weg, ein Zeitraum kommt hin. Eine Pruefung, die auf einen + Zustand hofft, prueft irgendwann gar nichts mehr. */ + { + const d4 = new DatabaseSync(DB); + d4.prepare("DELETE FROM leistung WHERE creator_id = ?").run(idKiro); + d4.prepare(`INSERT OR REPLACE INTO leistung_zeitraum + (creator_id, von, bis, tage, diamanten, dauer_min, follower_neu, erfasst, erfasst_von) + VALUES (?,?,?,?,?,?,?,?,?)`) + .run(idKiro, "2026-09-01", "2026-09-13", 13, 13210, 384, 97, + new Date().toISOString(), 1); + d4.close(); + } + await seite.goto(BASIS + `/workspace/leistung.html?creator=${idKiro}`, + { waitUntil: "networkidle" }); + await seite.waitForTimeout(1800); + + const ohneTage = await seite.evaluate(() => ({ + leerDa: document.getElementById("woche-leer")?.hidden === false, + kartenWeg: document.getElementById("zahlkarten")?.hidden === true, + nullen: [...document.querySelectorAll(".zahlkarte__wert")] + .filter((e) => e.offsetParent !== null && e.textContent.trim() === "0").length, + satz: document.getElementById("woche-leer")?.textContent || "", + })); + ok(ohneTage.leerDa, "statt der Nullen steht die Erklaerung da"); + ok(ohneTage.kartenWeg && ohneTage.nullen === 0, + `keine einzige sichtbare Null mehr (${ohneTage.nullen})`); + ok(/kein einziger Tag erfasst/.test(ohneTage.satz), + `sie sagt, WAS los ist ("${ohneTage.satz.slice(0, 46)}…")`); + ok(/01\.09\./.test(ohneTage.satz) && /13 Tage/.test(ohneTage.satz), + "und nennt den Zeitraum, der stattdessen da ist"); + ok(/EINEN Tag/.test(ohneTage.satz), + "und den Weg, wie man die Wochenzahlen doch fuellt"); + + if (process.env.SCHIRM) { + await seite.locator("#woche").screenshot( + { path: join(HIER, "pruef-woche-leer.png") }); + } + + /* GEGENPROBE: Sobald EIN Tag da ist, verschwindet die Erklaerung und + die Karten kommen zurueck. Ohne sie hiesse alles oben nur, dass + die Karten jetzt immer weg sind. */ + { + const d5 = new DatabaseSync(DB); + d5.prepare(`INSERT OR REPLACE INTO leistung + (creator_id, tag, diamanten, gueltiger_tag, erfasst, erfasst_von, quelle) + VALUES (?,?,?,1,?,?, 'hand')`) + .run(idKiro, gestern, 500, new Date().toISOString(), 1); + d5.close(); + } + await seite.reload({ waitUntil: "networkidle" }); + await seite.waitForTimeout(1600); + const mitTag = await seite.evaluate(() => ({ + leerDa: document.getElementById("woche-leer")?.hidden === false, + kartenDa: document.getElementById("zahlkarten")?.hidden === false, + })); + ok(!mitTag.leerDa && mitTag.kartenDa, + "mit einem einzigen Tag sind die Karten wieder da"); + + if (process.env.SCHIRM) { await seite.locator("#spannen-block").screenshot( { path: join(HIER, "pruef-spannen.png") }); diff --git a/workspace/app.webmanifest b/workspace/app.webmanifest index 5c9f4483..86a7dae9 100644 --- a/workspace/app.webmanifest +++ b/workspace/app.webmanifest @@ -13,25 +13,25 @@ "theme_color": "#06090f", "icons": [ { - "src": "/assets/img/app-symbole/workspace-192.png?v=202609141948", + "src": "/assets/img/app-symbole/workspace-192.png?v=202609142005", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-512.png?v=202609141948", + "src": "/assets/img/app-symbole/workspace-512.png?v=202609142005", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609141948", + "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609142005", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609141948", + "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609142005", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/assets/css/leistung.css b/workspace/assets/css/leistung.css index a516a92d..081f0584 100644 --- a/workspace/assets/css/leistung.css +++ b/workspace/assets/css/leistung.css @@ -432,67 +432,136 @@ .dialog--breit .neu { max-height: min(86vh, 900px); overflow-y: auto; } /* ===================================================================== - ZEITRÄUME AUS BACKSTAGE (14.09.2026) + ZEITRÄUME AUS BACKSTAGE — zweite Fassung (14.09.2026) - Filipe: "sieh zu dass die excel auch so durch geht." + Filipe zur ersten: "das muss viel geiler aussehen und viel klarer." - Sie stehen zwischen der Woche und den Tageszeilen -- gröber als ein - Tag, feiner als gar nichts. Und sie sehen ABSICHTLICH anders aus als - die Wochenkarten: Wer sie für Tageswerte hält, rechnet mit ihnen - weiter. Der Zeitraum steht deshalb ganz vorn und nicht als Beiwerk. + Er hatte recht. Die erste Fassung war eine Liste kleiner Werte ohne + Rangfolge: Spanne, Diamanten, LIVE, Follower -- alles gleich groß, + nichts sprang heraus. Wer draufschaut, will ZWEI Dinge in einer + halben Sekunde wissen: WELCHER Zeitraum und WIE VIELE Diamanten. + Genau die sind jetzt groß, alles andere ordnet sich darunter. + + DER RAHMEN IST BEWUSST ANDERS ALS BEI DEN WOCHENKARTEN. Wer einen + Zeitraum für einen Tageswert hält, rechnet mit ihm weiter -- die + Karte muss auf den ersten Blick sagen, dass sie etwas anderes ist. + Deshalb: eigene Farbe an der Kante, die Spanne als Überschrift, die + Zahl der Tage als Marke daneben. ===================================================================== */ .leistung-spannen { margin: 26px 0 0; } .spannen__satz { - margin: 4px 0 12px; - font-size: .8rem; line-height: 1.55; + margin: 4px 0 14px; + font-size: .82rem; line-height: 1.6; color: var(--text-still); - max-width: 62ch; + max-width: 64ch; } .spannen { - display: grid; gap: 10px; - grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); + display: grid; gap: 12px; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); } + .spanne { - border: 1px solid var(--rand); border-radius: 14px; - padding: 11px 13px 12px; - background: rgba(255, 255, 255, .025); + position: relative; overflow: hidden; + border: 1px solid var(--rand); border-radius: 16px; + padding: 14px 16px 15px; + background: + linear-gradient(180deg, rgba(255, 255, 255, .045), rgba(255, 255, 255, .012)), + var(--flaeche-tief, rgba(10, 16, 24, .72)); } +/* Die Kante links: ein Streifen in der Hausfarbe. Er sagt "andere + Sorte Zahl", ohne dass ein einziges Wort dafür nötig wäre. */ +.spanne::before { + content: ""; position: absolute; inset: 0 auto 0 0; + width: 3px; + background: linear-gradient(180deg, + color-mix(in srgb, var(--akzent) 75%, transparent), + color-mix(in srgb, var(--akzent) 15%, transparent)); +} + .spanne__kopf { - display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; - margin-bottom: 8px; + display: flex; align-items: center; gap: 9px; flex-wrap: wrap; + padding-bottom: 10px; margin-bottom: 11px; + border-bottom: 1px solid var(--rand); } -.spanne__zeit { - font-size: .95rem; font-weight: 650; color: var(--text); +.spanne__spanne { + display: inline-flex; align-items: baseline; gap: 5px; + font-size: 1.06rem; font-weight: 650; color: var(--text); font-variant-numeric: tabular-nums; } -/* Die Zahl der Tage ist die WICHTIGSTE Einordnung und trotzdem still: - "12.480 Diamanten" ueber drei Tage ist etwas anderes als ueber - dreizehn -- ohne diese Angabe sagt die Zahl nichts. */ +.spanne__strich { color: var(--text-still); font-weight: 400; } .spanne__tage { - font-size: .74rem; color: var(--text-still); - border: 1px solid var(--rand); border-radius: 999px; - padding: 1px 8px 2px; + font-size: .73rem; color: var(--text-leise); + border: 1px solid color-mix(in srgb, var(--akzent) 30%, var(--rand)); + background: color-mix(in srgb, var(--akzent) 10%, transparent); + border-radius: 999px; + padding: 2px 9px 3px; + white-space: nowrap; } -.spanne__werte { - display: grid; gap: 3px 14px; - grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); + +/* Die Hauptzahl. Groß, aber nicht grell -- sie soll die erste sein, + die man liest, nicht die einzige, die man sieht. */ +.spanne__haupt { + display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 9px; + margin-bottom: 12px; } -.spanne__wert { display: flex; flex-direction: column; gap: 1px; min-width: 0; } -.spanne__name { - /* .72rem = 11.52 px, knapp ueber der Lesbarkeitsgrenze von 11.5 px. - .68rem waeren 10.88 gewesen -- und eine gesperrte Versalzeile ist - ohnehin schwerer zu lesen als normale Schrift. Zum zweiten Mal an - diesem Tag derselbe Griff; deshalb steht die Zahl jetzt mit - Begruendung da und nicht nur als Wert. */ - font-size: .72rem; letter-spacing: .07em; text-transform: uppercase; +.spanne__haupt-zahl { + font-size: 1.85rem; font-weight: 700; line-height: 1.05; + color: var(--text); + font-variant-numeric: tabular-nums; +} +.spanne__haupt-name { + font-size: .78rem; letter-spacing: .06em; text-transform: uppercase; color: var(--text-still); } -.spanne__zahl { - font-size: .92rem; color: var(--text-leise); +/* Der Durchschnitt steht in derselben Zeile und deutlich kleiner: + Er ist eine Einordnung, kein zweiter Messwert. */ +.spanne__schnitt { + flex-basis: 100%; + font-size: .76rem; color: var(--text-still); font-variant-numeric: tabular-nums; } -.spanne__schnitt { - margin: 9px 0 0; padding-top: 8px; + +.spanne__werte { + display: grid; gap: 8px 14px; + grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); + padding-top: 11px; border-top: 1px solid var(--rand); - font-size: .76rem; color: var(--text-still); +} +.spanne__wert { display: flex; flex-direction: column; gap: 2px; min-width: 0; } +.spanne__name { + font-size: .72rem; letter-spacing: .05em; text-transform: uppercase; + color: var(--text-still); + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; +} +.spanne__zahl { + font-size: .95rem; color: var(--text-leise); + font-variant-numeric: tabular-nums; +} + +/* ===================================================================== + EINE WOCHE OHNE EINEN EINZIGEN TAG (14.09.2026) + + Filipe: "wieso werden die zahlen oben nicht ausgefüllt von der excel + datei?" Sieben Karten mit "0" und "wie in der Vorwoche" sehen aus + wie ein Fehler. Stattdessen steht dort jetzt die Antwort -- und der + Weg, wie man es ändert. + ===================================================================== */ +.woche-leer { + border: 1px dashed color-mix(in srgb, var(--akzent) 34%, var(--rand)); + border-radius: 14px; + padding: 14px 16px 15px; + background: color-mix(in srgb, var(--akzent) 5%, transparent); + max-width: 72ch; +} +.woche-leer__satz { + margin: 0 0 6px; + font-size: .96rem; font-weight: 600; color: var(--text); +} +.woche-leer__grund { + margin: 0; font-size: .84rem; line-height: 1.6; color: var(--text-leise); +} +.woche-leer__weg { + margin: 9px 0 0; padding-top: 9px; + border-top: 1px solid var(--rand); + font-size: .82rem; line-height: 1.6; color: var(--text-still); } diff --git a/workspace/assets/js/leistung.js b/workspace/assets/js/leistung.js index dd69bc7e..cb5fd3ef 100644 --- a/workspace/assets/js/leistung.js +++ b/workspace/assets/js/leistung.js @@ -661,16 +661,38 @@ if (!liste.length) return; for (const z of liste) { - const karte = el('div', 'spanne'); + const karte = el('article', 'spanne'); - const kopf = el('div', 'spanne__kopf'); - kopf.append(el('span', 'spanne__zeit', `${kurzTag(z.von)} – ${kurzTag(z.bis)}`)); - /* DIE ZAHL DER TAGE STEHT DABEI. Ohne sie sagt "12.480 - Diamanten" nichts: über drei Tage ist das etwas anderes als - über dreizehn. */ + /* ---- Kopf: die Spanne gross, die Dauer als Marke ------------- */ + const kopf = el('header', 'spanne__kopf'); + const spanne = el('div', 'spanne__spanne'); + spanne.append(el('span', 'spanne__von', kurzTag(z.von))); + spanne.append(el('span', 'spanne__strich', '–')); + spanne.append(el('span', 'spanne__bis', kurzTag(z.bis))); + kopf.append(spanne); + /* DIE ZAHL DER TAGE IST DIE WICHTIGSTE EINORDNUNG: "13.210 + Diamanten" ueber drei Tage ist etwas anderes als ueber + dreizehn. Sie steht deshalb neben der Spanne und nicht + irgendwo unten. */ kopf.append(el('span', 'spanne__tage', `${z.tage} Tage`)); karte.append(kopf); + /* ---- Die Hauptzahl -------------------------------------------- */ + if (z.diamanten !== null && z.diamanten !== undefined) { + const haupt = el('div', 'spanne__haupt'); + haupt.append(el('span', 'spanne__haupt-zahl', zahl(z.diamanten))); + haupt.append(el('span', 'spanne__haupt-name', 'Diamanten')); + if (z.tage > 0) { + /* DIE EINZIGE UMRECHNUNG, DIE EHRLICH IST -- und sie steht + als Durchschnitt da, nicht als Tageswert. Gespeichert wird + sie nirgends. */ + haupt.append(el('span', 'spanne__schnitt', + `Ø ${zahl(Math.round(z.diamanten / z.tage))} pro Tag`)); + } + karte.append(haupt); + } + + /* ---- Die uebrigen Werte --------------------------------------- */ const werte = el('div', 'spanne__werte'); const zeig = (name, wert, form) => { if (wert === null || wert === undefined) return; @@ -679,22 +701,13 @@ w.append(el('span', 'spanne__zahl', form(wert))); werte.append(w); }; - zeig('Diamanten', z.diamanten, zahl); - zeig('LIVE', z.dauer_min, stunden); - zeig('Gültige Tage', z.gueltige_tage, (n) => String(n)); + zeig('LIVE-Zeit', z.dauer_min, stunden); + zeig('Gültige Tage', z.gueltige_tage, (n) => `${n} von ${z.tage}`); zeig('Ø Zuschauer', z.zuschauer_avg, zahl); + zeig('Spitze', z.zuschauer_max, zahl); zeig('Neue Follower', z.follower_neu, zahl); - karte.append(werte); + if (werte.children.length) karte.append(werte); - /* PRO TAG IM SCHNITT -- die einzige Umrechnung, die ehrlich ist: - Sie steht als Durchschnitt da und nicht als Tageswert, und sie - wird nirgends gespeichert. Wer eine Woche vergleichen will, - braucht sie; wer sie für einen echten Tag hält, liest das - Wort "Ø" nicht. */ - if (z.diamanten !== null && z.diamanten !== undefined && z.tage > 0) { - karte.append(el('p', 'spanne__schnitt', - `Ø ${zahl(Math.round(z.diamanten / z.tage))} Diamanten pro Tag`)); - } ziel.append(karte); } } @@ -730,6 +743,46 @@ : `${e.tage} von 7 Tagen erfasst`; $('erfassung').dataset.knapp = e.tage < 4 ? 'ja' : ''; + /* KEIN TAG ERFASST -> DIE ANTWORT STATT SIEBEN NULLEN (14.09.2026). + + Filipe: "wieso werden die zahlen oben nicht ausgefüllt von der + excel datei?" + + Die Frage entsteht an DIESER Stelle, also steht die Antwort hier. + Sieben Karten mit "0" und "wie in der Vorwoche" sehen aus wie ein + Fehler -- dabei ist einfach kein einziger Tag erfasst, weil die + Backstage-Ausgabe einen ZEITRAUM enthielt. + + Und sie sagt nicht nur WARUM, sondern auch, was zu tun ist: + in Backstage den Zeitraum auf einen Tag stellen. Ein Hinweis ohne + Ausweg ist eine Sackgasse mit Erklärung. */ + const spannen = stand?.zeitraeume || []; + const leer = $('woche-leer'); + if (e.tage === 0) { + leer.textContent = ''; + leer.append(el('p', 'woche-leer__satz', + 'Für diese Woche ist noch kein einziger Tag erfasst.')); + if (spannen.length) { + const s0 = spannen[0]; + leer.append(el('p', 'woche-leer__grund', + `Deine Backstage-Ausgabe deckt ${kurzTag(s0.von)} – ${kurzTag(s0.bis)} ab ` + + `(${s0.tage} Tage auf einmal). Aus einer Summe über ${s0.tage} Tage lässt ` + + 'sich nicht ablesen, wie ein einzelner Tag lief – deshalb steht sie unten ' + + 'als Zeitraum und nicht hier oben.')); + leer.append(el('p', 'woche-leer__weg', + 'Wenn du die Wochenzahlen füllen willst: In Backstage den Zeitraum auf ' + + 'EINEN Tag stellen, herunterladen, hier einlesen – je Tag einmal.')); + } else { + leer.append(el('p', 'woche-leer__grund', + 'Trag einen Tag von Hand ein oder lies eine Datei mit Tageszeilen ein.')); + } + leer.hidden = false; + $('zahlkarten').hidden = true; + } else { + leer.hidden = true; + $('zahlkarten').hidden = false; + } + wochenKartenBauen(); zieleBauen(); await tageLaden(); diff --git a/workspace/aufgaben.html b/workspace/aufgaben.html index 4f65bbc0..cdc7de30 100644 --- a/workspace/aufgaben.html +++ b/workspace/aufgaben.html @@ -12,19 +12,19 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - + + + + + + - +
@@ -252,11 +252,11 @@ - - - - - - + + + + + +