From 542070e864045f1fc641f9e803e7d38704021696 Mon Sep 17 00:00:00 2001 From: Dogfather Date: Fri, 18 Sep 2026 21:59:53 +0200 Subject: [PATCH] Community: der Chat-Knopf fuehrte auf JEDER Seite ins Leere ERST DIE METHODE, DANN DER FUND. An einem Tag habe ich in der Community elf Dinge gefunden, die dort nicht hingehoerten -- jedes einzelne, weil ich zufaellig hingesehen habe. Das ist keine Methode. Der Workspace ist fuer die Agentur gebaut worden, und die Community hat ihn geerbt; solche Reste findet man nicht durch Nachdenken, sondern indem man ALLE Seiten durchgeht, die ein Mitglied erreichen kann. server/pruef-community-sicht.mjs tut genau das. Sie leitet aus rechte.js ab, welche Seiten offenstehen (4) und welche nicht (27) -- von Hand aufgezaehlt waere das eine Liste, die bei der naechsten Seite niemand nachzieht --, oeffnet jede davon als Mitglied und fragt zweierlei: Fuehrt ein sichtbarer Weg auf eine verbotene Seite? Steht dort die Sprache eines Arbeitsplatzes? BEIM ERSTEN LAUF: 27 sichtbare Wege, davon ZEHN ins Leere -- und alle zehn derselbe Knopf. Der Chat steht oben rechts in der Kopfleiste, auf jeder einzelnen Seite, mit Zaehler. `chat.html` steht einem Mitglied aber nicht offen: Der Klick landet wieder auf der Startseite. Keine Meldung, kein Grund, nichts passiert -- an der Stelle, die man am ehesten drueckt. Der Knopf haengt jetzt an `darf_chat` aus /api/ich, und das kommt aus derselben Rechtetabelle wie die Schranke dahinter. Die Oberflaeche vergleicht keine Rollennamen -- das waere eine zweite Wahrheit, die bei der naechsten Rechteaenderung auseinanderlaeuft. Dieselbe Ueberlegung steht zwei Zeilen weiter oben schon einmal. UND DIE PRUEFUNG HAT GLEICH MEINEN EIGENEN FEHLER GEFUNDEN: Die erste Fassung stand in `aufbauChat`, wo es die Person gar nicht gibt -- ReferenceError auf allen zehn Seiten. Ohne den Skriptfehler-Abschnitt waere der Knopf verschwunden UND die Seite kaputt gewesen, und das haette wie ein Erfolg ausgesehen. Jetzt haengt es dort, wo die Person ankommt (`werZeigen`) -- ein vorhandener Knopf laesst sich immer entfernen, auf die Reihenfolge des Ladens zu bauen waere eine Annahme. GEGENPROBE: DogFather hat seinen Chat-Knopf weiterhin und 24 Wege auf andere Seiten. Ohne diesen Abschnitt saehe eine abgeschaffte Funktion genauso aus wie eine, die richtig entscheidet. 7 Pruefungen, 0 Fehler. Co-Authored-By: Claude Opus 5 --- server/pruef-community-sicht.mjs | 268 +++++++++++++++++++++++++++++++ server/workspace.js | 14 ++ workspace/app.webmanifest | 8 +- workspace/assets/js/kopf.js | 23 +++ workspace/aufgaben.html | 24 +-- workspace/automation.html | 26 +-- workspace/befinden.html | 24 +-- workspace/bereich.html | 36 ++--- workspace/bewerben.html | 30 ++-- workspace/bewerbungen.html | 28 ++-- workspace/calls.html | 28 ++-- workspace/chat.html | 28 ++-- workspace/content.html | 30 ++-- workspace/crew-index.html | 10 +- workspace/crew.webmanifest | 8 +- workspace/dateien.html | 26 +-- workspace/entwicklung.html | 24 +-- workspace/index.html | 8 +- workspace/kalender.html | 28 ++-- workspace/leistung.html | 26 +-- workspace/personen.html | 26 +-- workspace/profil.html | 28 ++-- workspace/rechte.html | 24 +-- workspace/report.html | 28 ++-- workspace/scouting.html | 26 +-- workspace/start.html | 24 +-- workspace/startcheck.html | 28 ++-- workspace/steckbrief.html | 28 ++-- workspace/talente.html | 26 +-- workspace/team.html | 26 +-- workspace/teamlage.html | 24 +-- workspace/teilen.html | 22 +-- workspace/treff-moderation.html | 24 +-- workspace/treff-regeln.html | 26 +-- workspace/uebersicht.html | 26 +-- workspace/wissen.html | 26 +-- 36 files changed, 707 insertions(+), 402 deletions(-) create mode 100644 server/pruef-community-sicht.mjs diff --git a/server/pruef-community-sicht.mjs b/server/pruef-community-sicht.mjs new file mode 100644 index 00000000..cc1b1422 --- /dev/null +++ b/server/pruef-community-sicht.mjs @@ -0,0 +1,268 @@ +/* ===================================================================== + WAS EIN MITGLIED DER COMMUNITY SIEHT -- SYSTEMATISCH (18.09.2026) + + Filipe: „perfektioniere jede einzelne kategorie der community." + + --------------------------------------------------------------------- + WARUM ES DIESE PRÜFUNG GIBT + + An einem Tag habe ich in der Community elf Dinge gefunden, die dort + nicht hingehörten: Aufgabenzähler, „gönn dir was", „0 betreut", + sieben Links auf eine Seite, die ein Mitglied gar nicht öffnen darf. + Jeder einzelne Fund kam daher, dass ich zufällig hingesehen habe. + + Das ist keine Methode. Der Workspace ist für die Agentur gebaut + worden, und die Community hat ihn geerbt -- überall dort, wo + niemand hingesehen hat, steht noch die Sprache und die Logik eines + Arbeitsplatzes. Solche Reste findet man nicht durch Nachdenken, + sondern indem man ALLE Seiten durchgeht, die ein Mitglied erreichen + kann. + + --------------------------------------------------------------------- + ZWEI FRAGEN, BEIDE MESSBAR + + 1. TOTE WEGE: Führt irgendein Link, Knopf oder Formular auf eine + Seite, die diese Person nicht öffnen darf? Sie landet dann wieder + auf der Startseite -- ohne Meldung, ohne Grund. Man drückt, es + passiert nichts, und beim nächsten Knopf zweifelt man an sich. + + 2. FREMDE SPRACHE: Stehen dort Wörter, die es hier nicht gibt -- + „Review", „betreut", „Pipeline", „Creator anlegen"? Sie sind + nicht falsch, sie gehören nur jemand anderem. + + Aufrufen mit: node server/pruef-community-sicht.mjs + ===================================================================== */ +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { request as httpAnfrage } from "node:http"; +import { portMussFreiSein } from "./helfer-port.mjs"; + +const PORT = await portMussFreiSein(4198, "pruef-community-sicht"); +const ordner = mkdtempSync(join(tmpdir(), "ws-cs-")); +process.env.WORKSPACE_DB = join(ordner, "workspace.db"); +process.env.PORT = String(PORT); +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 }); }; +import { notbremse } from "./helfer-notbremse.mjs"; +await import("./index.js"); +notbremse(180_000, "pruef-community-sicht"); +await new Promise((r) => setTimeout(r, 700)); + +process.on("uncaughtException", (f) => { console.error("ABSTURZ:", f); process.exit(7); }); + +let fehler = 0, geprueft = 0; +const melde = (t) => console.log(t); +const ok = (b, t) => { geprueft++; console.log((b ? " ok " : " FEHL ") + t); if (!b) fehler++; }; + +const CREW = "crew.dogfather-universe.com"; + +/* --------------------------------------------------------------------- + WELCHE SEITEN DARF EIN MITGLIED? -- aus der Rechtetabelle abgeleitet. + + NICHT VON HAND AUFGEZÄHLT. Eine Liste hier müsste bei jeder neuen + Seite nachgezogen werden, und genau das vergisst man. Die Tabelle + in rechte.js ist ohnehin die Wahrheit -- also wird sie gefragt. + --------------------------------------------------------------------- */ +const { darfSeite } = await import("./rechte.js"); +const { readFileSync, readdirSync } = await import("node:fs"); +const alleSeiten = readdirSync(join(import.meta.dirname, "..", "workspace")) + .filter((d) => d.endsWith(".html")); + +const GAST = { rolle: "gast", haus: "crew" }; +const erlaubt = alleSeiten.filter((d) => darfSeite(GAST, `/workspace/${d}`)); +const verboten = alleSeiten.filter((d) => !darfSeite(GAST, `/workspace/${d}`)); + +melde(""); +melde("=== 1. Was ueberhaupt offensteht ==="); +ok(erlaubt.length >= 3 && erlaubt.length <= 8, + `ein Mitglied darf ${erlaubt.length} Seiten: ${erlaubt.join(", ")}`); +ok(verboten.length >= 15, + `und ${verboten.length} nicht -- so viele Wege gibt es, ins Leere zu zeigen`); + +/* --------------------------------------------------------------------- + DIE MESSUNG IM BROWSER + --------------------------------------------------------------------- */ +function roh(pfad, host, kopf = {}, koerper = null) { + return new Promise((f, s) => { + const a = httpAnfrage({ + host: "127.0.0.1", port: PORT, path: pfad, + method: koerper ? "POST" : "GET", + headers: { Host: host, ...(koerper ? { "Content-Type": "application/json" } : {}), ...kopf }, + }, (an) => { + let t = ""; + an.on("data", (c) => { t += c; }); + an.on("end", () => f({ code: an.statusCode, text: t, kopf: an.headers })); + }); + a.on("error", s); + if (koerper) a.write(JSON.stringify(koerper)); + a.end(); + }); +} + +const { DatabaseSync } = await import("node:sqlite"); +const { scryptSync, randomBytes } = await import("node:crypto"); +{ + const d = new DatabaseSync(process.env.WORKSPACE_DB); + for (const [name, rolle, code] of [ + ["Filipe", "admin", "CODE-DOGI-0001"], + ["Mara", "gast", "CODE-GAST-0001"], + ]) { + const salz = randomBytes(16).toString("hex"); + const hash = scryptSync(code, salz, 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, salz, 32768, new Date().toISOString()); + } + d.close(); +} + +async function anmelden(rolle, code) { + let a = await roh("/workspace/api/anmelden", CREW, {}, { rolle, code }); + if (a.code === 400 && a.text.includes("alter_offen")) { + a = await roh("/workspace/api/anmelden", CREW, {}, { rolle, code, alter_ok: true }); + } + return [].concat(a.kopf["set-cookie"] || []).map((z) => z.split(";")[0]).join("; "); +} +const kGast = await anmelden("gast", "CODE-GAST-0001"); +const kDogi = await anmelden("admin", "CODE-DOGI-0001"); + +/* Damit die Bretter nicht leer sind -- auf einer leeren Seite findet + man keine Wege, die ins Leere fuehren. */ +for (const b of ["treff", "anschlag", "ansteht", "wunsch", "highlight", "regeln", "mitmachen"]) { + await roh(`/workspace/api/bereich/${b}/start`, CREW, + { cookie: kDogi, origin: `http://${CREW}:${PORT}` }, {}); +} + +let pw = null; +try { + pw = await import("file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs"); +} catch { /* dritter Ausgang unten */ } + +if (!pw) { + melde(""); + melde("KANN NICHT NACHSEHEN: Playwright fehlt -- die Seiten wurden nicht geoeffnet."); + melde(`${geprueft} Pruefungen, ${fehler} Fehler`); + process.exit(3); +} + +/* WÖRTER, DIE JEMAND ANDEREM GEHÖREN. + + Keine Rollennamen -- die stehen bewusst nirgends in ausgelieferten + Dateien. Gesucht wird nach der SPRACHE eines Arbeitsplatzes. */ +const FREMDE_WOERTER = [ + "Vorarbeiten", "gönn dir was", "betreut", "Review", + "Pipeline", "überfällig", "In Arbeit", "Abgebrochen", +]; + +const browser = await pw.chromium.launch(); +try { + const ctx = await browser.newContext({ viewport: { width: 1400, height: 1000 } }); + await ctx.addCookies(kGast.split("; ").filter(Boolean).map((z) => { + const [name, ...rest] = z.split("="); + return { name, value: rest.join("="), domain: "127.0.0.1", path: "/" }; + })); + const seite = await ctx.newPage(); + const skriptfehler = []; + seite.on("pageerror", (e) => skriptfehler.push(String(e).slice(0, 100))); + + /* Jede erlaubte Seite -- und bei bereich.html jedes der sieben + Bretter, denn sie sehen völlig verschieden aus. */ + const ziele = []; + for (const d of erlaubt) { + if (d === "bereich.html") { + for (const b of ["treff", "anschlag", "ansteht", "wunsch", "highlight", "regeln", "mitmachen"]) { + ziele.push(`${d}?b=${b}`); + } + } else ziele.push(d); + } + + melde(""); + melde("=== 2. Wege, die ins Leere fuehren ==="); + let toteWege = 0, geprueftLinks = 0; + const gefunden = []; + for (const ziel of ziele) { + await seite.goto(`http://127.0.0.1:${PORT}/workspace/${ziel}`, { waitUntil: "networkidle" }); + await seite.waitForTimeout(900); + const wege = await seite.evaluate(() => + [...document.querySelectorAll("a[href]")] + .filter((a) => a.offsetParent !== null) + .map((a) => ({ ziel: a.getAttribute("href"), text: a.textContent.trim().slice(0, 30) }))); + for (const w of wege) { + const datei = String(w.ziel).split("?")[0].split("#")[0].replace(/^\.?\//, ""); + if (!datei.endsWith(".html")) continue; + geprueftLinks++; + if (verboten.includes(datei)) { + toteWege++; + gefunden.push(`${ziel}: „${w.text}" -> ${datei}`); + } + } + } + /* DIE ANZAHL GEHÖRT IN DIE BEDINGUNG. Ohne sie wäre „0 tote Wege" + auch dann wahr, wenn gar keine Seite geladen hätte. */ + ok(geprueftLinks >= 20 && toteWege === 0, + `${geprueftLinks} sichtbare Wege auf ${ziele.length} Seiten, davon ${toteWege} ins Leere`); + for (const g of gefunden.slice(0, 10)) console.log(` -> ${g}`); + + melde(""); + melde("=== 3. Sprache, die jemand anderem gehoert ==="); + let fremd = 0; + const wo = []; + for (const ziel of ziele) { + await seite.goto(`http://127.0.0.1:${PORT}/workspace/${ziel}`, { waitUntil: "networkidle" }); + await seite.waitForTimeout(700); + const text = await seite.evaluate(() => document.body.innerText); + for (const w of FREMDE_WOERTER) { + if (text.includes(w)) { fremd++; wo.push(`${ziel}: „${w}"`); } + } + } + ok(fremd === 0, `keine fremde Arbeitssprache auf ${ziele.length} Seiten (${fremd} Stellen)`); + for (const g of wo.slice(0, 10)) console.log(` -> ${g}`); + + /* ===================================================================== + 4. DIE GEGENPROBE: BEHAELT DAS TEAM SEINE WEGE? + + Was hier weggenommen wird, weil es fuer ein Mitglied ins Leere + fuehrt, muss fuer die anderen stehen bleiben. Ohne diesen + Abschnitt saehe eine abgeschaffte Funktion genauso aus wie eine, + die richtig entscheidet -- und zwar in beiden Faellen gruen. + ===================================================================== */ + melde(""); + melde("=== 4. Und behaelt das Team seine Wege? ==="); + { + const ctx2 = await browser.newContext({ viewport: { width: 1400, height: 1000 } }); + await ctx2.addCookies(kDogi.split("; ").filter(Boolean).map((z) => { + const [name, ...rest] = z.split("="); + return { name, value: rest.join("="), domain: "127.0.0.1", path: "/" }; + })); + const seite2 = await ctx2.newPage(); + await seite2.goto(`http://127.0.0.1:${PORT}/workspace/start.html`, { waitUntil: "networkidle" }); + await seite2.waitForTimeout(1200); + const z = await seite2.evaluate(() => ({ + chat: !!document.querySelector(".chat-knopf"), + wege: [...document.querySelectorAll("a[href$='.html']")].length, + })); + ok(z.chat, "DogFather hat seinen Chat-Knopf weiterhin"); + ok(z.wege >= 5, `und weiterhin Wege auf andere Seiten (${z.wege})`); + await ctx2.close(); + } + + melde(""); + melde("=== 5. Und laeuft ueberhaupt alles? ==="); + ok(skriptfehler.length === 0, + `kein Skriptfehler auf ${ziele.length} Seiten` + + (skriptfehler.length ? ` -- ${skriptfehler[0]}` : "")); +} finally { + await browser.close(); +} + +melde(""); +melde(`${geprueft} Pruefungen, ${fehler} Fehler`); +melde(fehler ? "NICHT IN ORDNUNG" : "ALLES IN ORDNUNG"); +try { rmSync(ordner, { recursive: true, force: true }); } catch { /* Rest */ } +process.exit(fehler ? 1 : 0); diff --git a/server/workspace.js b/server/workspace.js index 5ef70edb..62fcedba 100644 --- a/server/workspace.js +++ b/server/workspace.js @@ -4786,6 +4786,20 @@ workspaceRouter.get("/workspace/api/ich", (req, res) => { `ich.rolle === 'admin'`, und dieselbe Zeile schaltete auch das Loeschen frei; die beiden gehoeren nicht zusammen. */ darf_rollen_wechseln: darfRollenWechseln(person), + /* OB DER CHAT-KNOPF IN DER KOPFLEISTE ERSCHEINT (18.09.2026). + + Er wurde auf JEDER Seite gebaut. Fuer ein Mitglied der Community + fuehrte er ins Leere: `chat.html` steht ihm nicht offen, der + Klick landete wieder auf der Startseite. Gemessen von + pruef-community-sicht: zehn Seiten, zehn tote Wege -- und der + Knopf steht oben rechts, wo man ihn am ehesten drueckt. + + DIE ANTWORT KOMMT AUS DERSELBEN TABELLE wie die Schranke selbst. + Die Oberflaeche vergleicht keine Rollennamen -- das waere eine + zweite Wahrheit, und bei der naechsten Rechteaenderung liefe sie + auseinander. Genau die Ueberlegung steht schon zwei Zeilen + darueber; hier gilt sie noch einmal. */ + darf_chat: darfSeite(person, "/workspace/chat.html"), /* DIE KACHELN, WENN SIE NICHT IM BROWSER STEHEN DUERFEN. Fuer die fuenf bekannten Rollen steht hier `null`, und die diff --git a/workspace/app.webmanifest b/workspace/app.webmanifest index 6c66103f..28e2eb36 100644 --- a/workspace/app.webmanifest +++ b/workspace/app.webmanifest @@ -22,25 +22,25 @@ }, "icons": [ { - "src": "/assets/img/app-symbole/workspace-192.png?v=202609182128", + "src": "/assets/img/app-symbole/workspace-192.png?v=202609182158", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-512.png?v=202609182128", + "src": "/assets/img/app-symbole/workspace-512.png?v=202609182158", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609182128", + "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609182158", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609182128", + "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609182158", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/assets/js/kopf.js b/workspace/assets/js/kopf.js index c7fc4fd2..36e552e2 100644 --- a/workspace/assets/js/kopf.js +++ b/workspace/assets/js/kopf.js @@ -20,6 +20,28 @@ Steht hier und nicht in jeder Seitendatei -- jede von ihnen setzte bisher dieselbe Zeile selbst zusammen, vierzehnmal. */ window.werZeigen = function (ich) { + /* DER CHAT-KNOPF GEHOERT NICHT ZU JEDEM (18.09.2026). + + Er wurde auf JEDER Seite gebaut. Fuer ein Mitglied der Community + fuehrte er ins Leere: `chat.html` steht ihm nicht offen, der + Klick landete wieder auf der Startseite -- keine Meldung, kein + Grund, nichts passiert. Gemessen von pruef-community-sicht: + zehn Seiten, zehn tote Wege, und der Knopf steht oben rechts, + wo man ihn am ehesten drueckt. + + HIER UND NICHT IN `aufbauChat`: Dort gibt es die Person nicht -- + sie kommt als Parameter in diese Funktion, und zwar je nach + Seite frueher oder spaeter als der Knopf gebaut wird. Auf die + Reihenfolge zu bauen waere eine Annahme; ein vorhandener Knopf + laesst sich dagegen immer entfernen. + + `=== false` und nicht `!`: Fehlt die Angabe (aeltere Antwort des + Servers), bleibt alles wie bisher. Ein fehlendes Feld soll + niemandem den Chat wegnehmen. */ + if (ich && ich.darf_chat === false) { + document.querySelector('.chat-knopf')?.remove(); + } + const ziel = document.getElementById('wer'); if (!ziel || !ich) return; ziel.textContent = ''; @@ -800,6 +822,7 @@ /* Auf der Chatseite selbst gibt es nichts zu verlinken. */ if (/\/chat\.html$/.test(location.pathname)) return; + const el = (tag, klasse, text) => { const k = document.createElement(tag); if (klasse) k.className = klasse; diff --git a/workspace/aufgaben.html b/workspace/aufgaben.html index 7b4ec5b4..aba98357 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. --> - - - - - - + + + + + + - + @@ -291,10 +291,10 @@ - - - - - + + + + + diff --git a/workspace/automation.html b/workspace/automation.html index a7ee71ea..40a424c9 100644 --- a/workspace/automation.html +++ b/workspace/automation.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -168,10 +168,10 @@ - - - - - + + + + + diff --git a/workspace/befinden.html b/workspace/befinden.html index 779b08b1..d9c97602 100644 --- a/workspace/befinden.html +++ b/workspace/befinden.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -105,9 +105,9 @@ - - - - + + + + diff --git a/workspace/bereich.html b/workspace/bereich.html index 1e59a274..8b85d28c 100644 --- a/workspace/bereich.html +++ b/workspace/bereich.html @@ -12,24 +12,24 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - + + + + + + - - + + - + @@ -251,14 +251,14 @@ - - - - - - - - - + + + + + + + + + diff --git a/workspace/bewerben.html b/workspace/bewerben.html index 18264839..c0643549 100644 --- a/workspace/bewerben.html +++ b/workspace/bewerben.html @@ -7,17 +7,17 @@ - - - - - - - - - + + + + + + + + + - + @@ -107,10 +107,10 @@ - - - - - + + + + + diff --git a/workspace/bewerbungen.html b/workspace/bewerbungen.html index 561ca9a9..dc2fcd15 100644 --- a/workspace/bewerbungen.html +++ b/workspace/bewerbungen.html @@ -7,16 +7,16 @@ - - - - - - - - + + + + + + + + - + @@ -80,10 +80,10 @@ - - - - - + + + + + diff --git a/workspace/calls.html b/workspace/calls.html index 522e8ca6..a3ea6c2d 100644 --- a/workspace/calls.html +++ b/workspace/calls.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -89,11 +89,11 @@ - - - - - - + + + + + + diff --git a/workspace/chat.html b/workspace/chat.html index 63b2b17d..521b985d 100644 --- a/workspace/chat.html +++ b/workspace/chat.html @@ -12,26 +12,26 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - - + + + - + @@ -341,15 +341,15 @@ - - - - + + + + - - + + diff --git a/workspace/content.html b/workspace/content.html index 9e9e4c27..56d3163b 100644 --- a/workspace/content.html +++ b/workspace/content.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -179,12 +179,12 @@ - - - - - - - + + + + + + + diff --git a/workspace/crew-index.html b/workspace/crew-index.html index bf035c38..0519b140 100644 --- a/workspace/crew-index.html +++ b/workspace/crew-index.html @@ -36,15 +36,15 @@ - - - + + + - + @@ -339,6 +339,6 @@ - + diff --git a/workspace/crew.webmanifest b/workspace/crew.webmanifest index 1b624ef0..a72aea68 100644 --- a/workspace/crew.webmanifest +++ b/workspace/crew.webmanifest @@ -22,25 +22,25 @@ }, "icons": [ { - "src": "/assets/img/app-symbole/crew-192.png?v=202609182128", + "src": "/assets/img/app-symbole/crew-192.png?v=202609182158", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/crew-512.png?v=202609182128", + "src": "/assets/img/app-symbole/crew-512.png?v=202609182158", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609182128", + "src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609182158", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609182128", + "src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609182158", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/dateien.html b/workspace/dateien.html index 62a00cc6..86370cdf 100644 --- a/workspace/dateien.html +++ b/workspace/dateien.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -108,10 +108,10 @@ - - - - - + + + + + diff --git a/workspace/entwicklung.html b/workspace/entwicklung.html index 6f25af45..2a39c7f3 100644 --- a/workspace/entwicklung.html +++ b/workspace/entwicklung.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -102,9 +102,9 @@ - - - - + + + + diff --git a/workspace/index.html b/workspace/index.html index 5bf28752..6eca90c6 100644 --- a/workspace/index.html +++ b/workspace/index.html @@ -30,9 +30,9 @@ - - - + + + @@ -401,6 +401,6 @@ - + diff --git a/workspace/kalender.html b/workspace/kalender.html index 104639e0..3c4c5025 100644 --- a/workspace/kalender.html +++ b/workspace/kalender.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -377,11 +377,11 @@ - - - - - - + + + + + + diff --git a/workspace/leistung.html b/workspace/leistung.html index ec09e872..264ed914 100644 --- a/workspace/leistung.html +++ b/workspace/leistung.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -444,10 +444,10 @@ - - - - - + + + + + diff --git a/workspace/personen.html b/workspace/personen.html index b16f559e..2ecf4069 100644 --- a/workspace/personen.html +++ b/workspace/personen.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -423,10 +423,10 @@ - - - - - + + + + + diff --git a/workspace/profil.html b/workspace/profil.html index f61eefa8..66e4e8d5 100644 --- a/workspace/profil.html +++ b/workspace/profil.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -214,11 +214,11 @@ - - - - - - + + + + + + diff --git a/workspace/rechte.html b/workspace/rechte.html index 06a6971f..746455d8 100644 --- a/workspace/rechte.html +++ b/workspace/rechte.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -134,9 +134,9 @@ Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen, die seit dem 07.09. jede Seite danach absucht. --> - - - - + + + + diff --git a/workspace/report.html b/workspace/report.html index 1a9f648d..64ee38e8 100644 --- a/workspace/report.html +++ b/workspace/report.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -106,11 +106,11 @@ - - - - - - + + + + + + diff --git a/workspace/scouting.html b/workspace/scouting.html index b2240531..22c9280b 100644 --- a/workspace/scouting.html +++ b/workspace/scouting.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -173,10 +173,10 @@ - - - - - + + + + + diff --git a/workspace/start.html b/workspace/start.html index 1ed37839..0ce05aaa 100644 --- a/workspace/start.html +++ b/workspace/start.html @@ -12,21 +12,21 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - + + - + @@ -674,10 +674,10 @@

- - - - - + + + + + diff --git a/workspace/startcheck.html b/workspace/startcheck.html index 84cce0f7..ca6545cc 100644 --- a/workspace/startcheck.html +++ b/workspace/startcheck.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -85,11 +85,11 @@ - - - - - - + + + + + + diff --git a/workspace/steckbrief.html b/workspace/steckbrief.html index e7d86382..8e88ce3d 100644 --- a/workspace/steckbrief.html +++ b/workspace/steckbrief.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -146,11 +146,11 @@ - - - - - - + + + + + + diff --git a/workspace/talente.html b/workspace/talente.html index aac4dbb5..5c5be815 100644 --- a/workspace/talente.html +++ b/workspace/talente.html @@ -7,18 +7,18 @@ - - - - - - + + + + + + - - - + + + @@ -111,9 +111,9 @@ - - - - + + + + diff --git a/workspace/team.html b/workspace/team.html index ff2dd917..1346924b 100644 --- a/workspace/team.html +++ b/workspace/team.html @@ -7,20 +7,20 @@ - - - - - - - + + + + + + + - + @@ -110,10 +110,10 @@ - - - - - + + + + + diff --git a/workspace/teamlage.html b/workspace/teamlage.html index c032634e..2cedb715 100644 --- a/workspace/teamlage.html +++ b/workspace/teamlage.html @@ -7,20 +7,20 @@ - - - - - - - + + + + + + + - + - - - - + + + + diff --git a/workspace/teilen.html b/workspace/teilen.html index f336b70b..0de47fa9 100644 --- a/workspace/teilen.html +++ b/workspace/teilen.html @@ -7,13 +7,13 @@ - - - - - - - + + + + + + + @@ -112,9 +112,9 @@ - - - - + + + + diff --git a/workspace/treff-moderation.html b/workspace/treff-moderation.html index d47cf9a8..59acf85c 100644 --- a/workspace/treff-moderation.html +++ b/workspace/treff-moderation.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -126,9 +126,9 @@ - - - - + + + + diff --git a/workspace/treff-regeln.html b/workspace/treff-regeln.html index b10c39d6..3278185c 100644 --- a/workspace/treff-regeln.html +++ b/workspace/treff-regeln.html @@ -7,18 +7,18 @@ - - - - - - - + + + + + + + - + @@ -211,10 +211,10 @@ Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen, die seit dem 07.09. jede Seite danach absucht. --> - - - - - + + + + + diff --git a/workspace/uebersicht.html b/workspace/uebersicht.html index 09bce4a2..e0a2fe02 100644 --- a/workspace/uebersicht.html +++ b/workspace/uebersicht.html @@ -12,22 +12,22 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - - + + + - + @@ -149,11 +149,11 @@ - + - - - - + + + + diff --git a/workspace/wissen.html b/workspace/wissen.html index 050cb0a5..7d965c71 100644 --- a/workspace/wissen.html +++ b/workspace/wissen.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -190,10 +190,10 @@ - - - - - + + + + +