Files
dogfather-universe/workspace/assets/js/bereiche.js
T
DogFatherGitandClaude Opus 5 44716fa54b Aus Zeichnungen werden Gegenstaende -- Kacheln der GANZEN Seite
"ich will dass die krank realistisch sind, und alle kacheln durch die
ganze website perfektionieren."

DIE ZEICHEN bekommen die Beleuchtung, die man aus der Wirklichkeit
kennt -- vier Lagen statt einer:

  KOERPER        gefuellte Grundform, oben satt, unten auslaufend
  EIGENSCHATTEN  eine dunkle Lage, die von unten hereinkriecht. Ein
                 Koerper ist unten dunkler als oben; ohne das bleibt
                 jede Flaeche eine Farbflaeche
  GLANZ          die Spiegelung, schmal ueber die obere Haelfte
  KONTUR         mit ZWEI Lichtquellen: oben das Hauptlicht (fast weiss),
                 in der Mitte der Eigenton, unten STREULICHT vom
                 Untergrund. Der letzte Stopp ist der Unterschied
                 zwischen "Zeichnung" und "Ding" -- ohne ihn laeuft jede
                 Form nach unten ins Dunkle aus.

Dazu ein SCHLAGSCHATTEN auf die Plakette, versetzt nach unten statt
mittig. Er ist der Grund, warum das Zeichen ueber der Flaeche schwebt
statt darauf zu liegen.

DIE PLAKETTE bekommt eine KOERNUNG -- eine sehr feine, unregelmaessige
Struktur. Das ist der Unterschied zwischen "am Rechner gemacht" und
"Gegenstand": Eine makellos glatte Farbflaeche gibt es in der
Wirklichkeit nicht, und das Auge erkennt das sofort, auch wenn niemand
sagen koennte woran. Eingebettetes Rauschen, keine Bilddatei -- kostet
nichts zu laden und kann nicht fehlen.

DIE KACHELN, und zwar BEIDE Systeme:

  workspace  .kachel  -- bekam Tiefe nach unten (fehlte ganz: die Kachel
             klebte auf dem Hintergrund statt darauf zu liegen) und eine
             Lichtkante, die in der Mitte am hellsten ist und nach
             aussen auslaeuft. Echtes Licht auf einer Kante sieht so
             aus; eine durchgehend gleich helle Linie ist ein Strich.

  oeffentlich .card (133 Vorkommen auf der Website) -- war eine Flaeche
             mit einem Rand. Jetzt: Verlauf statt Flaeche, Lichtkante
             oben, Schatten nach unten. Beim Ueberfahren hebt sie sich,
             der Schatten wird laenger, die Kante heller.

Alles bleibt gedeckt. Diese Kacheln stehen zu Dutzenden auf einer Seite
-- was einzeln beeindruckt, blendet im Dutzend.

GEPRUEFT: Buehne 38 (Textkontrast an echten Bildpunkten), Startansicht
133, Rollen 97, Handy 50, Grosscheck 15, Lesbarkeit 14, dazu die drei
Laeufe der oeffentlichen Seite (Startseite, Design, Barrierefreiheit).
Alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-03 02:21:34 +02:00

