Startseite: aus siebzehn gleichen Rechtecken wird eine Uebersicht
Sie war eine Wand: siebzehn identische Kaesten, auf jedem stand "OEFFNEN".
Wenn alles gleich aussieht, ist alles gleich wichtig -- also nichts. Und
"OEFFNEN" ist keine Information; dass eine Kachel sich oeffnen laesst,
weiss man.
Drei Aenderungen, jede mit einem Grund:
1. GRUPPEN statt einer Liste. "Taeglich" (was man sowieso jeden Tag
aufmacht), "Rund um den Creator" (die Betreuungsakte), "Team & System"
(was den Laden am Laufen haelt). Das sind drei verschiedene Absichten.
2. ZAHLEN STATT "OEFFNEN". Auf der Kachel steht jetzt, wo Arbeit liegt --
"Aufgaben 4", rot markiert, weil etwas ueberfaellig ist. Gespeist aus
DERSELBEN Quelle wie die Hinweisliste darueber, kein zweiter Zaehler:
Zwei verschiedene Wahrheiten uebereinander auf einem Bildschirm waeren
schlimmer als gar keine Zahl.
3. ZEICHEN UND FARBE. Siebzehn eigene Linienzeichen (eigene Pfade, keine
Fremdbibliothek -- kleiner als jede Schriftart und keine zusaetzliche
Lieferkette) und acht Farbtoene.
Warum acht Toene und nicht siebzehn: Ich hatte zuerst eine eigene Farbe
je Kachel gebaut und das Ergebnis pruefen lassen. Zwei Paare hatten einen
Abstand von 1.4 und 5.6 -- also praktisch dieselbe Farbe. Das sieht nach
Zufall aus, nicht nach Absicht. Die acht jetzt verwendeten sind gegen
genau diesen Hintergrund gerechnet und bestehen alle Pruefungen
(Helligkeitsband, Farbstaerke, Farbfehlsichtigkeit dE 8.4,
Normalsicht 19.3, Kontrast). Verteilt so, dass in einer Zeile nie
zweimal derselbe Ton steht. Die Farbe stuetzt nur -- WAS eine Kachel
ist, sagen Zeichen und Name.
Dazu:
- Begruessung nach Tageszeit statt immer "Willkommen".
- Sechs Nullen nebeneinander sind Rauschen: Ist wirklich nichts offen,
steht dort ein Satz und der Platz gehoert den Bereichen.
- Die Hinweisliste stand mit sieben Zeilen im Weg. Jetzt vier sichtbar,
Rest auf Knopfdruck -- derselbe Helfer wie im Protokoll und im Verlauf.
- Gestaffelter Einlauf, aber in einer no-preference-Abfrage: Bei
"weniger Bewegung" entsteht gar keine Animation, nicht nur eine ohne
Dauer. Geprueft mit reducedMotion.
Beim Ansehen des ersten Bildes fielen abgeschnittene Untertitel auf
("Stammdaten, Ziele, 90-..."). Abgeschnittener Text ist der haeufigste
stille Fehler in einer Kachel, weil er nach Absicht aussieht. Texte
gekuerzt -- und der Test misst jetzt die tatsaechliche Textbreite gegen
die verfuegbare, damit es nicht wiederkommt.
40 Pruefungen, Computer und Handy, alle vier Rollen: Ein Creator sieht
"Mein Profil" statt der Liste aller Creator, keine Personenverwaltung,
keine Pipeline, keine Automationen -- und trotzdem drei saubere Gruppen.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 449 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 408 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 383 KiB |
@@ -0,0 +1,212 @@
|
||||
/* Browserpruefung der Startseite: Gruppen, Zeichen, Farbtoene, Zahlen auf
|
||||
den Kacheln -- und was jede Rolle davon zu sehen bekommt. */
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
|
||||
const ordner = mkdtempSync(join(tmpdir(), "ws-start-"));
|
||||
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
|
||||
process.env.PORT = "4186";
|
||||
process.env.SITE_ACCESS_SECRET = "lokaler-test";
|
||||
process.env.SITE_ACCESS_CODE_DOGI = "DOGI-TEST-1";
|
||||
process.env.SITE_ACCESS_CODE_VANVAN = "VANVAN-TEST-1";
|
||||
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, 700));
|
||||
const BASIS = "http://127.0.0.1:4186";
|
||||
setTimeout(() => { console.log("ABBRUCH"); process.exit(1); }, 200_000).unref?.();
|
||||
|
||||
let fehler = 0;
|
||||
const ok = (b, t) => { console.log((b ? " ok " : " FEHL ") + t); if (!b) fehler++; };
|
||||
|
||||
await fetch(BASIS + "/workspace/api/anmelden", {
|
||||
method: "POST", headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ rolle: "admin", code: "x" }) }).catch(() => {});
|
||||
|
||||
const { DatabaseSync } = await import("node:sqlite");
|
||||
const { scryptSync, randomBytes } = await import("node:crypto");
|
||||
const d = new DatabaseSync(process.env.WORKSPACE_DB);
|
||||
const jetzt = new Date().toISOString();
|
||||
const heute = jetzt.slice(0, 10);
|
||||
const gestern = new Date(Date.now() - 86400_000).toISOString().slice(0, 10);
|
||||
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, jetzt);
|
||||
return d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
||||
}
|
||||
const idDogi = anlegen("Filipe", "admin", "CODE-DOGI-0001");
|
||||
const idScout = anlegen("Patrick", "scout", "CODE-SCOU-0001");
|
||||
const idAnna = anlegen("Tili", "creator", "CODE-ANNA-0001");
|
||||
d.prepare("INSERT INTO betreuung (creator_id, betreuer_id, seit) VALUES (?,?,?)").run(idAnna, idScout, jetzt);
|
||||
|
||||
/* Arbeit an mehreren Stellen -- damit auf den Kacheln wirklich Zahlen
|
||||
stehen und man sieht, ob sie an der richtigen landen. */
|
||||
for (const [status, frist] of [["offen", gestern], ["offen", gestern], ["offen", heute],
|
||||
["arbeit", null], ["review", null]]) {
|
||||
d.prepare("INSERT INTO aufgaben (titel, status, creator_id, frist, erstellt, erstellt_von) VALUES ('Test',?,?,?,?,?)")
|
||||
.run(status, idAnna, frist, jetzt, idDogi);
|
||||
}
|
||||
d.prepare("INSERT INTO termine (titel, beginn, creator_id, erledigt, erstellt, erstellt_von) VALUES ('Heute',?,?,0,?,?)")
|
||||
.run(heute + "T18:00", idAnna, jetzt, idDogi);
|
||||
d.prepare("INSERT INTO eintraege (bereich, art, titel, datum, dringlichkeit, status, creator_id, erstellt, erstellt_von) VALUES ('technik','problem','Ton weg',?,'hoch','offen',?,?,?)")
|
||||
.run(heute, idAnna, jetzt, idDogi);
|
||||
d.close();
|
||||
|
||||
const { chromium } = await import(
|
||||
"file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs");
|
||||
const browser = await chromium.launch();
|
||||
|
||||
async function anmelden(kontext, rolle, code) {
|
||||
const seite = await kontext.newPage();
|
||||
await seite.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" });
|
||||
await seite.click(`.rolle[data-rolle="${rolle}"]`);
|
||||
await seite.fill("#code", code);
|
||||
await seite.click("button[type=submit]");
|
||||
await seite.waitForURL("**/start.html", { timeout: 15000 });
|
||||
await seite.waitForTimeout(900);
|
||||
return seite;
|
||||
}
|
||||
|
||||
const lesen = (seite) => seite.evaluate(() => ({
|
||||
gruss: document.getElementById("gruss")?.textContent,
|
||||
gruppen: [...document.querySelectorAll(".gruppe")].map((g) => ({
|
||||
name: g.querySelector(".gruppe__name")?.textContent,
|
||||
kacheln: g.querySelectorAll(".kachel").length,
|
||||
})),
|
||||
kacheln: [...document.querySelectorAll(".kachel")].map((k) => ({
|
||||
name: k.querySelector(".kachel__name")?.textContent,
|
||||
unter: k.querySelector(".kachel__unter")?.textContent,
|
||||
ton: k.dataset.ton,
|
||||
farbe: getComputedStyle(k.querySelector(".kachel__svg")).stroke,
|
||||
pfade: k.querySelectorAll(".kachel__svg path").length,
|
||||
zahl: k.querySelector(".kachel__zahl")?.textContent || null,
|
||||
warn: k.querySelector(".kachel__zahl")?.dataset.warn === "ja",
|
||||
ziel: k.querySelector(".kachel__link")?.getAttribute("href"),
|
||||
})),
|
||||
/* Abgeschnittener Text ist der haeufigste stille Fehler in einer
|
||||
Kachel -- er sieht auf den ersten Blick nach Absicht aus. Gemessen
|
||||
wird die tatsaechliche Textbreite gegen die verfuegbare. */
|
||||
abgeschnitten: [...document.querySelectorAll(".kachel__name, .kachel__unter")]
|
||||
.filter((e) => e.scrollWidth > e.clientWidth + 1)
|
||||
.map((e) => e.textContent),
|
||||
hinweise: [...document.querySelectorAll("#dran .dran__punkt")]
|
||||
.filter((z) => z.offsetParent !== null).length,
|
||||
hinweiseGesamt: document.querySelectorAll("#dran .dran__punkt").length,
|
||||
zahlenLeer: !document.getElementById("zahlen-leer")?.hidden,
|
||||
zahlen: [...document.querySelectorAll(".zahl")].length,
|
||||
ueber: document.documentElement.scrollWidth - document.documentElement.clientWidth,
|
||||
ueberstehend: [...document.querySelectorAll("main *")]
|
||||
.filter((e) => e.getBoundingClientRect().right > window.innerWidth + 1)
|
||||
.map((e) => String(e.className).slice(0, 40)).slice(0, 4),
|
||||
}));
|
||||
|
||||
for (const [breite, wie] of [[1440, "Computer"], [390, "Handy"]]) {
|
||||
console.log(`\n=== DogFather · ${wie}`);
|
||||
const kontext = await browser.newContext({ viewport: { width: breite, height: 1200 } });
|
||||
const konsole = [];
|
||||
const seite = await anmelden(kontext, "admin", "CODE-DOGI-0001");
|
||||
seite.on("console", (m) => { if (m.type() === "error") konsole.push(m.text()); });
|
||||
seite.on("pageerror", (e) => konsole.push("pageerror: " + e.message));
|
||||
await seite.reload({ waitUntil: "networkidle" });
|
||||
await seite.waitForTimeout(900);
|
||||
|
||||
const r = await lesen(seite);
|
||||
console.log(" Gruß: ", r.gruss);
|
||||
console.log(" Gruppen:", r.gruppen.map((g) => `${g.name} (${g.kacheln})`).join(" · "));
|
||||
console.log(" Zahlen: ", r.kacheln.filter((k) => k.zahl).map((k) => `${k.name}=${k.zahl}${k.warn ? "!" : ""}`).join(" · "));
|
||||
|
||||
ok(r.gruppen.length === 3, `drei Gruppen (${r.gruppen.length})`);
|
||||
ok(r.kacheln.length === 17, `siebzehn Kacheln (${r.kacheln.length})`);
|
||||
ok(/^(Guten Morgen|Guten Tag|Guten Abend|Noch wach), Filipe$/.test(r.gruss || ""),
|
||||
`Begrüßung nach Tageszeit ("${r.gruss}")`);
|
||||
|
||||
/* Jede Kachel muss ein Zeichen haben -- eine ohne waere ein leeres
|
||||
Kaestchen und faellt sofort auf. */
|
||||
ok(r.kacheln.every((k) => k.pfade > 0),
|
||||
`jede Kachel hat ein Zeichen (${r.kacheln.filter((k) => !k.pfade).map((k) => k.name).join(", ") || "alle"})`);
|
||||
ok(r.kacheln.every((k) => k.unter && k.unter.length > 4), "jede Kachel sagt, was drin ist");
|
||||
ok(r.kacheln.every((k) => k.ziel && k.ziel !== "#"), "jede Kachel führt irgendwohin");
|
||||
|
||||
/* Acht verschiedene Farben, und nirgends steht "ÖFFNEN" mehr. */
|
||||
const toene = new Set(r.kacheln.map((k) => k.farbe));
|
||||
ok(toene.size === 8, `acht verschiedene Farbtöne im Einsatz (${toene.size})`);
|
||||
const oeffnen = await seite.evaluate(() => document.body.textContent.includes("ÖFFNEN"));
|
||||
ok(!oeffnen, "das Wort ÖFFNEN kommt nicht mehr vor");
|
||||
|
||||
/* Die Zahlen müssen auf der RICHTIGEN Kachel stehen. */
|
||||
const auf = (n) => r.kacheln.find((k) => k.name === n);
|
||||
ok(auf("Aufgaben")?.zahl === "4",
|
||||
`Aufgaben trägt 4 (2 überfällig + 1 heute + 1 Review) (${auf("Aufgaben")?.zahl})`);
|
||||
ok(auf("Aufgaben")?.warn === true, "und ist als Warnung markiert");
|
||||
ok(auf("Kalender")?.zahl === "1", `Kalender trägt 1 (${auf("Kalender")?.zahl})`);
|
||||
ok(auf("LIVE-Analyse")?.zahl === "1", `der dringende Bereichspunkt (${auf("LIVE-Analyse")?.zahl})`);
|
||||
ok(!auf("Wissens-Bibliothek")?.zahl, "wo nichts liegt, steht keine Zahl");
|
||||
|
||||
ok(r.abgeschnitten.length === 0,
|
||||
`kein Text wird abgeschnitten (${r.abgeschnitten.join(" | ") || "keiner"})`);
|
||||
ok(r.hinweise <= 4, `höchstens vier Hinweise sichtbar (${r.hinweise} von ${r.hinweiseGesamt})`);
|
||||
ok(r.zahlen === 6, `die Aufgabenzahlen stehen (${r.zahlen})`);
|
||||
ok(!r.zahlenLeer, "und nicht der Leer-Satz");
|
||||
ok(r.ueber <= 0, `nichts steht über (${r.ueber}px, ${r.ueberstehend.join(", ")})`);
|
||||
ok(konsole.length === 0, `keine Fehler in der Konsole${konsole.length ? " -> " + konsole.join(" | ") : ""}`);
|
||||
|
||||
await seite.screenshot({ path: breite === 1440 ? "pruef-start-computer.png" : "pruef-start-handy.png", fullPage: true });
|
||||
await kontext.close();
|
||||
}
|
||||
|
||||
console.log("\n=== Creator");
|
||||
{
|
||||
const kontext = await browser.newContext({ viewport: { width: 1440, height: 1200 } });
|
||||
const seite = await anmelden(kontext, "creator", "CODE-ANNA-0001");
|
||||
const r = await lesen(seite);
|
||||
console.log(" Gruppen:", r.gruppen.map((g) => `${g.name} (${g.kacheln})`).join(" · "));
|
||||
const namen = r.kacheln.map((k) => k.name);
|
||||
ok(namen.includes("Mein Profil"), "sieht sein eigenes Profil");
|
||||
ok(!namen.includes("Creator-Profile"), "und nicht die Liste aller Creator");
|
||||
ok(!namen.includes("Personen & Zugänge"), "keine Personenverwaltung");
|
||||
ok(!namen.includes("Scout-Pipeline"), "keine Scout-Pipeline");
|
||||
ok(!namen.includes("Automationen"), "keine Automationen");
|
||||
ok(r.gruppen.length === 3, `trotzdem drei Gruppen (${r.gruppen.length})`);
|
||||
ok(r.kacheln.every((k) => k.pfade > 0), "alle Zeichen da");
|
||||
await seite.screenshot({ path: "pruef-start-creator.png", fullPage: true });
|
||||
await kontext.close();
|
||||
}
|
||||
|
||||
console.log("\n=== Scout");
|
||||
{
|
||||
const kontext = await browser.newContext({ viewport: { width: 1440, height: 1200 } });
|
||||
const seite = await anmelden(kontext, "scout", "CODE-SCOU-0001");
|
||||
const r = await lesen(seite);
|
||||
const namen = r.kacheln.map((k) => k.name);
|
||||
ok(namen.includes("Scout-Pipeline"), "sieht seine Pipeline");
|
||||
ok(!namen.includes("Personen & Zugänge"), "keine Personenverwaltung");
|
||||
ok(!namen.includes("Automationen"), "keine Automationen");
|
||||
ok(namen.includes("Creator-Profile"), "aber die Creator-Profile");
|
||||
await kontext.close();
|
||||
}
|
||||
|
||||
console.log("\n=== Weniger Bewegung: keine Animation");
|
||||
{
|
||||
const kontext = await browser.newContext({
|
||||
viewport: { width: 1440, height: 1000 }, reducedMotion: "reduce" });
|
||||
const seite = await anmelden(kontext, "admin", "CODE-DOGI-0001");
|
||||
const bewegung = await seite.evaluate(() => {
|
||||
const k = document.querySelector(".kachel");
|
||||
const s = getComputedStyle(k);
|
||||
return { animation: s.animationName, sichtbar: s.opacity };
|
||||
});
|
||||
ok(bewegung.animation === "none", `keine Animation (${bewegung.animation})`);
|
||||
ok(Number(bewegung.sichtbar) === 1, `und trotzdem voll sichtbar (${bewegung.sichtbar})`);
|
||||
await kontext.close();
|
||||
}
|
||||
|
||||
await browser.close();
|
||||
console.log(`\n${fehler === 0 ? "Alles in Ordnung." : fehler + " Prüfung(en) fehlgeschlagen."}`);
|
||||
try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ }
|
||||
process.exit(fehler === 0 ? 0 : 1);
|
||||
+186
-32
@@ -214,52 +214,206 @@ body.start {
|
||||
.zahl[data-warn="ja"] { border-color: rgba(255, 154, 162, .42); background: rgba(255, 154, 162, .07); }
|
||||
.zahl[data-warn="ja"] .zahl__wert { color: var(--warn); }
|
||||
|
||||
/* ---------- Bereiche --------------------------------------------------- */
|
||||
/* ---------- Bereiche: Gruppen und Kacheln --------------------------------
|
||||
|
||||
.bereiche {
|
||||
Vorher: siebzehn gleiche Rechtecke mit "ÖFFNEN" darauf. Wenn alles
|
||||
gleich aussieht, ist alles gleich wichtig -- also nichts.
|
||||
|
||||
Drei Dinge tragen jetzt die Gestaltung:
|
||||
|
||||
1. Die Kachel ist ruhig, bis man sie ansieht. Der Farbton sitzt im
|
||||
Zeichen und in einer schmalen Kante -- nicht als Fläche. Siebzehn
|
||||
farbige Flächen wären ein Bonbonglas, kein Werkzeug.
|
||||
|
||||
2. Beim Überfahren geht ein sehr weicher Schimmer aus der oberen
|
||||
linken Ecke an. Kein Blitzen, kein Springen: Alphawerte unter 0.25,
|
||||
Bewegung unter einem Pixel.
|
||||
|
||||
3. Der Einlauf ist gestaffelt -- genau EINE Bewegung beim Aufbau,
|
||||
danach Ruhe. Bei "weniger Bewegung" fällt sie ersatzlos weg.
|
||||
|
||||
Die acht Farbtöne sind gegen genau diesen Hintergrund gerechnet:
|
||||
Helligkeitsband, Farbstärke, Abstand bei Farbfehlsichtigkeit
|
||||
(schlechtestes Paar dE 8.4), Normalsicht-Abstand (19.3) und Kontrast
|
||||
-- alle Prüfungen bestanden. Warum acht und nicht siebzehn: Siebzehn
|
||||
unterscheidbare Farben gibt es nicht; ein Versuch mit einer eigenen
|
||||
Farbe je Kachel ergab Paare mit Abstand 1.4, also praktisch dieselbe
|
||||
Farbe. Sie stützen nur -- WAS eine Kachel ist, sagen Zeichen und Name.
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
.gruppe { margin-bottom: 34px; }
|
||||
.gruppe:last-child { margin-bottom: 0; }
|
||||
|
||||
.gruppe__kopf {
|
||||
display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
|
||||
margin-bottom: 12px; padding-bottom: 9px;
|
||||
border-bottom: 1px solid var(--rand);
|
||||
}
|
||||
.gruppe__name {
|
||||
margin: 0; font-size: .76rem; font-weight: 700;
|
||||
letter-spacing: .1em; text-transform: uppercase; color: var(--text-leise);
|
||||
}
|
||||
.gruppe__unter { font-size: .78rem; color: var(--text-still); }
|
||||
|
||||
.kacheln {
|
||||
list-style: none; margin: 0; padding: 0;
|
||||
display: grid; gap: 10px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(238px, 1fr));
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.bereich {
|
||||
display: flex; align-items: baseline; gap: 10px;
|
||||
padding: 13px 15px;
|
||||
background: rgba(255, 255, 255, .03);
|
||||
/* Die acht geprüften Töne. Zugewiesen wird der PLATZ, nicht der Rang --
|
||||
so behält ein Bereich seine Farbe, auch wenn andere dazukommen. */
|
||||
.kachel[data-ton="1"] { --ton: #3987e5; }
|
||||
.kachel[data-ton="2"] { --ton: #d95926; }
|
||||
.kachel[data-ton="3"] { --ton: #199e70; }
|
||||
.kachel[data-ton="4"] { --ton: #c98500; }
|
||||
.kachel[data-ton="5"] { --ton: #d55181; }
|
||||
.kachel[data-ton="6"] { --ton: #4d9e4d; }
|
||||
.kachel[data-ton="7"] { --ton: #9085e9; }
|
||||
.kachel[data-ton="8"] { --ton: #e66767; }
|
||||
|
||||
.kachel {
|
||||
--ton: var(--akzent);
|
||||
position: relative;
|
||||
border-radius: 15px;
|
||||
background:
|
||||
linear-gradient(155deg,
|
||||
color-mix(in srgb, var(--ton) 9%, transparent),
|
||||
rgba(255, 255, 255, .022) 45%);
|
||||
border: 1px solid var(--rand);
|
||||
border-radius: var(--radius-klein);
|
||||
overflow: hidden;
|
||||
transition: border-color var(--tempo), transform var(--tempo);
|
||||
}
|
||||
.kachel[data-gross="ja"] { grid-column: span 2; }
|
||||
|
||||
/* Die farbige Kante links. Sie ist das Einzige, was den Ton kräftig
|
||||
zeigt -- drei Pixel reichen, um eine Kachel wiederzuerkennen. */
|
||||
.kachel::before {
|
||||
content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
|
||||
background: linear-gradient(180deg, var(--ton), transparent 90%);
|
||||
opacity: .5;
|
||||
transition: opacity var(--tempo);
|
||||
}
|
||||
|
||||
.bereich__name { font-weight: 600; font-size: .95rem; }
|
||||
|
||||
.bereich__stand {
|
||||
margin-left: auto;
|
||||
font-size: .72rem; letter-spacing: .04em; text-transform: uppercase;
|
||||
color: var(--text-still);
|
||||
white-space: nowrap;
|
||||
/* Der Schimmer beim Überfahren. Liegt still auf 0 und wird nur
|
||||
eingeblendet -- nichts bewegt sich, es wird nur heller. */
|
||||
.kachel::after {
|
||||
content: ""; position: absolute; inset: 0; pointer-events: none;
|
||||
background: radial-gradient(120% 130% at 0% 0%,
|
||||
color-mix(in srgb, var(--ton) 16%, transparent), transparent 62%);
|
||||
opacity: 0;
|
||||
transition: opacity var(--tempo);
|
||||
}
|
||||
|
||||
/* Phase 1 ist in Arbeit - das wird hervorgehoben, der Rest bleibt ruhig. */
|
||||
.bereich[data-phase="1"] { border-color: rgba(63, 189, 245, .34); }
|
||||
.bereich[data-phase="1"] .bereich__stand { color: var(--akzent); }
|
||||
|
||||
/* Fertige Bereiche sind anklickbar und heben sich deutlich ab. */
|
||||
.bereich[data-fertig="ja"] {
|
||||
padding: 0;
|
||||
border-color: rgba(63, 189, 245, .5);
|
||||
background: linear-gradient(100deg, rgba(63, 189, 245, .10), rgba(138, 118, 255, .07));
|
||||
transition: border-color var(--tempo), background var(--tempo);
|
||||
.kachel:hover {
|
||||
border-color: color-mix(in srgb, var(--ton) 42%, var(--rand));
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.bereich[data-fertig="ja"]:hover { border-color: rgba(63, 189, 245, .8); }
|
||||
.kachel:hover::before { opacity: 1; }
|
||||
.kachel:hover::after { opacity: 1; }
|
||||
.kachel:has(:focus-visible) { border-color: var(--ton); }
|
||||
|
||||
.bereich__link {
|
||||
display: flex; align-items: baseline; gap: 10px; width: 100%;
|
||||
padding: 13px 15px;
|
||||
.kachel__link {
|
||||
position: relative; z-index: 1;
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
padding: 14px 15px 14px 17px;
|
||||
color: inherit; text-decoration: none;
|
||||
border-radius: var(--radius-klein);
|
||||
}
|
||||
.bereich__link:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
|
||||
.bereich[data-fertig="ja"] .bereich__stand { color: var(--akzent); font-weight: 600; }
|
||||
.kachel__link:focus-visible {
|
||||
outline: 2px solid var(--ton); outline-offset: -3px; border-radius: 13px;
|
||||
}
|
||||
|
||||
/* Das Zeichen sitzt in einem eigenen kleinen Feld -- dadurch bekommt der
|
||||
Ton eine Fläche, ohne dass die ganze Kachel farbig wird. */
|
||||
.kachel__zeichen {
|
||||
flex: none;
|
||||
display: grid; place-items: center;
|
||||
width: 38px; height: 38px; border-radius: 11px;
|
||||
background: color-mix(in srgb, var(--ton) 14%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--ton) 28%, transparent);
|
||||
transition: background var(--tempo), border-color var(--tempo);
|
||||
}
|
||||
.kachel:hover .kachel__zeichen {
|
||||
background: color-mix(in srgb, var(--ton) 24%, transparent);
|
||||
border-color: color-mix(in srgb, var(--ton) 52%, transparent);
|
||||
}
|
||||
.kachel[data-gross="ja"] .kachel__zeichen { width: 44px; height: 44px; border-radius: 13px; }
|
||||
|
||||
.kachel__svg {
|
||||
width: 20px; height: 20px;
|
||||
fill: none; stroke: var(--ton);
|
||||
stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
|
||||
}
|
||||
.kachel[data-gross="ja"] .kachel__svg { width: 23px; height: 23px; }
|
||||
|
||||
.kachel__text { display: grid; gap: 1px; min-width: 0; }
|
||||
.kachel__name {
|
||||
font-size: .93rem; font-weight: 650; letter-spacing: -.005em;
|
||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||
}
|
||||
.kachel[data-gross="ja"] .kachel__name { font-size: 1.02rem; }
|
||||
.kachel__unter {
|
||||
font-size: .74rem; color: var(--text-still);
|
||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Die Zahl auf der Kachel. Sie ersetzt den Pfeil, wenn dort Arbeit
|
||||
liegt -- eine Kachel, die "3" sagt, ist zehnmal mehr wert als eine,
|
||||
die "öffnen" sagt. */
|
||||
.kachel__zahl {
|
||||
flex: none; margin-left: auto;
|
||||
min-width: 26px; padding: 3px 9px;
|
||||
text-align: center; font-size: .82rem; font-weight: 700;
|
||||
font-variant-numeric: tabular-nums;
|
||||
color: var(--ton);
|
||||
background: color-mix(in srgb, var(--ton) 14%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--ton) 34%, transparent);
|
||||
border-radius: 999px;
|
||||
}
|
||||
.kachel__zahl[data-warn="ja"] {
|
||||
color: var(--warn);
|
||||
background: rgba(255, 154, 162, .12);
|
||||
border-color: rgba(255, 154, 162, .42);
|
||||
}
|
||||
|
||||
.kachel__pfeil {
|
||||
flex: none; margin-left: auto;
|
||||
color: var(--text-still); font-size: .9rem;
|
||||
transition: color var(--tempo), transform var(--tempo);
|
||||
}
|
||||
.kachel:hover .kachel__pfeil { color: var(--ton); transform: translateX(3px); }
|
||||
|
||||
/* Gestaffelter Einlauf. Die Verzögerung kommt aus --nr, das start.js je
|
||||
Kachel setzt. Steht in einer no-preference-Abfrage, damit bei
|
||||
"weniger Bewegung" gar keine Animation entsteht -- nicht nur eine
|
||||
ohne Dauer. */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.kachel {
|
||||
animation: kachel-ein .38s cubic-bezier(.32, 0, .2, 1) backwards;
|
||||
animation-delay: calc(var(--nr, 0) * 26ms);
|
||||
}
|
||||
@keyframes kachel-ein {
|
||||
from { opacity: 0; transform: translateY(6px); }
|
||||
to { opacity: 1; transform: none; }
|
||||
}
|
||||
}
|
||||
|
||||
.zahlen-leer {
|
||||
margin: 0; padding: 15px 17px;
|
||||
font-size: .88rem; color: var(--text-still);
|
||||
border: 1px dashed var(--rand); border-radius: var(--radius-klein);
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.kacheln { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
.kachel[data-gross="ja"] { grid-column: span 2; }
|
||||
}
|
||||
@media (max-width: 560px) {
|
||||
.kacheln { grid-template-columns: 1fr; }
|
||||
.kachel[data-gross="ja"] { grid-column: span 1; }
|
||||
.gruppe__kopf { gap: 4px; }
|
||||
.gruppe__unter { flex-basis: 100%; }
|
||||
}
|
||||
|
||||
.inhalt .fuss { margin-top: 40px; text-align: left; }
|
||||
|
||||
|
||||
+283
-89
@@ -1,7 +1,27 @@
|
||||
/* ===================================================================
|
||||
Startseite nach dem Anmelden.
|
||||
|
||||
Sie war eine Wand aus siebzehn gleichen Rechtecken, auf denen jeweils
|
||||
"ÖFFNEN" stand. Wenn alles gleich aussieht, ist alles gleich wichtig
|
||||
-- also nichts. Und "ÖFFNEN" ist keine Information, das weiss man von
|
||||
einer Kachel ohnehin.
|
||||
|
||||
Drei Dinge machen daraus etwas Brauchbares:
|
||||
|
||||
1. GRUPPEN. Was man täglich braucht, was zu einem Creator gehört, was
|
||||
den Laden am Laufen hält -- das sind drei verschiedene Absichten
|
||||
und nicht eine Liste.
|
||||
|
||||
2. ZAHLEN STATT "ÖFFNEN". Auf der Kachel steht, wo Arbeit liegt.
|
||||
Dieselben Quellen wie die Hinweise darüber, kein zweiter Zähler.
|
||||
Eine Kachel, die "3" sagt, ist zehnmal mehr wert als eine, die
|
||||
"öffnen" sagt.
|
||||
|
||||
3. ZEICHEN UND FARBE. Ein eigenes Zeichen je Bereich und ein eigener
|
||||
Farbton -- man findet sie nach kurzer Zeit blind.
|
||||
|
||||
Die Seite ist bereits serverseitig geschützt (workspace.js). Dieses
|
||||
Skript holt nur noch, WER angemeldet ist, und regelt das Abmelden.
|
||||
Skript holt nur noch, WER angemeldet ist.
|
||||
=================================================================== */
|
||||
(() => {
|
||||
'use strict';
|
||||
@@ -13,41 +33,235 @@
|
||||
scout: 'Scout · deine Pipeline und die Creator, die du betreust',
|
||||
};
|
||||
|
||||
/* Bereiche aus dem Konzept, mit der Phase aus dem Umsetzungsplan.
|
||||
`rollen` steuert, wem ein Bereich überhaupt angezeigt wird - schon
|
||||
jetzt, damit die Trennung von Anfang an sichtbar ist.
|
||||
/* ---------- Zeichen ------------------------------------------------------
|
||||
|
||||
"Dashboard" führte lange nirgendwohin -- man stand ja schon auf
|
||||
dieser Seite. Statt die Kachel zu streichen, hat sie jetzt ein
|
||||
Ziel: die Gesamtübersicht je Creator, die das Konzept auf Seite 1
|
||||
als "ÜBERSICHT -- alles zentral" verspricht und die es bisher
|
||||
nirgends gab. Diese Seite hier ist der Einstieg, die andere der
|
||||
Überblick. */
|
||||
const BEREICHE = [
|
||||
{ name: 'Dashboard', phase: 1, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'uebersicht.html' },
|
||||
{ name: 'Personen & Zugänge', phase: 1, rollen: ['admin', 'manager'], ziel: 'personen.html' },
|
||||
{ name: 'Creator-Profile', phase: 1, rollen: ['admin', 'manager', 'scout'], ziel: 'profil.html' },
|
||||
{ name: 'Mein Profil', phase: 1, rollen: ['creator'], ziel: 'profil.html' },
|
||||
{ name: 'Start-Check', phase: 1, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'startcheck.html' },
|
||||
{ name: 'Wissens-Bibliothek', phase: 1, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'wissen.html' },
|
||||
{ name: 'Aufgaben', phase: 1, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'aufgaben.html' },
|
||||
{ name: 'Kalender', phase: 1, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'kalender.html' },
|
||||
{ name: 'Dateien', phase: 1, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'dateien.html' },
|
||||
{ name: 'LIVE-Analyse', phase: 2, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'bereich.html?b=live' },
|
||||
{ name: 'Content-Planung', phase: 2, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'content.html' },
|
||||
{ name: 'Technik', phase: 2, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'bereich.html?b=technik' },
|
||||
{ name: 'Community', phase: 2, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'bereich.html?b=community' },
|
||||
{ name: 'Schutz & Regeln', phase: 2, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'bereich.html?b=schutz' },
|
||||
{ name: 'Reports & Review', phase: 2, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'report.html' },
|
||||
{ name: 'Calls & Protokolle', phase: 3, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'calls.html' },
|
||||
{ name: 'Scout-Pipeline', phase: 3, rollen: ['admin', 'manager', 'scout'], ziel: 'scouting.html' },
|
||||
{ name: 'Automationen', phase: 4, rollen: ['admin', 'manager'], ziel: 'automation.html' },
|
||||
Alle im selben Raster (24×24), alle nur aus Linien -- gefüllte Zeichen
|
||||
wirken neben Text wie Flecken. Eigene statt einer Fremdbibliothek:
|
||||
siebzehn Pfade sind kleiner als jede Schriftart und kosten keine
|
||||
zusätzliche Lieferkette. */
|
||||
|
||||
const ZEICHEN = {
|
||||
dashboard: ['M4.5 4.5h6v6h-6z', 'M13.5 4.5h6v4h-6z', 'M13.5 11.5h6v8h-6z', 'M4.5 13.5h6v6h-6z'],
|
||||
aufgaben: ['M4.5 5h4v14h-4z', 'M10 5h4v9h-4z', 'M15.5 5h4v11.5h-4z'],
|
||||
kalender: ['M4 6.5h16v13H4z', 'M4 10.5h16', 'M8.5 3.5v4', 'M15.5 3.5v4'],
|
||||
calls: ['M3.5 7h11v10h-11z', 'M14.5 11l6-3.5v9l-6-3.5z'],
|
||||
dateien: ['M3.5 6.5h5.5l2 2h9.5v11h-17z'],
|
||||
profil: ['M12 7a3.2 3.2 0 1 0 0 6.4A3.2 3.2 0 0 0 12 7z',
|
||||
'M5.5 20c.7-3.3 3.3-5.3 6.5-5.3s5.8 2 6.5 5.3'],
|
||||
startcheck: ['M6 4.5h12v15H6z', 'M9.2 9.6l1.7 1.7 3.6-3.7', 'M9.2 15.2h5.6'],
|
||||
live: ['M12 10.2a1.8 1.8 0 1 0 0 3.6 1.8 1.8 0 0 0 0-3.6z',
|
||||
'M8.2 8.2a5.4 5.4 0 0 0 0 7.6', 'M15.8 15.8a5.4 5.4 0 0 0 0-7.6',
|
||||
'M5.4 5.4a9.4 9.4 0 0 0 0 13.2', 'M18.6 18.6a9.4 9.4 0 0 0 0-13.2'],
|
||||
content: ['M3.5 6h17v13h-17z', 'M3.5 10h17', 'M8 6l-1.4 4', 'M13 6l-1.4 4', 'M18 6l-1.4 4'],
|
||||
technik: ['M4 7.5h16', 'M4 12h16', 'M4 16.5h16',
|
||||
'M9 7.5a1.4 1.4 0 1 0 0-.02z', 'M15 12a1.4 1.4 0 1 0 0-.02z',
|
||||
'M7.5 16.5a1.4 1.4 0 1 0 0-.02z'],
|
||||
community: ['M9 8.6a2.7 2.7 0 1 0 0 5.4 2.7 2.7 0 0 0 0-5.4z',
|
||||
'M3.5 19.5c.6-2.8 2.8-4.5 5.5-4.5s4.9 1.7 5.5 4.5',
|
||||
'M16 8.8a2.4 2.4 0 1 1 1.6 4.3', 'M17 15.2c2 .5 3.3 2 3.7 4.3'],
|
||||
schutz: ['M12 3.6 5.6 6.3v5.1c0 3.8 2.6 7.2 6.4 8.4 3.8-1.2 6.4-4.6 6.4-8.4V6.3z',
|
||||
'M9.4 11.8l1.9 1.9 3.4-3.6'],
|
||||
reports: ['M4 19.5h16', 'M7.5 16.5V9.5', 'M12 16.5V5.5', 'M16.5 16.5v-5'],
|
||||
personen: ['M14.4 6.2a4 4 0 1 0 0 8 4 4 0 0 0 0-8z', 'M11.6 12.2 4 19.8',
|
||||
'M6.4 17.4l2 2', 'M8.6 15.2l2 2'],
|
||||
scouting: ['M3.5 5.5h17l-6.6 7.6v6.4l-3.8-2.1v-4.3z'],
|
||||
wissen: ['M4 5h6.4c.9 0 1.6.7 1.6 1.6V19c0-.9-.7-1.6-1.6-1.6H4z',
|
||||
'M20 5h-6.4c-.9 0-1.6.7-1.6 1.6V19c0-.9.7-1.6 1.6-1.6H20z'],
|
||||
automation: ['M13.2 3.2 6 13.4h5.2l-.8 7.4 7.6-10.6h-5.2z'],
|
||||
};
|
||||
|
||||
/* ---------- Die Bereiche -------------------------------------------------
|
||||
|
||||
`rollen` steuert, wem ein Bereich überhaupt erscheint -- serverseitig
|
||||
wird es ohnehin noch einmal geprüft, das hier ist nur Höflichkeit.
|
||||
|
||||
`ton` ist der Farbplatz 1..8. Warum acht und nicht siebzehn: Siebzehn
|
||||
unterscheidbare Farben gibt es nicht. Ein erster Versuch mit einer
|
||||
eigenen Farbe je Kachel ergab Paare mit einem Abstand von 1.4 -- also
|
||||
praktisch dieselbe Farbe, und das sieht nach Zufall aus statt nach
|
||||
Absicht. Diese acht sind gegen genau diesen Hintergrund geprüft
|
||||
(Helligkeit, Farbstärke, Farbfehlsichtigkeit, Kontrast, alles
|
||||
bestanden) und so verteilt, dass in einer Zeile nie zweimal derselbe
|
||||
Ton steht. Die Farbe stützt nur -- was die Kachel IST, sagen Zeichen
|
||||
und Name. */
|
||||
|
||||
const GRUPPEN = [
|
||||
{
|
||||
name: 'Täglich',
|
||||
unter: 'Was du sowieso jeden Tag aufmachst',
|
||||
bereiche: [
|
||||
{ name: 'Dashboard', unter: 'Alle Creator auf einen Blick', zeichen: 'dashboard', ton: 1,
|
||||
gross: true, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'uebersicht.html' },
|
||||
{ name: 'Aufgaben', unter: 'Offen, in Arbeit, Review', zeichen: 'aufgaben', ton: 7,
|
||||
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'aufgaben.html' },
|
||||
{ name: 'Kalender', unter: 'Termine und Calls', zeichen: 'kalender', ton: 3,
|
||||
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'kalender.html' },
|
||||
{ name: 'Calls & Protokolle', unter: 'Gespräche mit To-dos', zeichen: 'calls', ton: 5,
|
||||
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'calls.html' },
|
||||
{ name: 'Dateien', unter: 'Ablage und Freigaben', zeichen: 'dateien', ton: 4,
|
||||
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'dateien.html' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Rund um den Creator',
|
||||
unter: 'Die Betreuungsakte – Stand, Zahlen, Verlauf',
|
||||
bereiche: [
|
||||
{ name: 'Creator-Profile', unter: 'Ziele und 90-Tage-Plan', zeichen: 'profil', ton: 1,
|
||||
rollen: ['admin', 'manager', 'scout'], ziel: 'profil.html' },
|
||||
{ name: 'Mein Profil', unter: 'Deine Ziele und Pläne', zeichen: 'profil', ton: 1,
|
||||
rollen: ['creator'], ziel: 'profil.html' },
|
||||
{ name: 'Start-Check', unter: 'Erstanalyse, 16 Punkte', zeichen: 'startcheck', ton: 3,
|
||||
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'startcheck.html' },
|
||||
{ name: 'LIVE-Analyse', unter: 'Vorher, während, danach', zeichen: 'live', ton: 8,
|
||||
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'bereich.html?b=live' },
|
||||
{ name: 'Content-Planung', unter: 'Idee bis Upload', zeichen: 'content', ton: 2,
|
||||
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'content.html' },
|
||||
{ name: 'Community', unter: 'Moderation und Konflikte', zeichen: 'community', ton: 5,
|
||||
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'bereich.html?b=community' },
|
||||
{ name: 'Technik', unter: 'Setup, Fehler, Lösungen', zeichen: 'technik', ton: 4,
|
||||
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'bereich.html?b=technik' },
|
||||
{ name: 'Schutz & Regeln', unter: 'Richtlinien und Vorfälle', zeichen: 'schutz', ton: 7,
|
||||
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'bereich.html?b=schutz' },
|
||||
{ name: 'Reports & Review', unter: 'Woche und Entscheidung', zeichen: 'reports', ton: 6,
|
||||
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'report.html' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Team & System',
|
||||
unter: 'Was den Laden am Laufen hält',
|
||||
bereiche: [
|
||||
{ name: 'Personen & Zugänge', unter: 'Rollen und Codes', zeichen: 'personen', ton: 4,
|
||||
rollen: ['admin', 'manager'], ziel: 'personen.html' },
|
||||
{ name: 'Scout-Pipeline', unter: 'Entdeckt bis übergeben', zeichen: 'scouting', ton: 3,
|
||||
rollen: ['admin', 'manager', 'scout'], ziel: 'scouting.html' },
|
||||
{ name: 'Wissens-Bibliothek', unter: 'Anleitungen und PDFs', zeichen: 'wissen', ton: 1,
|
||||
rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'wissen.html' },
|
||||
{ name: 'Automationen', unter: 'Was von allein passiert', zeichen: 'automation', ton: 7,
|
||||
rollen: ['admin', 'manager'], ziel: 'automation.html' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
/* Welcher Hinweis gehört auf welche Kachel. Die Zahl auf der Kachel ist
|
||||
damit KEIN neuer Zähler, sondern dieselbe Quelle wie die Liste
|
||||
darüber -- sonst stünden irgendwann zwei verschiedene Wahrheiten
|
||||
übereinander auf einem Bildschirm. */
|
||||
const HINWEIS_ZU_KACHEL = {
|
||||
aufgaben_ueberfaellig: 'Aufgaben',
|
||||
aufgaben_heute: 'Aufgaben',
|
||||
aufgaben_review: 'Aufgaben',
|
||||
termine_heute: 'Kalender',
|
||||
protokoll_fehlt: 'Calls & Protokolle',
|
||||
dateien_review: 'Dateien',
|
||||
bereiche_dringend: 'LIVE-Analyse',
|
||||
startcheck_handlung: 'Start-Check',
|
||||
ohne_startcheck: 'Start-Check',
|
||||
followup_faellig: 'Scout-Pipeline',
|
||||
uebergabe_offen: 'Scout-Pipeline',
|
||||
review_faellig: 'Reports & Review',
|
||||
review_bald: 'Reports & Review',
|
||||
ohne_betreuung: 'Personen & Zugänge',
|
||||
ohne_profil: 'Creator-Profile',
|
||||
};
|
||||
|
||||
const $ = (id) => document.getElementById(id);
|
||||
const el = (tag, klasse, text) => {
|
||||
const k = document.createElement(tag);
|
||||
if (klasse) k.className = klasse;
|
||||
if (text !== undefined) k.textContent = text;
|
||||
return k;
|
||||
};
|
||||
|
||||
function zeichenBauen(name) {
|
||||
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
svg.setAttribute('viewBox', '0 0 24 24');
|
||||
svg.setAttribute('aria-hidden', 'true');
|
||||
svg.setAttribute('class', 'kachel__svg');
|
||||
for (const d of (ZEICHEN[name] || [])) {
|
||||
const p = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
||||
p.setAttribute('d', d);
|
||||
svg.append(p);
|
||||
}
|
||||
return svg;
|
||||
}
|
||||
|
||||
let ich = null;
|
||||
let hinweise = [];
|
||||
|
||||
/* ---------- Aufbau ------------------------------------------------------- */
|
||||
|
||||
function bereicheBauen() {
|
||||
const ziel = $('bereiche');
|
||||
ziel.textContent = '';
|
||||
|
||||
/* Zahlen je Kachel aus den Hinweisen zusammenzählen. Warnstufe
|
||||
schlägt durch: Eine Kachel mit etwas Überfälligem ist rot, auch
|
||||
wenn daneben Harmloses mitgezählt wird. */
|
||||
const zahlen = new Map();
|
||||
for (const h of hinweise) {
|
||||
const kachel = HINWEIS_ZU_KACHEL[h.art];
|
||||
if (!kachel) continue;
|
||||
const bisher = zahlen.get(kachel) || { n: 0, warn: false };
|
||||
bisher.n += h.anzahl;
|
||||
if (h.stufe === 'warnung') bisher.warn = true;
|
||||
zahlen.set(kachel, bisher);
|
||||
}
|
||||
|
||||
let laufNr = 0;
|
||||
for (const gruppe of GRUPPEN) {
|
||||
const meine = gruppe.bereiche.filter((b) => b.rollen.includes(ich.rolle));
|
||||
if (!meine.length) continue;
|
||||
|
||||
const abschnitt = el('section', 'gruppe');
|
||||
const kopf = el('div', 'gruppe__kopf');
|
||||
kopf.append(el('h2', 'gruppe__name', gruppe.name));
|
||||
kopf.append(el('span', 'gruppe__unter', gruppe.unter));
|
||||
abschnitt.append(kopf);
|
||||
|
||||
const liste = el('ul', 'kacheln');
|
||||
for (const b of meine) {
|
||||
const li = el('li', 'kachel');
|
||||
li.dataset.ton = String(b.ton);
|
||||
if (b.gross) li.dataset.gross = 'ja';
|
||||
/* Der Einlauf wird gestaffelt -- aber über eine Eigenschaft, die
|
||||
bei "weniger Bewegung" nichts tut (siehe start.css). */
|
||||
li.style.setProperty('--nr', String(laufNr++));
|
||||
|
||||
const a = el('a', 'kachel__link');
|
||||
a.href = b.ziel;
|
||||
|
||||
const zeichen = el('span', 'kachel__zeichen');
|
||||
zeichen.append(zeichenBauen(b.zeichen));
|
||||
a.append(zeichen);
|
||||
|
||||
const text = el('span', 'kachel__text');
|
||||
text.append(el('span', 'kachel__name', b.name));
|
||||
text.append(el('span', 'kachel__unter', b.unter));
|
||||
a.append(text);
|
||||
|
||||
const zahl = zahlen.get(b.name);
|
||||
if (zahl && zahl.n > 0) {
|
||||
const marke = el('span', 'kachel__zahl', String(zahl.n));
|
||||
if (zahl.warn) marke.dataset.warn = 'ja';
|
||||
/* Vorlesende Programme bekommen einen Satz statt einer nackten
|
||||
Zahl -- "Aufgaben, 3" sagt nichts. */
|
||||
marke.setAttribute('aria-label', `${zahl.n} offene Punkte in ${b.name}`);
|
||||
a.append(marke);
|
||||
} else {
|
||||
a.append(el('span', 'kachel__pfeil', '→'));
|
||||
}
|
||||
|
||||
li.append(a);
|
||||
liste.append(li);
|
||||
}
|
||||
abschnitt.append(liste);
|
||||
ziel.append(abschnitt);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- Laden -------------------------------------------------------- */
|
||||
|
||||
async function laden() {
|
||||
let ich;
|
||||
try {
|
||||
const antwort = await fetch('/workspace/api/ich', { credentials: 'same-origin' });
|
||||
if (!antwort.ok) { location.assign('/workspace/'); return; }
|
||||
@@ -58,39 +272,17 @@
|
||||
}
|
||||
|
||||
$('wer').textContent = `${ich.name} · ${ich.rolle_name || ich.rolle}`;
|
||||
$('gruss').textContent = `Willkommen, ${ich.name}`;
|
||||
/* Tageszeit statt immer "Willkommen". Kostet nichts und macht aus
|
||||
einer Maske eine Begrüßung. */
|
||||
const stunde = new Date().getHours();
|
||||
const tageszeit = stunde < 5 ? 'Noch wach' : stunde < 11 ? 'Guten Morgen'
|
||||
: stunde < 18 ? 'Guten Tag' : 'Guten Abend';
|
||||
$('gruss').textContent = `${tageszeit}, ${ich.name}`;
|
||||
$('rollentext').textContent = ROLLENTEXT[ich.rolle] || ich.rolle;
|
||||
|
||||
const liste = $('bereiche');
|
||||
for (const b of BEREICHE.filter((b) => b.rollen.includes(ich.rolle))) {
|
||||
const li = document.createElement('li');
|
||||
li.className = 'bereich';
|
||||
li.dataset.phase = String(b.phase);
|
||||
if (b.ziel) li.dataset.fertig = 'ja';
|
||||
|
||||
const name = document.createElement('span');
|
||||
name.className = 'bereich__name';
|
||||
name.textContent = b.name;
|
||||
|
||||
const stand = document.createElement('span');
|
||||
stand.className = 'bereich__stand';
|
||||
stand.textContent = b.ziel ? 'öffnen' : (b.phase === 1 ? 'als Nächstes' : `Phase ${b.phase}`);
|
||||
|
||||
if (b.ziel) {
|
||||
/* Fertige Bereiche sind echte Verweise -- Tastatur und
|
||||
Rechtsklick funktionieren damit wie gewohnt. */
|
||||
const a = document.createElement('a');
|
||||
a.className = 'bereich__link';
|
||||
a.href = b.ziel;
|
||||
a.append(name, stand);
|
||||
li.append(a);
|
||||
} else {
|
||||
li.append(name, stand);
|
||||
}
|
||||
liste.append(li);
|
||||
}
|
||||
|
||||
/* Die Hinweise zuerst -- die Kacheln brauchen ihre Zahlen. */
|
||||
await hinweiseLaden();
|
||||
bereicheBauen();
|
||||
await zahlenLaden();
|
||||
}
|
||||
|
||||
@@ -124,34 +316,32 @@
|
||||
daten = await antwort.json();
|
||||
} catch { return; }
|
||||
|
||||
hinweise = daten.hinweise || [];
|
||||
const liste = $('dran');
|
||||
liste.textContent = '';
|
||||
if (!daten.hinweise.length) { $('dran-block').hidden = true; return; }
|
||||
if (!hinweise.length) { $('dran-block').hidden = true; return; }
|
||||
|
||||
for (const h of daten.hinweise) {
|
||||
const li = document.createElement('li');
|
||||
li.className = 'dran__punkt';
|
||||
for (const h of hinweise) {
|
||||
const li = el('li', 'dran__punkt');
|
||||
li.dataset.stufe = h.stufe;
|
||||
|
||||
/* Jeder Hinweis fuehrt irgendwohin -- ein Hinweis ohne Ziel ist
|
||||
nur ein schlechtes Gewissen. */
|
||||
const a = document.createElement('a');
|
||||
a.className = 'dran__link';
|
||||
const a = el('a', 'dran__link');
|
||||
a.href = h.ziel;
|
||||
|
||||
const text = document.createElement('span');
|
||||
text.className = 'dran__text';
|
||||
text.textContent = (EINZAHL[h.art] || ((n) => `${n} × ${h.text}`))(h.anzahl);
|
||||
|
||||
const pfeil = document.createElement('span');
|
||||
pfeil.className = 'dran__pfeil';
|
||||
a.append(el('span', 'dran__text',
|
||||
(EINZAHL[h.art] || ((n) => `${n} × ${h.text}`))(h.anzahl)));
|
||||
const pfeil = el('span', 'dran__pfeil', '→');
|
||||
pfeil.setAttribute('aria-hidden', 'true');
|
||||
pfeil.textContent = '→';
|
||||
|
||||
a.append(text, pfeil);
|
||||
a.append(pfeil);
|
||||
li.append(a);
|
||||
liste.append(li);
|
||||
}
|
||||
/* Sieben Hinweise untereinander sind eine Wand -- und die
|
||||
wichtigsten stehen ohnehin oben (der Server sortiert nach Stufe).
|
||||
Sichtbar bleiben vier, der Rest ist einen Klick entfernt.
|
||||
Derselbe Helfer wie im Protokoll und im Verlauf. */
|
||||
window.klappe?.(liste, $('dran-schalter'), $('dran-schalter-text'));
|
||||
$('dran-block').hidden = false;
|
||||
}
|
||||
|
||||
@@ -174,27 +364,31 @@
|
||||
daten = await antwort.json();
|
||||
} catch { return; }
|
||||
|
||||
/* Sechs Nullen nebeneinander sind kein Bericht, sondern Rauschen.
|
||||
Wenn wirklich nichts offen ist, steht dort ein Satz -- und der
|
||||
Platz gehört den Bereichen. */
|
||||
const summe = ZAHLEN.reduce((n, z) => n + (daten[z.schluessel] ?? 0), 0);
|
||||
const block = $('zahlen-block');
|
||||
if (!summe) {
|
||||
block.dataset.leer = 'ja';
|
||||
$('zahlen').textContent = '';
|
||||
$('zahlen-leer').hidden = false;
|
||||
return;
|
||||
}
|
||||
block.removeAttribute('data-leer');
|
||||
$('zahlen-leer').hidden = true;
|
||||
|
||||
const liste = $('zahlen');
|
||||
liste.textContent = '';
|
||||
for (const z of ZAHLEN) {
|
||||
const wert = daten[z.schluessel] ?? 0;
|
||||
const li = document.createElement('li');
|
||||
li.className = 'zahl';
|
||||
const li = el('li', 'zahl');
|
||||
if (z.warn && wert > 0) li.dataset.warn = 'ja';
|
||||
|
||||
const n = document.createElement('span');
|
||||
n.className = 'zahl__wert';
|
||||
n.textContent = String(wert);
|
||||
|
||||
const t = document.createElement('span');
|
||||
t.className = 'zahl__name';
|
||||
t.textContent = z.name;
|
||||
|
||||
li.append(n, t);
|
||||
li.append(el('span', 'zahl__wert', String(wert)));
|
||||
li.append(el('span', 'zahl__name', z.name));
|
||||
liste.append(li);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
laden();
|
||||
})();
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -134,8 +134,8 @@
|
||||
</form>
|
||||
</dialog>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/aufgaben.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/aufgaben.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/automation.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/automation.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -127,8 +127,8 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/automation.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/automation.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/bereich.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/bereich.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -98,8 +98,8 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/bereich.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/bereich.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/calls.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/calls.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -49,9 +49,9 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/ki.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/calls.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/ki.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/calls.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/content.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/content.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -153,8 +153,8 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/content.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/content.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/dateien.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/dateien.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -88,8 +88,8 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/dateien.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/dateien.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
type="image/webp" media="(max-width: 899px)" />
|
||||
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="gate">
|
||||
@@ -143,6 +143,6 @@
|
||||
</p>
|
||||
</main>
|
||||
|
||||
<script src="assets/js/gate.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/gate.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/kalender.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/kalender.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -94,8 +94,8 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kalender.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kalender.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/personen.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/personen.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -104,8 +104,8 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/personen.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/personen.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/profil.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/profil.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -127,8 +127,8 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/profil.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/profil.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/report.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/report.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -86,9 +86,9 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/ki.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/report.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/ki.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/report.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/scouting.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/scouting.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -124,8 +124,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/scouting.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/scouting.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+24
-15
@@ -7,8 +7,8 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -32,22 +32,31 @@
|
||||
zwischen "wie viel liegt an" und "was muss ich jetzt tun" ist.
|
||||
Bleibt komplett weg, wenn nichts anliegt. -->
|
||||
<section class="dran" id="dran-block" hidden>
|
||||
<p class="feldschild">Was ist dran</p>
|
||||
<ul class="dran__liste" id="dran"></ul>
|
||||
<div class="klapp-kopf">
|
||||
<p class="feldschild">Was ist dran</p>
|
||||
<button type="button" class="knopf-still" id="dran-schalter"
|
||||
aria-expanded="false" aria-controls="dran" hidden>
|
||||
<span id="dran-schalter-text">Alle zeigen</span>
|
||||
<svg class="klapp-pfeil" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="m6 9.5 6 6 6-6" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<ul class="dran__liste" id="dran" data-klapp="zu"></ul>
|
||||
</section>
|
||||
|
||||
<!-- Zahlen zuerst: Das Konzept will "Prioritäten statt Datenfriedhof". -->
|
||||
<section class="zahlen-block">
|
||||
<!-- Zahlen zuerst: Das Konzept will "Prioritäten statt Datenfriedhof".
|
||||
Sind alle sechs null, steht dort ein Satz statt sechs Nullen. -->
|
||||
<section class="zahlen-block" id="zahlen-block">
|
||||
<p class="feldschild">Deine Aufgaben</p>
|
||||
<ul class="zahlen" id="zahlen"></ul>
|
||||
<p class="zahlen-leer" id="zahlen-leer" hidden>Nichts offen. Alles abgearbeitet.</p>
|
||||
</section>
|
||||
|
||||
<!-- Bereiche aus dem Konzept. Was noch nicht gebaut ist, steht ehrlich
|
||||
dran, statt Kacheln anzubieten, die ins Leere führen. -->
|
||||
<section>
|
||||
<p class="feldschild">Bereiche</p>
|
||||
<ul class="bereiche" id="bereiche"></ul>
|
||||
</section>
|
||||
<!-- Die Bereiche, in drei Gruppen: was man täglich braucht, was zu
|
||||
einem Creator gehört, was den Laden am Laufen hält. Aufgebaut von
|
||||
start.js – dort steht auch, warum. -->
|
||||
<div id="bereiche"></div>
|
||||
|
||||
<p class="fuss">
|
||||
„Was ist dran" führt keine eigene Liste, sondern zeigt, was in den Bereichen
|
||||
@@ -56,8 +65,8 @@
|
||||
</p>
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/start.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/start.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/startcheck.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/startcheck.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -65,9 +65,9 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/ki.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/startcheck.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/ki.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/startcheck.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/uebersicht.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/uebersicht.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070d" />
|
||||
<link rel="icon" href="assets/img/favicon.png" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/wissen.css?v=202608312145" />
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202608312236" />
|
||||
<link rel="stylesheet" href="assets/css/wissen.css?v=202608312236" />
|
||||
</head>
|
||||
|
||||
<body class="start">
|
||||
@@ -170,8 +170,8 @@
|
||||
|
||||
</main>
|
||||
|
||||
<script src="assets/js/wahl.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wissen.js?v=202608312145" defer></script>
|
||||
<script src="assets/js/wahl.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/kopf.js?v=202608312236" defer></script>
|
||||
<script src="assets/js/wissen.js?v=202608312236" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user