/* =================================================================== Die Bereiche -- EINE Quelle für die ganze Anwendung. Zeichen, Farbton, Rolle und Ziel jedes Bereichs standen bis zum 01.09.2026 nur in start.js. Seit jede Unterseite Zeichen und Farbe ihrer Kachel trägt, brauchen sie auch die Kopfleisten -- und eine zweite, abgeschriebene Liste wäre der sichere Weg, dass "Aufgaben" irgendwann auf der Startseite gelb und auf der Aufgabenseite grün ist. Deshalb liegt beides jetzt hier und wird von start.js UND kopf.js benutzt. Wer eine Kachel ändert, ändert damit automatisch auch den Kopf der zugehörigen Seite. =================================================================== */ (() => { 'use strict'; /* ---------- Zeichen ------------------------------------------------------ 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 = { /* Vier Felder mit deutlicher Fuge. Die Fuge ist die eigentliche Aussage des Zeichens ("mehrere Bereiche nebeneinander") -- ist sie zu schmal, sieht man nur einen Kasten. */ dashboard: ['M4 4.5h6.4v6.4H4z', 'M13.6 4.5h6.4v4.2h-6.4z', 'M13.6 11.6h6.4v7.9h-6.4z', 'M4 13.7h6.4v5.8H4z'], aufgaben: ['M4.5 5h4v14h-4z', 'M10 5h4v9h-4z', 'M15.5 5h4v11.5h-4z'], /* Der Kasten beginnt tiefer, die Querlinie sitzt weiter unten und die beiden Beine stehen weiter aussen. Bei 25 px Groesse verschmelzen Linien, die naeher als vier Einheiten beieinander liegen, zu einer Flaeche -- vorher sah der Kalender deshalb aus wie ein leerer Kasten. */ kalender: ['M3.5 7h17v12.5h-17z', 'M3.5 11.5h17', 'M7.5 4v4.6', 'M16.5 4v4.6'], calls: ['M3.5 7h11v10h-11z', 'M14.5 11l6-3.5v9l-6-3.5z'], dateien: ['M3.5 6.5h5.5l2 2h9.5v11h-17z'], /* Der Steckbrief: eine Person IN einer Karte -- unterscheidbar vom Profil-Zeichen (nur die Person), damit die beiden Kacheln nicht gleich aussehen. */ steckbrief: ['M3.5 5.5h17v13h-17z', 'M8.5 11.2a1.9 1.9 0 1 0 0-3.8 1.9 1.9 0 0 0 0 3.8z', 'M5.6 16.2c0-1.7 1.3-3 2.9-3s2.9 1.3 2.9 3', 'M14.5 9.5h4', 'M14.5 13h4'], 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'], /* Drei Regler mit ihren Griffen. Die Griffe waren bis zum 03.09.2026 unbrauchbare Pfade ("a1.4 1.4 0 1 0 0-.02z" -- ein Bogen der Laenge null): Sie wurden schlicht nicht gezeichnet, und uebrig blieben drei nackte Striche, die aussahen wie ein Menue-Symbol. Jetzt sind es echte Kreise. */ technik: ['M4 7.5h16', 'M4 12h16', 'M4 16.5h16', 'M9 5.9a1.6 1.6 0 1 0 0 3.2 1.6 1.6 0 0 0 0-3.2z', 'M15 10.4a1.6 1.6 0 1 0 0 3.2 1.6 1.6 0 0 0 0-3.2z', 'M7.5 14.9a1.6 1.6 0 1 0 0 3.2 1.6 1.6 0 0 0 0-3.2z'], 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..17 -- JEDE Kachel hat ihre eigene Farbe. Ein erster Versuch mit frei gewählten Farben ergab Paare mit einem Abstand von 1,4: praktisch dieselbe Farbe, das sieht nach Zufall aus statt nach Absicht. Deshalb sind Farben UND Zuordnung gerechnet, von tools/kachel-farben.mjs. Die Überlegung dahinter: Das Auge vergleicht nur, was nebeneinander liegt. Siebzehn Farben müssen sich also nicht alle voneinander unterscheiden, sondern nur von ihren Nachbarn im Raster -- und da sind es jetzt mindestens 105,9 Grad. Wer hier Kacheln umsortiert oder eine hinzufügt, ändert damit die Nachbarschaften. Dann gehört tools/kachel-farben.mjs neu gelaufen (dort die Liste NACHBARN anpassen), sonst stimmt der Abstand nicht mehr und niemand merkt es. */ const GRUPPEN = [ { name: 'Täglich', unter: 'Was du sowieso jeden Tag aufmachst', bereiche: [ { name: 'Dashboard', unter: 'Alle Creator auf einen Blick', zeichen: 'dashboard', ton: 3, gross: true, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'uebersicht.html', szene: 'showbuehne' }, { name: 'Aufgaben', unter: 'Offen, in Arbeit, Review', zeichen: 'aufgaben', ton: 11, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'aufgaben.html', szene: 'garage' }, { name: 'Kalender', unter: 'Termine und Calls', zeichen: 'kalender', ton: 16, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'kalender.html', szene: 'skyline' }, { name: 'Calls & Protokolle', unter: 'Gespräche mit To-dos', zeichen: 'calls', ton: 9, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'calls.html', szene: 'lounge' }, { name: 'Dateien', unter: 'Ablage und Freigaben', zeichen: 'dateien', ton: 2, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'dateien.html', szene: 'arena' }, ], }, { name: 'Rund um den Creator', unter: 'Die Betreuungsakte – Stand, Zahlen, Verlauf', bereiche: [ /* ZWEI VERSCHIEDENE DINGE, zwei Kacheln (01.09.2026). Vorher war beides dieselbe Seite, und das war verwirrend: Oben stand "Profil: SpongBobSchwammKopf" und mitten darin "MEIN PROFIL - Dogfather". Zwei Personen auf einem Bildschirm, ohne dass klar war, welche gerade gemeint ist. Es sind auch wirklich zwei Sachen: MEIN STECKBRIEF gehoert MIR -- Bild, ein Satz ueber mich, meine Kanaele. Fuehre ich selbst, hat jeder (auch Scouts und Manager). CREATOR-PROFILE die BETREUUNGSAKTE eines Creators -- Ziele, 90-Tage-Plan, interne Notizen. Fuehren die Betreuer. Ein Creator sieht nur seine eigene Akte (dort steht auch sein Steckbrief mit drin, er hat ja nur eine Seite). Alle anderen bekommen beide Kacheln getrennt. */ { name: 'Mein Steckbrief', unter: 'Dein Bild und deine Kanäle', zeichen: 'steckbrief', ton: 15, rollen: ['admin', 'manager', 'scout'], ziel: 'steckbrief.html', szene: 'halle' }, { name: 'Creator-Profile', unter: 'Ziele und 90-Tage-Plan', zeichen: 'profil', ton: 8, rollen: ['admin', 'manager', 'scout'], ziel: 'profil.html', szene: 'halle' }, { name: 'Mein Profil', unter: 'Dein Steckbrief, Ziele und Pläne', zeichen: 'profil', ton: 8, rollen: ['creator'], ziel: 'profil.html', szene: 'halle' }, { name: 'Start-Check', unter: 'Erstanalyse, 16 Punkte', zeichen: 'startcheck', ton: 18, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'startcheck.html', szene: 'wald' }, { name: 'LIVE-Analyse', unter: 'Vorher, während, danach', zeichen: 'live', ton: 7, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'bereich.html?b=live', szene: 'portal' }, { name: 'Content-Ideen', unter: 'Idee bis Upload', zeichen: 'content', ton: 13, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'content.html', szene: 'portal' }, { name: 'Community', unter: 'Moderation und Konflikte', zeichen: 'community', ton: 6, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'bereich.html?b=community', szene: 'lounge' }, { name: 'Technik', unter: 'Setup, Fehler, Lösungen', zeichen: 'technik', ton: 12, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'bereich.html?b=technik', szene: 'garage' }, { name: 'Schutz & Regeln', unter: 'Richtlinien und Vorfälle', zeichen: 'schutz', ton: 1, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'bereich.html?b=schutz', szene: 'halle' }, { name: 'Reports & Review', unter: 'Woche und Entscheidung', zeichen: 'reports', ton: 14, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'report.html', szene: 'showbuehne' }, ], }, { name: 'Team & System', unter: 'Was den Laden am Laufen hält', /* Für einen Creator bleibt von dieser Gruppe genau eine Kachel übrig: die Wissens-Bibliothek. "Team & System" wäre dann eine Überschrift, die etwas verspricht, was gar nicht da ist -- und die klingt, als gäbe es dahinter noch einen Bereich, den er nicht sehen darf. Er liest stattdessen "Wissen", und das beschreibt genau, was dort steht. Der Untertitel wechselt mit. */ nameCreator: 'Wissen', unterCreator: 'Nachschlagen, wenn du etwas brauchst', bereiche: [ /* NUR DogFather (02.09.2026, Wunsch: "die manager sollen diese kategorien garnicht sehen"). Es war ohnehin ein Widerspruch: In der Rollenauswahl steht seit jeher "Manager -- dieselben Rechte wie DogFather, AUSSER der Personenverwaltung". Die Kachel stand trotzdem bei ihm, und die Seite liess ihn auch hinein. Eine Beschreibung, die etwas anderes sagt als die Software, ist schlimmer als beides einzeln: Man weiss danach nicht mehr, welcher von beiden man glauben soll. */ { name: 'Personen & Zugänge', unter: 'Rollen und Codes', zeichen: 'personen', ton: 10, rollen: ['admin'], ziel: 'personen.html', szene: 'halle' }, { name: 'Scout-Pipeline', unter: 'Entdeckt bis übergeben', zeichen: 'scouting', ton: 17, rollen: ['admin', 'manager', 'scout'], ziel: 'scouting.html', szene: 'wald' }, { name: 'Wissens-Bibliothek', unter: 'Anleitungen und PDFs', zeichen: 'wissen', ton: 4, rollen: ['admin', 'manager', 'creator', 'scout'], ziel: 'wissen.html', szene: 'arena' }, /* Ebenfalls nur DogFather (02.09.2026). Was von allein passiert, legt fest, was ALLEN anderen automatisch zugeschoben wird -- das gehört in dieselbe Hand wie die Rollenvergabe. */ { name: 'Automationen', unter: 'Was von allein passiert', zeichen: 'automation', ton: 5, rollen: ['admin'], ziel: 'automation.html', szene: 'garage' }, ], }, ]; /* Ein Bereich anhand des Dateinamens finden. Die Bereichsseite (bereich.html?b=live) trägt ihren Bereich in der Adresse -- deshalb wird auch die Abfrage verglichen, nicht nur der Dateiname. */ function zuSeite(pfad, abfrage) { const datei = String(pfad).split('/').pop() || 'start.html'; const gesucht = datei + (abfrage || ''); let treffer = null; for (const g of GRUPPEN) { for (const b of g.bereiche) { if (b.ziel === gesucht) return b; /* Ohne Abfrage: der erste Bereich mit passendem Dateinamen. "Mein Profil" und "Creator-Profile" zeigen auf dieselbe Datei und teilen sich Zeichen und Ton -- da ist beides richtig. */ if (!treffer && b.ziel.split('?')[0] === datei) treffer = b; } } return treffer; } /* Ein SVG mit dem Zeichen eines Bereichs. Klasse frei wählbar, damit Kachel, Hinweiszeile und Seitenkopf dieselbe Form in unterschiedlicher Größe benutzen können. */ /* ---------- Die Zeichen (überarbeitet 03.09.2026) ------------------------ Wunsch: "ich will dass du die symbole perfektionnierst, ich will wirklich dass jeder sich denkt woooow." Vorher war jedes Zeichen eine flache Linie in einer Farbe. Sauber, aber leblos -- siebzehn gleich starke Striche nebeneinander. Jetzt besteht jedes Zeichen aus ZWEI übereinanderliegenden Lagen derselben Form: SCHEIN dick, weich, halbdurchsichtig -- das Licht, das die Linie wirft. Sie liegt darunter und wird nie gelesen, aber ohne sie sitzt das Zeichen flach auf der Fläche statt darüber zu schweben. LINIE die eigentliche Zeichnung, mit einem VERLAUF von oben hell nach unten gedämpft. Der Verlauf ist der eigentliche Kniff. Er ist EINMAL im Dokument definiert und benutzt `currentColor` -- dadurch passt er sich jeder der siebzehn Kachelfarben von selbst an, ohne siebzehn Verläufe. Eine Lichtquelle oben, wie in der echten Welt: Genau das lässt eine Linie geprägt statt gemalt wirken. Kein zusätzliches Bild, keine Schriftart, kein Nachladen -- alles entsteht aus den Pfaden, die ohnehin schon da waren. */ const NS = 'http://www.w3.org/2000/svg'; const VERLAUF_ID = 'zeichen-verlauf'; /** Legt den gemeinsamen Verlauf einmal ins Dokument. Alle Zeichen * verweisen darauf; ein zweiter Aufruf tut nichts. */ function verlaufSicherstellen() { if (document.getElementById(VERLAUF_ID)) return; const svg = document.createElementNS(NS, 'svg'); svg.setAttribute('aria-hidden', 'true'); svg.setAttribute('width', '0'); svg.setAttribute('height', '0'); svg.style.position = 'absolute'; const defs = document.createElementNS(NS, 'defs'); const lg = document.createElementNS(NS, 'linearGradient'); lg.setAttribute('id', VERLAUF_ID); /* userSpaceOnUse, NICHT die Vorgabe objectBoundingBox -- und das ist kein Detail, sondern der Unterschied zwischen "sieht toll aus" und "die Hälfte des Zeichens fehlt". Ein Verlauf in Objektkoordinaten wird auf den Umriss JEDES einzelnen Pfades gerechnet. Eine waagerechte Linie (M4 12h16) hat aber eine Höhe von null: Der Verlauf ist damit entartet, und der Browser zeichnet den Pfad einfach GAR NICHT. Genau das ist passiert: Beim Kalender verschwand die Querlinie, beim Technik-Zeichen alle drei Regler-Striche, bei den Berichten die Grundlinie. Zurück blieb ein leerer Kasten und drei Punkte -- und es sah aus, als sei die Idee mit dem Verlauf schuld. In Benutzerkoordinaten läuft der Verlauf über die festen 24 Einheiten des Rasters, unabhängig davon, wie hoch oder flach der einzelne Pfad ist. Damit bekommt jede Linie den Farbwert, der ihrer Höhe im Zeichen entspricht -- was ohnehin richtiger ist: Das Licht kommt von oben, nicht von jedem Strich einzeln. */ lg.setAttribute('gradientUnits', 'userSpaceOnUse'); lg.setAttribute('x1', '0'); lg.setAttribute('y1', '2'); lg.setAttribute('x2', '0'); lg.setAttribute('y2', '22'); /* currentColor statt einer festen Farbe: Der Verlauf erbt damit den Ton der Kachel, auf der er gerade liegt. */ for (const [pos, deck] of [['0', '1'], ['0.55', '0.92'], ['1', '0.6']]) { const s = document.createElementNS(NS, 'stop'); s.setAttribute('offset', pos); s.setAttribute('stop-color', 'currentColor'); s.setAttribute('stop-opacity', deck); lg.append(s); } defs.append(lg); svg.append(defs); document.body.append(svg); } function zeichenBauen(name, klasse = 'kachel__svg') { verlaufSicherstellen(); const svg = document.createElementNS(NS, 'svg'); svg.setAttribute('viewBox', '0 0 24 24'); svg.setAttribute('aria-hidden', 'true'); svg.setAttribute('class', klasse); /* EINE Lage. Ein zweiter, weichgezeichneter Unterbau stand hier kurzzeitig und hat die feinen Lücken zugeschmiert -- siehe die ausführliche Begründung in start.css. */ const g = document.createElementNS(NS, 'g'); g.setAttribute('class', 'zeichen__linie'); for (const d of (ZEICHEN[name] || [])) { const pfad = document.createElementNS(NS, 'path'); pfad.setAttribute('d', d); g.append(pfad); } svg.append(g); return svg; } /* ---------- Das Merkzeichen ---------------------------------------------- Wunsch vom 01.09.2026: "wenn die Ansprechpartner was markieren, sollen die da so ein Zeichen/Symbol haben, so dass die sehen, da ist was -- und es soll auch oben in der Kachel angezeigt werden." Es ist bewusst das EINZIGE Zeichen der ganzen Anwendung, das eine eigene Form hat statt der 24×24-Linienzeichen oben: eine Raute mit Ausrufestrich. Der Grund ist nicht Geschmack, sondern Erkennbarkeit -- alle anderen Zeichen sind Rechtecke und Kreise; eine Raute ist die einzige Form auf dem Bildschirm, die spitz nach oben zeigt, und genau deshalb findet das Auge sie zwischen zwanzig Kacheln sofort. Und es ist immer DIESELBE Farbe (Bernstein), egal auf welcher Kachel es sitzt. Ein Zeichen, das seine Farbe wechselt, muss gelesen werden; eines, das immer gleich aussieht, wird erkannt. Rot wäre falsch -- "verbessern" ist kein Fehler, sondern ein Auftrag. anzahl > 1 schreibt die Zahl daneben, sonst steht nur das Zeichen. Der Satz für Vorleseprogramme wird immer gesetzt: Ein Symbol ohne Text ist für sie nicht vorhanden. */ function merkzeichenBauen(anzahl = 0, klasse = 'merk') { const s = document.createElement('span'); s.className = klasse; s.setAttribute('role', 'img'); s.setAttribute('aria-label', anzahl > 0 ? `${anzahl} ${anzahl === 1 ? 'Punkt ist' : 'Punkte sind'} zum Verbessern markiert` : 'Zum Verbessern markiert'); 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', klasse + '__svg'); /* Drei Pfade: die gefüllte Raute, der Strich, der Punkt. Getrennt, damit die Fläche eine andere Deckkraft bekommen kann als die Linie -- eine durchgehend volle Raute wäre auf dunklem Grund ein Klecks. */ const teile = [ ['M12 1.9 22.1 12 12 22.1 1.9 12z', 'flaeche'], ['M12 7.5v5.6', 'strich'], ['M12 16.9h.01', 'punkt'], ]; for (const [d, art] of teile) { const p = document.createElementNS('http://www.w3.org/2000/svg', 'path'); p.setAttribute('d', d); p.setAttribute('class', `${klasse}__${art}`); svg.append(p); } s.append(svg); if (anzahl > 1) { const n = document.createElement('span'); n.className = klasse + '__n'; n.textContent = String(anzahl); n.setAttribute('aria-hidden', 'true'); s.append(n); } return s; } window.Bereiche = { ZEICHEN, GRUPPEN, zuSeite, zeichenBauen, merkzeichenBauen }; })();