526 lines
25 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ===================================================================
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). Seit dem 03.09.2026 besteht jedes
Zeichen aus ZWEI Teilen:
fuellung eine gefüllte Grundform -- der Gegenstand selbst,
gedeckt hinterlegt
linien die scharfe Zeichnung darüber
Das ist der Unterschied zwischen einem Symbol und einem Piktogramm.
Eine reine Kontur ist neutral; sobald ein Teil FLÄCHE hat, bekommt
das Zeichen ein Vorn und ein Hinten, und das Auge erkennt es, ohne
es zu lesen. Gefüllt wird immer das, worum es geht: beim Kalender
der Kopf, beim Ordner der Korpus, bei einer Person der Kopf, beim
Regler die Griffe.
WARUM NICHT EINFACH DICKER: Ein früherer Versuch legte eine dicke,
weichgezeichnete Kopie der LINIE darunter. Das hat die feinen
Lücken zugeschmiert -- aus dem Kalender wurde ein leerer Kasten
(siehe start.css). Eine Fläche ist etwas anderes als ein
aufgeblasener Strich: Sie liegt INNERHALB der Kontur und lässt die
Zwischenräume unberührt.
Eigene Pfade statt einer Fremdbibliothek: siebzehn Zeichen sind
kleiner als jede Schriftart und kosten keine Lieferkette. */
const ZEICHEN = {
dashboard: {
/* Zwei der vier Felder gefüllt, über Eck -- das gibt dem Zeichen
einen Rhythmus. Alle vier zu füllen wäre ein Klotz. */
fuellung: ['M4 4.5h6.4v6.4H4z', 'M13.6 11.6h6.4v7.9h-6.4z'],
linien: ['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: {
/* Die mittlere Spalte -- "in Arbeit". Das Brett hat drei Spalten,
und die mittlere ist die, in der gerade etwas passiert. */
fuellung: ['M10 5h4v9h-4z'],
linien: ['M4.5 5h4v14h-4z', 'M10 5h4v9h-4z', 'M15.5 5h4v11.5h-4z'],
},
kalender: {
/* Der Kopf des Blattes. Genau der Streifen, an dem man einen
Kalender auch aus drei Metern erkennt. */
fuellung: ['M3.5 7h17v4.5h-17z'],
linien: ['M3.5 7h17v12.5h-17z', 'M3.5 11.5h17', 'M7.5 4v4.6', 'M16.5 4v4.6'],
},
calls: {
/* Das Objektiv. Der Kasten bleibt offen, sonst wird das Zeichen
schwer. */
fuellung: ['M14.5 11l6-3.5v9l-6-3.5z'],
linien: ['M3.5 7h11v10h-11z', 'M14.5 11l6-3.5v9l-6-3.5z'],
},
dateien: {
/* Der Korpus ohne die Lasche -- so bleibt die Stufe oben sichtbar,
die den Ordner ausmacht. */
fuellung: ['M3.5 10h17v9.5h-17z'],
linien: ['M3.5 6.5h5.5l2 2h9.5v11h-17z', 'M3.5 10h17'],
},
steckbrief: {
/* Kopf und Schultern der Person IN der Karte -- unterscheidbar vom
Profil-Zeichen (nur die Person), damit die beiden Kacheln nicht
gleich aussehen. */
fuellung: ['M8.5 11.2a1.9 1.9 0 1 0 0-3.8 1.9 1.9 0 0 0 0 3.8z'],
linien: ['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: {
fuellung: ['M12 7a3.2 3.2 0 1 0 0 6.4A3.2 3.2 0 0 0 12 7z'],
linien: ['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: {
/* Nur der Haken ist gefüllt -- er ist die Aussage des Zeichens.
Ein gefülltes Klemmbrett wäre ein Kasten. */
fuellung: ['M9.2 9.6l1.7 1.7 3.6-3.7 1 1-4.6 4.7-2.7-2.7z'],
linien: ['M6 4.5h12v15H6z', 'M9.2 9.6l1.7 1.7 3.6-3.7', 'M9.2 15.2h5.6'],
},
live: {
/* Der Sender in der Mitte. Die Wellen bleiben Linien -- gefüllte
Wellen sähen aus wie ein Auge. */
fuellung: ['M12 10.2a1.8 1.8 0 1 0 0 3.6 1.8 1.8 0 0 0 0-3.6z'],
linien: ['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: {
/* Die Klappe der Filmklappe. */
fuellung: ['M3.5 6h17v4h-17z'],
linien: ['M3.5 6h17v13h-17z', 'M3.5 10h17', 'M8 6l-1.4 4', 'M13 6l-1.4 4', 'M18 6l-1.4 4'],
},
technik: {
/* Die drei Griffe. Sie waren bis zum 03.09.2026 Bögen der Länge
null und wurden nie gezeichnet -- übrig blieben drei nackte
Striche, die aussahen wie ein Menü-Symbol. */
fuellung: ['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'],
linien: ['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: {
/* Der vordere Kopf. Der hintere bleibt Kontur -- dadurch entsteht
die Tiefe, um die es bei zwei Personen geht. */
fuellung: ['M9 8.6a2.7 2.7 0 1 0 0 5.4 2.7 2.7 0 0 0 0-5.4z'],
linien: ['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: {
fuellung: ['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'],
linien: ['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: {
/* Aus drei Strichen werden drei Säulen -- ein Balkendiagramm hat
Balken, keine Striche. */
fuellung: ['M6.6 9.5h1.8v7h-1.8z', 'M11.1 5.5h1.8v11h-1.8z', 'M15.6 11.5h1.8v5h-1.8z'],
linien: ['M4 19.5h16', 'M6.6 9.5h1.8v7h-1.8z', 'M11.1 5.5h1.8v11h-1.8z',
'M15.6 11.5h1.8v5h-1.8z'],
},
personen: {
/* Der Bart des Schlüssels bleibt Linie, der Kopf wird Fläche. */
fuellung: ['M14.4 6.2a4 4 0 1 0 0 8 4 4 0 0 0 0-8z'],
linien: ['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: {
/* Der Trichter, aber nur der obere Teil -- der Stiel bleibt offen,
sonst kippt das Zeichen optisch nach unten. */
fuellung: ['M3.5 5.5h17l-6.6 7.6h-3.8z'],
linien: ['M3.5 5.5h17l-6.6 7.6v6.4l-3.8-2.1v-4.3z'],
},
wissen: {
/* Die linke Seite gefüllt: ein aufgeschlagenes Buch hat eine
Seite im Licht und eine im Schatten. */
fuellung: ['M4 5h6.4c.9 0 1.6.7 1.6 1.6V19c0-.9-.7-1.6-1.6-1.6H4z'],
linien: ['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: {
fuellung: ['M13.2 3.2 6 13.4h5.2l-.8 7.4 7.6-10.6h-5.2z'],
linien: ['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-verlaeufe';
/* ---------- Die drei Verläufe ------------------------------------------
Ein Zeichen wird aus drei Lagen aufgebaut, und jede hat ihren
eigenen Verlauf. Alle drei stehen EINMAL im Dokument und arbeiten
mit currentColor -- dadurch nehmen sie den Ton jeder der siebzehn
Kacheln an, ohne dass es einundfünfzig Verläufe braucht.
flaeche die gefüllte Grundform: oben kräftig, unten fast weg.
Das ist der Körper des Gegenstands.
linie die Kontur: oben fast WEISS, unten im Farbton. Genau so
sieht Metall aus, auf das Licht von oben fällt -- und
genau das lässt ein Zeichen plastisch wirken statt
gezeichnet.
glanz ein schmaler heller Streifen quer über die obere Hälfte.
Die Spiegelung. Sie ist der Unterschied zwischen "gut
gemacht" und "das will ich anfassen".
ALLE in Benutzerkoordinaten (userSpaceOnUse) über die festen 24
Einheiten des Rasters. In Objektkoordinaten -- der Vorgabe -- würde
der Verlauf auf den Umriss JEDES einzelnen Pfades gerechnet, und
eine waagerechte Linie hat die Höhe null: Der Verlauf wäre entartet
und der Browser zeichnete den Pfad gar nicht. Genau daran sind am
03.09.2026 die Querlinie im Kalender, die Regler in Technik und die
Grundlinie der Berichte verschwunden. */
function verlaufSicherstellen() {
if (document.getElementById(VERLAUF_ID)) return;
const svg = document.createElementNS(NS, 'svg');
svg.setAttribute('id', VERLAUF_ID);
svg.setAttribute('aria-hidden', 'true');
svg.setAttribute('width', '0');
svg.setAttribute('height', '0');
svg.style.position = 'absolute';
const defs = document.createElementNS(NS, 'defs');
const bauen = (id, stops, x2 = '0', y1 = '2', y2 = '22') => {
const lg = document.createElementNS(NS, 'linearGradient');
lg.setAttribute('id', id);
lg.setAttribute('gradientUnits', 'userSpaceOnUse');
lg.setAttribute('x1', '0'); lg.setAttribute('y1', y1);
lg.setAttribute('x2', x2); lg.setAttribute('y2', y2);
for (const [pos, farbe, deck] of stops) {
const st = document.createElementNS(NS, 'stop');
st.setAttribute('offset', pos);
st.setAttribute('stop-color', farbe);
st.setAttribute('stop-opacity', deck);
lg.append(st);
}
defs.append(lg);
};
/* Der Körper: oben satt, unten fast durchsichtig. */
bauen('zeichen-flaeche', [
['0', 'currentColor', '0.68'],
['0.45', 'currentColor', '0.38'],
['1', 'currentColor', '0.12'],
]);
/* Der Eigenschatten: eine zweite Fuellung, die von unten dunkel
hereinkriecht. Ein Koerper ist unten dunkler als oben -- ohne das
bleibt jede Flaeche eine Farbflaeche. */
bauen('zeichen-schatten', [
['0', '#000000', '0'],
['0.55', '#000000', '0'],
['1', '#000000', '0.45'],
]);
/* Die Kontur: Licht von oben. Oben fast weiss, unten im Farbton --
das ist der Trick, der die Zeichen aus der Fläche hebt. */
/* Die Kontur bekommt ZWEI Lichtquellen -- so wie ein echter
Gegenstand auf einem Tisch:
oben das Hauptlicht, fast weiss
Mitte der Eigenton des Gegenstands
unten STREULICHT, das vom Untergrund zurueckgeworfen wird
Der letzte Stopp ist der Unterschied zwischen "Zeichnung" und
"Ding". Ohne ihn laeuft jede Form nach unten ins Dunkle aus und
sieht aus wie gemalt; mit ihm bekommt sie unten eine Kante, und
das Auge liest sie als Koerper im Raum. */
bauen('zeichen-linie', [
['0', '#ffffff', '0.98'],
['0.38', '#ffffff', '0.78'],
['0.78', 'currentColor', '0.95'],
['1', '#ffffff', '0.42'],
]);
/* Die Spiegelung, diagonal von links oben nach rechts unten. */
bauen('zeichen-glanz', [
['0', '#ffffff', '0.55'],
['0.45', '#ffffff', '0.12'],
['0.7', '#ffffff', '0'],
], '18', '0', '20');
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);
/* Erst die Fläche, dann die Linie -- in dieser Reihenfolge liegt
die Zeichnung oben. Ein Zeichen ohne Füllung (ältere Einträge,
die noch ein reines Feld sind) bekommt einfach keine. */
const eintrag = ZEICHEN[name] || {};
/* Drei Lagen, von hinten nach vorn: Körper, Spiegelung auf dem
Körper, dann die Kontur. Die Spiegelung benutzt dieselben Pfade
wie der Körper -- sie liegt also GENAU auf ihm und nicht daneben. */
const teile = Array.isArray(eintrag)
? [['zeichen__linie', eintrag]]
: [['zeichen__fuellung', eintrag.fuellung || []],
['zeichen__eigenschatten', eintrag.fuellung || []],
['zeichen__glanz', eintrag.fuellung || []],
['zeichen__linie', eintrag.linien || []]];
for (const [lage, pfade] of teile) {
if (!pfade.length) continue;
const g = document.createElementNS(NS, 'g');
g.setAttribute('class', lage);
for (const d of pfade) {
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 };
})();