--- DAS WICHTIGSTE ZUERST: die Verbergungsregel --- Filipe, ausdruecklich und dringlich: "und noch gaaaaaanz wichtig keiner soll vanvan sehen ausser ich, ueberall soll keiner vanvan sehen ausser dogfather." ES GAB DAVON NUR EINE HAELFTE. In der Personenliste wurde der zweite Admin-Zugang fuer Spicy Media ausgeblendet (Wunsch vom 31.08.). Ueberall sonst -- Chat, Kalender, Aufgaben, Dateien, Zentrale -- war er sichtbar. `sichtbarePersonenIds` hat ihn sogar ausdruecklich JEDER Rolle gezeigt, weil sie alle Admins einsammelt. WORAN DIE BEIDEN AUSEINANDERGEHALTEN WERDEN: In der Datenbank tragen beide die Rolle `admin`, es gibt kein unterscheidendes Feld. Der Unterschied, den es wirklich gibt, ist das Alter -- DogFather ist der erste Zugang. Also: der Admin mit der kleinsten Nummer ist DogFather, alle weiteren sind verborgen. Drei Ausnahmen: DogFather sieht alle, ein verborgener Zugang sieht sich selbst, und bei nur einem Admin gibt es nichts zu verbergen. WARUM AN EINER STELLE UND NICHT IN DEN ABFRAGEN: Allein workspace-personen.js hat 23 Abfragen auf `personen`. Eine Regel, die man 23-mal wiederholt, ist 23 Gelegenheiten, sie zu vergessen -- und beim Vergessen faellt niemand auf die Nase, sondern jemand SIEHT etwas. Die Regel sitzt deshalb in `verborgeneIds()` und wird ueber einen MANTEL um die sechs Listenfunktionen gelegt: Diese haben zusammen achtzehn Rueckgabewege; sie einzeln zu flicken waeren achtzehn Gelegenheiten, einen zu uebersehen. Die ungefilterten Fassungen (`...Roh`) werden nicht mehr exportiert -- niemand kann sie versehentlich benutzen. `null` HIESS BISHER "SIEHT ALLES". Sobald es etwas zu verbergen gibt, gilt das nicht mehr: Die Liste wird ausgeschrieben. Das ist strenger, nicht lockerer. NEUE PRUEFUNG server/pruef-verborgen.mjs -- sechs Personen (darunter ein zweiter Admin), fuenf Schnittstellen, jede Rolle einzeln. Sie hat beim ersten Lauf sofort ein Loch gefunden, das ich sonst nicht bemerkt haette: Die ZENTRALE holt sich das Haus selbst und ging an allen Listenfunktionen vorbei -- Spicy Media sah VanVan dort als Segment im Team-Ring. Und beim Korrigieren der Pruefpfade fiel ein zweites auf: `darfEintragen` im Kalender liess die Leitung JEDEN eintragen, bevor ueberhaupt eine Liste befragt wurde. Eine Sichtbarkeitsregel, die nur beim Lesen gilt und nicht beim Schreiben, hat ein Loch in der Mitte. Die Pruefung hat eine Gegenprobe: Ein Manager MUSS DogFather in derselben Liste sehen -- sonst waere "sieht VanVan nicht" auch dann gruen, wenn die Listen leer zurueckkaemen. --- screen1 Punkt 1: Silber mit Babyblau --- "ich will dass diese farbe gemischt wird mit babyblau." #c7dcf4 statt #d8e0ec -- dieselbe Helligkeit, mit Blaurichtung. Nachgerechnet bleibt der Abstand zur naechsten Rolle bei 0,1790, immer noch weiter als das frueher benutzte Babyblau (0,1349). Gemischt ist es ausserdem SICHTBAR: Die Schiene laeuft von Silber nach Babyblau, und der Glanz traegt beide Toene. Eine Mischung, die man nur im Hexwert findet, ist keine. --- screen1 Punkt 2: das Wasserzeichen --- "soll viel groesser sein und nicht so abgecuttet sondern gut zu sehen sein." NACHGEMESSEN war es auf der Dashboard-Kachel zu 50 Prozent abgeschnitten, und zwar auf DREI Seiten: 36 px ueber dem oberen Rand, 44 rechts, 60 unten -- 220 px Zeichen auf einer 152 px hohen Kachel. UND ES GAB ZUM DRITTEN MAL DIESE WOCHE EINE DOPPELREGEL: 3600 Zeilen unter der sorgfaeltig begruendeten Fassung (156 px bei 0,14) stand eine zweite (118 px bei 0,085) mit derselben Spezifitaet. Sie gewann, und die Begruendung oben war wirkungslos. Am 08.09. hatte ich beim Wasserzeichen schon einmal genau so eine Doppelung gefunden -- und diese hier uebersehen. Jetzt eine Fassung, und die Groesse haengt an der KACHELHOEHE: Ein um 8 Grad gedrehtes Quadrat der Seite S braucht S x 1,129 Platz, also `min(132px, 100% - 30px)`. Nachgemessen 100 Prozent sichtbar statt 50, bei 0,14 statt 0,085 -- die sichtbare Flaeche hat sich verdoppelt. --- screen1 Punkt 3: die Personenliste in einer Kachel --- Die fuenf Rollengruppen standen als fuenf lose Abschnitte frei auf dem Hintergrundbild. Es ist aber EINE Liste mit fuenf Abschnitten. Jetzt eine Sammelkachel aus der Modulliste, mit dunklen Fugen statt Luft -- und dunkler als die Karten darin, wie eine Vitrine. --- screen1 Punkt 4: "Womit meldest du dich an?" --- Der einzige Satz auf der Anmeldeseite, der eine FRAGE stellt, stand als graue Feldbeschriftung da. Jetzt gebuerstetes Metall, ein Anschlag aus drei Kerben in Rot und Babyblau und eine auslaufende Linie -- dieselbe Sprache wie die Typenschilder im Workspace. Rueckfall vollwertig: Faellt `background-clip: text` aus, steht dort heller Text. Geprueft: pruef-verborgen (neu), pruef-rollen, pruef-start-ansicht, pruef-css-klassen, pruef-workspace-seiten, pruef-buehne, pruef-handy, pruef-chat, pruef-kalender -- alle in Ordnung. Co-Authored-By: Claude Opus 5 <[email protected]>
209 lines
9.6 KiB
HTML
209 lines
9.6 KiB
HTML
<!doctype html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||
<title>Chat · Spicy & Dogi</title>
|
||
<meta name="robots" content="noindex, nofollow" />
|
||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||
<!-- Die Farbe der Fensterleiste, wenn der Workspace als App laeuft.
|
||
Stand auf #0674b9 (kraeftiges Blau) und stach damit als einziger
|
||
heller Balken ueber einer durchweg dunklen Seite. Jetzt derselbe
|
||
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
|
||
eine Flaeche sind statt zweier. -->
|
||
<meta name="theme-color" content="#06090f" />
|
||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png" />
|
||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png" />
|
||
<link rel="stylesheet" href="assets/css/gate.css?v=202609090318" />
|
||
<link rel="stylesheet" href="assets/css/start.css?v=202609090318" />
|
||
<!-- aufgaben.css bringt die Dialog- und Formularstile mit (.dialog,
|
||
.neu__zeile, .dialog__knoepfe). Sie stehen dort seit dem
|
||
Aufgabenbrett; sie hierher zu kopieren hiesse, sie an zwei Stellen
|
||
zu pflegen. Dieselbe Lösung nutzen kalender.html und content.html.
|
||
Gemeldet von pruef-css-klassen.mjs, bevor jemand einen ungestylten
|
||
Dialog zu sehen bekam. -->
|
||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609090318" />
|
||
<link rel="stylesheet" href="assets/css/chat.css?v=202609090318" />
|
||
<link rel="stylesheet" href="assets/css/module.css?v=202609090318" />
|
||
</head>
|
||
|
||
<body class="start">
|
||
|
||
<div class="schleier" aria-hidden="true"></div>
|
||
|
||
<header class="kopfleiste">
|
||
<button type="button" class="zurueck-knopf" id="zurueck" hidden>
|
||
<svg class="zurueck-knopf__pfeil" viewBox="0 0 24 24" aria-hidden="true">
|
||
<path d="M14.5 5.5 8 12l6.5 6.5" />
|
||
</svg>
|
||
<span class="zurueck-knopf__text">Zurück</span>
|
||
</button>
|
||
<p class="marke"><span class="marke__text"><a class="zurueck" href="start.html">Creator Workspace</a> · Chat</span></p>
|
||
<div class="kopfleiste__rechts">
|
||
<span class="wer" id="wer">…</span>
|
||
<button type="button" class="abmelden" id="abmelden">Abmelden</button>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="inhalt inhalt--breit chat-seite">
|
||
|
||
<!-- DIE GANZE SEITE IST EINE FLÄCHE, kein Dokument zum Scrollen.
|
||
|
||
Ein Chat ist kein Text, den man von oben nach unten liest --
|
||
man springt zwischen Gesprächen, und das Eingabefeld muss
|
||
immer erreichbar sein, ohne zu suchen. Deshalb: feste Höhe,
|
||
und gescrollt wird nur INNERHALB der beiden Spalten.
|
||
|
||
data-ansicht steuert am Handy, welche Spalte zu sehen ist:
|
||
"liste" oder "verlauf". Am Rechner stehen beide nebeneinander
|
||
und das Merkmal bewirkt nichts. -->
|
||
<div class="chat" id="chat" data-ansicht="liste">
|
||
|
||
<!-- ---------- Links: die Gespräche ---------- -->
|
||
<section class="chat__spalte chat__spalte--liste" aria-labelledby="liste-titel">
|
||
<div class="chat__kopf">
|
||
<h1 class="chat__titel" id="liste-titel">Gespräche</h1>
|
||
<button type="button" class="knopf knopf--klein" id="neu-oeffnen">Neu</button>
|
||
</div>
|
||
|
||
<!-- Suchen erst, wenn es etwas zu suchen gibt (chat.js blendet
|
||
es ab acht Gesprächen ein). Ein Suchfeld über drei Einträgen
|
||
ist Zierde. -->
|
||
<div class="chat__suche" id="suche-zeile" hidden>
|
||
<input type="search" id="suche" placeholder="Name oder Gruppe …"
|
||
aria-label="Gespräche durchsuchen" autocomplete="off" />
|
||
</div>
|
||
|
||
<ul class="chat__liste" id="raeume" aria-live="polite"></ul>
|
||
|
||
<!-- ---------- Fundstellen in Nachrichten (09.09.2026, Punkt 15)
|
||
|
||
Das Suchfeld darueber durchsuchte bisher nur die NAMEN der
|
||
Gespraeche. Das ist die kleinere Haelfte: Was man wirklich
|
||
sucht, ist ein Satz, den jemand vor drei Wochen geschrieben
|
||
hat.
|
||
|
||
Die Fundstellen stehen UNTER der Gespraechsliste und nicht
|
||
an ihrer Stelle -- beides ist eine Antwort auf dieselbe
|
||
Eingabe, und wer nach "Patrick" sucht, will vielleicht das
|
||
Gespraech und vielleicht die Nachricht. Ein Umschalter
|
||
zwischen zwei Ansichten haette ihn zwingen wollen, das
|
||
vorher zu wissen. -->
|
||
<div class="chat-funde" id="funde" hidden>
|
||
<p class="chat-funde__schild" id="funde-schild">In Nachrichten</p>
|
||
<ul class="chat-funde__liste" id="funde-liste"></ul>
|
||
</div>
|
||
|
||
<p class="chat__leer" id="liste-leer" hidden>
|
||
Noch keine Gespräche. Mit <strong>Neu</strong> schreibst du der
|
||
ersten Person.
|
||
</p>
|
||
</section>
|
||
|
||
<!-- ---------- Rechts: der Verlauf ---------- -->
|
||
<section class="chat__spalte chat__spalte--verlauf" aria-labelledby="verlauf-titel">
|
||
|
||
<!-- Der Kopf trägt am Handy den Zurück-Weg zur Liste. -->
|
||
<div class="chat__kopf chat__kopf--verlauf">
|
||
<button type="button" class="chat__zurueck" id="zur-liste" aria-label="Zurück zu den Gesprächen">
|
||
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M14.5 5.5 8 12l6.5 6.5" /></svg>
|
||
</button>
|
||
<div class="chat__kopf-text">
|
||
<h2 class="chat__titel" id="verlauf-titel">Wähle ein Gespräch</h2>
|
||
<p class="chat__unter" id="verlauf-unter"></p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- aria-live="polite": Ein Vorleseprogramm sagt neue Nachrichten
|
||
an, ohne den Nutzer mitten im Satz zu unterbrechen. -->
|
||
<div class="chat__verlauf" id="verlauf" role="log" aria-live="polite" aria-relevant="additions">
|
||
<p class="chat__leer" id="verlauf-leer">
|
||
Links ein Gespräch auswählen – oder mit <strong>Neu</strong> eines anfangen.
|
||
</p>
|
||
</div>
|
||
|
||
<!-- Das Eingabefeld. Ein <form>, damit Enter abschickt, ohne
|
||
dass dafür Code nötig wäre. -->
|
||
<!-- DIE ANTWORTLEISTE (09.09.2026, Punkt 15).
|
||
|
||
Sie steht UEBER dem Eingabefeld und innerhalb desselben
|
||
<form>: So sieht man beim Tippen, worauf man antwortet, und
|
||
kann es mit einem Griff wieder loswerden. Eine Leiste
|
||
ausserhalb waere beim Tippen ausserhalb des Blickfelds.
|
||
|
||
`hidden` als Vorgabe -- sie erscheint erst, wenn wirklich
|
||
auf etwas geantwortet wird. Ein leerer Kasten ueber dem
|
||
Eingabefeld waere jeden Tag im Weg fuer den Fall, dass man
|
||
ihn vielleicht braucht. -->
|
||
<form class="chat__eingabe" id="schreiben" hidden>
|
||
<div class="antwort-leiste" id="antwort-leiste" hidden>
|
||
<span class="antwort-leiste__strich" aria-hidden="true"></span>
|
||
<span class="antwort-leiste__inhalt">
|
||
<span class="antwort-leiste__schild">Antwort an</span>
|
||
<span class="antwort-leiste__von" id="antwort-von"></span>
|
||
<span class="antwort-leiste__text" id="antwort-text"></span>
|
||
</span>
|
||
<button type="button" class="antwort-leiste__weg" id="antwort-weg"
|
||
aria-label="Antwort verwerfen">✕</button>
|
||
</div>
|
||
<label class="chat__eingabe-schild" for="text">Nachricht</label>
|
||
<!-- KURZER PLATZHALTER. Hier stand der Hinweis "Enter schickt,
|
||
Umschalt+Enter macht eine neue Zeile" -- zwei Fehler auf
|
||
einmal: Am Handy brach er auf zwei Zeilen um und schob das
|
||
Feld halb unter den Bildschirmrand, UND er stimmte dort
|
||
nicht: Auf Geräten ohne Tastatur schickt Enter absichtlich
|
||
nicht, sonst käme man nie zu einer zweiten Zeile.
|
||
Die Tastenbelegung steht jetzt im title -- sie ist ein
|
||
Hinweis für Wiederkehrer, keine Aufforderung. -->
|
||
<textarea id="text" rows="1" maxlength="4000"
|
||
placeholder="Nachricht schreiben …"
|
||
title="Enter schickt ab, Umschalt+Enter macht eine neue Zeile"></textarea>
|
||
<button type="submit" class="chat__senden" id="senden" aria-label="Abschicken">
|
||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||
<path d="M4 12l16-7-7 16-2.5-6.5z" />
|
||
</svg>
|
||
</button>
|
||
</form>
|
||
<p class="fehler" id="fehler" role="alert" aria-live="polite"></p>
|
||
</section>
|
||
</div>
|
||
</main>
|
||
|
||
<!-- Neues Gespräch. Beides in einem Dialog: Wer eine Person anklickt,
|
||
schreibt ihr; wer mehrere anhakt, legt eine Gruppe an. Zwei
|
||
getrennte Dialoge hätten die Frage "Einzeln oder Gruppe?" VOR die
|
||
eigentliche Absicht gestellt. -->
|
||
<dialog class="dialog" id="neu-dialog">
|
||
<form method="dialog" id="neu-form" class="neu neu--blank">
|
||
<h2 class="dialog__titel">Neues Gespräch</h2>
|
||
<p class="dialog__unter">
|
||
Eine Person antippen, um ihr zu schreiben. Mehrere auswählen ergibt
|
||
eine Gruppe.
|
||
</p>
|
||
|
||
<div class="chat-wahl" id="partner"></div>
|
||
|
||
<!-- Erscheint erst ab zwei Ausgewählten -- vorher wäre ein
|
||
Gruppenname eine Frage ohne Anlass. -->
|
||
<div class="neu__zeile" id="gruppenname-zeile" hidden>
|
||
<label class="feld-schild" for="gruppenname">Name der Gruppe</label>
|
||
<input id="gruppenname" maxlength="80" placeholder="z. B. Luna & Betreuung" />
|
||
</div>
|
||
|
||
<p class="fehler" id="neu-fehler" role="alert" aria-live="polite"></p>
|
||
|
||
<div class="dialog__knoepfe">
|
||
<button type="submit" class="knopf knopf--klein" id="neu-los" disabled>Schreiben</button>
|
||
<button type="button" class="abmelden" id="neu-zu">Abbrechen</button>
|
||
</div>
|
||
</form>
|
||
</dialog>
|
||
|
||
<script src="assets/js/bereiche.js?v=202609090318"></script>
|
||
<script src="assets/js/wahl.js?v=202609090318" defer></script>
|
||
<script src="assets/js/kopf.js?v=202609090318"></script>
|
||
<script src="assets/js/glocke.js?v=202609090318"></script>
|
||
<script src="assets/js/chat.js?v=202609090318"></script>
|
||
</body>
|
||
</html>
|