From 17157b4f1815c69f6f8ef9e2cb11279e727a738d Mon Sep 17 00:00:00 2001 From: Dogfather Date: Sun, 6 Sep 2026 17:48:03 +0200 Subject: [PATCH] Sicht-Umschalter: ein Auge statt des Wortes "SICHT" Filipe zu dem Feld in der Kopfleiste: "das soll viel besser aussehen viel geiler aber nicht so eine scheisse." Er hatte recht. Da stand ein Etikett mit dem Wort SICHT und daneben ein Auswahlfeld -- ein Formular, das in die Kopfleiste gerutscht war. Drei Aenderungen: * DAS AUGE ersetzt das Wort. Es sagt dasselbe in einem Zeichen und laesst dem NAMEN den Platz, um den es eigentlich geht. Fuer Vorleseprogramme bleibt die Beschriftung erhalten, nur unsichtbar -- sie ersatzlos zu loeschen haette das Feld unbeschriftet gelassen. * "Meine Sicht" statt "Alles (meine Sicht)". Der Zusatz erklaerte nichts und machte den Knopf so breit, dass am Handy nichts anderes mehr danebenpasste. * EIN KREUZ statt "zurueck zu mir". Der Satz brauchte mehr Platz als der Name daneben, und was ein Kreuz an einer aktiven Auswahl tut, weiss jeder. Die Worte bleiben im aria-label und im Titel. DIE EIGENTLICHE VERBESSERUNG ist aber die Hierarchie: Im Normalfall ist der Umschalter still (graues Auge, ruhiger Rand). Sobald eine FREMDE Sicht laeuft, traegt er ganz Farbe -- nicht nur ein Zusatzknopf am Rand. Das ist der gefaehrlichste Zustand dieser Funktion: Wer sie vergisst, sieht am naechsten Tag drei Aufgaben statt dreissig und haelt das fuer den Bestand. Ein Zustand, der Schaden anrichtet, muss lauter sein als einer, der nichts tut. Co-Authored-By: Claude Opus 5 --- .gitignore | 3 ++ server/bild-sicht.mjs | 88 ++++++++++++++++++++++++++++++++++ workspace/assets/css/start.css | 45 ++++++++++++++++- workspace/assets/js/kopf.js | 36 +++++++++++++- workspace/aufgaben.html | 16 +++---- workspace/automation.html | 18 +++---- workspace/bereich.html | 26 +++++----- workspace/calls.html | 20 ++++---- workspace/chat.html | 16 +++---- workspace/content.html | 22 ++++----- workspace/dateien.html | 18 +++---- workspace/index.html | 4 +- workspace/kalender.html | 18 +++---- workspace/personen.html | 18 +++---- workspace/profil.html | 20 ++++---- workspace/report.html | 20 ++++---- workspace/scouting.html | 18 +++---- workspace/start.html | 14 +++--- workspace/startcheck.html | 20 ++++---- workspace/steckbrief.html | 18 +++---- workspace/uebersicht.html | 14 +++--- workspace/wissen.html | 18 +++---- 22 files changed, 328 insertions(+), 162 deletions(-) create mode 100644 server/bild-sicht.mjs diff --git a/.gitignore b/.gitignore index 09be56c7..b16b4d62 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,9 @@ gesamtlauf.txt # Bilder zum Ansehen (server/bild-*.mjs) -- entstehen bei jedem Lauf neu tagesblick-*.png +chat-*.png +calls-*.png +sicht-*.png # --------------------------------------------------------------------- # Bilder der Pruefungen (06.09.2026) diff --git a/server/bild-sicht.mjs b/server/bild-sicht.mjs new file mode 100644 index 00000000..c24ecdcf --- /dev/null +++ b/server/bild-sicht.mjs @@ -0,0 +1,88 @@ +/* Bild des Sicht-Umschalters in BEIDEN Zustaenden -- zum Ansehen. + Der Normalfall (eigene Sicht) und der Ausnahmefall (fremde Sicht) + sollen sich deutlich unterscheiden; nur nebeneinander sieht man, ob + das gelungen ist. */ +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +const ordner = mkdtempSync(join(tmpdir(), "ws-sicht-")); +process.env.WORKSPACE_DB = join(ordner, "workspace.db"); +const { portMussFreiSein } = await import("./helfer-port.mjs"); +await portMussFreiSein(4329, "das Bildwerkzeug"); +process.env.PORT = "4329"; +process.env.SITE_ACCESS_SECRET = "lokaler-test"; +process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00"; + +const express = (await import("express")).default; +const ec = express.response.cookie; +express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); }; +await import("./index.js"); +await new Promise((r) => setTimeout(r, 1000)); +const BASIS = "http://127.0.0.1:4329"; + +const { DatabaseSync } = await import("node:sqlite"); +const { scryptSync, randomBytes } = await import("node:crypto"); +await fetch(BASIS + "/workspace/api/anmelden", { + method: "POST", headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ rolle: "admin", code: "x" }) }).catch(() => {}); +for (let i = 0; i < 60; i++) { + try { + const p = new DatabaseSync(process.env.WORKSPACE_DB); + try { p.prepare("SELECT 1 FROM personen LIMIT 1").get(); break; } finally { p.close(); } + } catch { await new Promise((r) => setTimeout(r, 250)); } +} +const d = new DatabaseSync(process.env.WORKSPACE_DB); +const j = new Date().toISOString(); +function anlegen(name, rolle, code) { + const salt = randomBytes(16).toString("hex"); + const hash = scryptSync(code, salt, 64, { N: 32768, r: 8, p: 1, maxmem: 96 * 1024 * 1024 }).toString("hex"); + d.prepare("INSERT INTO personen (name,rolle,code_hash,code_salt,code_n,aktiv,erstellt) VALUES (?,?,?,?,?,1,?)") + .run(name, rolle, hash, salt, 32768, j); + return d.prepare("SELECT last_insert_rowid() AS id").get().id; +} +anlegen("Filipe", "admin", "CODE-DOGI-0001"); +anlegen("Patrick von Hohenstein", "scout", "CODE-SCOU-0001"); +const idLuna = anlegen("Luna", "creator", "CODE-CREA-0001"); +d.close(); + +const pw = await import("file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs"); +const browser = await pw.chromium.launch(); +const ctx = await browser.newContext({ viewport: { width: 1400, height: 900 }, deviceScaleFactor: 3 }); +const seite = await ctx.newPage(); +await seite.goto(BASIS + "/workspace/", { waitUntil: "networkidle" }); +await seite.click('.rolle[data-rolle="admin"]'); +await seite.fill("#code", "CODE-DOGI-0001"); +await seite.click("button[type=submit]"); +await seite.waitForURL("**/start.html", { timeout: 25000 }); +await seite.waitForTimeout(1500); + +const feld = await seite.$("#sicht-wahl"); +if (feld) { + await feld.screenshot({ path: "sicht-eigene.png" }); + console.log("sicht-eigene.png geschrieben"); +} + +/* Jetzt auf Lunas Sicht umschalten. */ +await seite.selectOption("#sicht-feld", String(idLuna)).catch(async () => { + /* wahl.js ersetzt das