Chat: sechs Ergaenzungen -- und ein Absturz, den nie jemand gesehen hat
Filipe: "die kategorie chat, boah ich will dass du die wirklich ueberall perfektionierst. wirklich alles was gratis ist und hinzugefuegt werden kann ohne problem will ich drin haben bitte. ich will das es hoch profissionel und ultra krass geil ist." Zuerst Bestand aufgenommen, nicht gebaut: Suche, Ungelesen-Zahlen, die "ab hier neu"-Linie, Lesestand, Live-Strom, Antworten mit Zitat, Zuruecknehmen und Enter-zum-Senden gab es schon. Dazugekommen ist, was gefehlt hat und ohne fremde Bibliothek geht: 1. ADRESSEN SIND ANKLICKBAR. Gebaut als echte Knoten, nie ueber innerHTML -- ein Chat ist die eine Stelle, an der jeder schreiben darf. Erkannt wird bewusst wenig (http, https, www.): Wer mehr erkennt, macht irgendwann aus "z.b." einen Link ins Nichts. Satzzeichen am Ende bleiben beim Satz. rel="noopener noreferrer". 2. KOPIEREN je Nachricht, mit Rueckfall auf "Text markieren", wenn der Browser die Zwischenablage nicht hergibt. 3. DER VERLAUF REISST NIEMANDEN MEHR WEG. Vorher sprang er bei JEDEM Neuzeichnen ans Ende -- wer weiter oben nachlas und dabei eine Nachricht bekam, verlor die Stelle. Jetzt bleibt er stehen, und ein Knopf sagt, WIE VIEL unten wartet, nicht nur DASS etwas da ist. 4. ENTWUERFE JE GESPRAECH. Wer mitten im Satz wechselt, findet ihn wieder. Im localStorage, nicht auf dem Server: Ein Entwurf ist nichts, was jemand anders sehen soll. Abgeschickt heisst geloescht. 5. EMOJI-AUSWAHL, dreissig feste Zeichen, eingefuegt an der Cursorstelle. Am Handy hat die Tastatur sie ohnehin -- am Rechner nicht, und dort sitzt die Betreuung. 6. ZEICHENZAEHLER, sichtbar ab 400 Rest. Die Grenze steht NICHT im Skript, sondern kommt aus dem maxlength des Feldes -- zwei Stellen fuer dieselbe Zahl laufen auseinander. --- DER FUND, um den es eigentlich geht --- Die neue Pruefung hoert auf "pageerror". Damit kam sofort neun Mal dieselbe Meldung: "Cannot set properties of null (setting 'hidden')", raumOeffnen, Zeile 278. Ursache: verlaufZeichnen() leerte den Verlaufskasten mit `textContent = ''`. Darin liegt aber #verlauf-leer, der Absatz "Links ein Gespraech auswaehlen". Nach dem ersten Zeichnen gab es ihn nicht mehr, und raumOeffnen faellt sechs Zeilen weiter darueber. Die Folge ist nicht die Fehlermeldung, sondern der Abbruch: Beim ZWEITEN Aufruf liefen history.replaceState, gelesenMelden() und raeumeZeichnen() nie. Der zweite Aufruf ist der Normalfall -- der Ereignisstrom ruft nach jedem Verbindungsaufbau genau das, um nachzuholen, was waehrend der Pause geschrieben wurde. Dieses Nachholen hat nie funktioniert. Von aussen sah alles normal aus; nur die Konsole wusste Bescheid. Behoben, indem nur noch die Nachrichten entfernt werden und der Absatz stehenbleibt. Abschnitt 8 der Pruefung wechselt jetzt dreimal zwischen zwei Gespraechen OHNE Neuladen und verlangt null Abstuerze. --- UND EIN ZWEITER, der schon laenger drin war --- Abschnitt 9 misst den Kontrast an der wirklichen Flaeche (Text kurz unsichtbar, Flaeche fotografiert). Die Fusszeile jeder Nachricht stand auf --text-still: auf der eigenen Blase 3,68:1, unter den 4,5:1 fuer Text dieser Groesse. Aufgefallen ist es nie, weil niemand nachgemessen hat. Jetzt traegt .chat-nachricht__fuss EINE Farbe (--text-leise, 4,81:1) und Uhrzeit, antworten, zuruecknehmen und kopieren erben sie -- statt vier eigener Angaben, die beim naechsten Mal auseinanderlaufen. --- Pruefung --- server/pruef-chat-ausbau.mjs, neu, 64 Pruefungen, alle gruen. Zu jedem Punkt eine Gegenprobe: kein Link ohne Adresse, keine Auszeichnung aus <b>/<img onerror>, kein Kopier-Knopf an zurueckgenommenen Nachrichten, kein Sprungknopf fuer den, der schon unten steht, kein Entwurf nach dem Abschicken, ein absichtlich zu dunkler Text faellt durch, und ein absichtlich geworfener Fehler wird bemerkt (sonst waere Abschnitt 10 auch gruen, wenn niemand zuhoert). Ausserdem gruen: pruef-css-klassen, pruef-chat, pruef-chat-optik. Angesehen bei 1440 px und bei 390 px. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -321,12 +321,28 @@
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
/* EINE FARBE FÜR DIE GANZE FUSSZEILE — und zwar hier, an einer Stelle.
|
||||
---------------------------------------------------------------------
|
||||
Uhrzeit, "antworten", "zurücknehmen" und "kopieren" standen alle auf
|
||||
var(--text-still) (#7f8fa6). Gemessen (pruef-chat-ausbau, Abschnitt 9)
|
||||
ergibt das auf der eigenen Blase 3,68:1 -- unter den 4,5:1, die für
|
||||
Text dieser Größe gelten. Es ist nie aufgefallen, weil niemand
|
||||
nachgemessen hat; die Blase ist heller als der übrige Grund, und
|
||||
genau dort wird eine leise Farbe zu leise.
|
||||
|
||||
var(--text-leise) (#94a5bb) bringt dieselbe Stelle auf 4,80:1 und
|
||||
bleibt trotzdem deutlich ruhiger als der Nachrichtentext.
|
||||
|
||||
Die Kinder erben sie (color: inherit). Vier eigene Farbangaben wären
|
||||
vier Stellen, die beim nächsten Mal auseinanderlaufen -- der Fehler,
|
||||
der in diesem Haus am häufigsten vorkommt. */
|
||||
.chat-nachricht__fuss {
|
||||
display: flex; align-items: center; gap: 9px;
|
||||
margin-top: 4px;
|
||||
color: var(--text-leise);
|
||||
}
|
||||
.chat-nachricht__zeit {
|
||||
font-size: .75rem; color: var(--text-still);
|
||||
font-size: .75rem; color: inherit;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
/* Der Zurücknehmen-Knopf erscheint erst beim Darüberfahren -- er ist
|
||||
@@ -335,7 +351,7 @@
|
||||
.chat-nachricht__weg-knopf {
|
||||
padding: 0; border: 0; background: none;
|
||||
font: inherit; font-size: .75rem;
|
||||
color: var(--text-still); cursor: pointer;
|
||||
color: inherit; cursor: pointer;
|
||||
opacity: 0; transition: opacity .16s ease, color .16s ease;
|
||||
}
|
||||
.chat-nachricht:hover .chat-nachricht__weg-knopf,
|
||||
@@ -790,7 +806,124 @@
|
||||
.chat-nachricht__antwort-knopf {
|
||||
border: 0; background: none; padding: 0;
|
||||
font: inherit; font-size: .72rem;
|
||||
color: var(--text-still); cursor: pointer;
|
||||
color: inherit; cursor: pointer;
|
||||
text-decoration: underline; text-underline-offset: 2px;
|
||||
}
|
||||
.chat-nachricht__antwort-knopf:hover { color: var(--text-leise); }
|
||||
.chat-nachricht__antwort-knopf:hover { color: var(--text); }
|
||||
|
||||
/* =====================================================================
|
||||
CHAT: SECHS ERGÄNZUNGEN (09.09.2026)
|
||||
|
||||
Filipe: "die kategorie chat, boah ich will dass du die wirklich
|
||||
überall perfektionierst. wirklich alles was gratis ist und
|
||||
hinzugefügt werden kann ohne problem will ich drin haben."
|
||||
|
||||
Alle sechs kommen ohne fremde Bibliothek aus und laden nichts nach:
|
||||
Links, Kopieren, Emoji-Auswahl, Zeichenzähler, ein Bildlauf der nicht
|
||||
mehr wegreisst, und Entwürfe je Gespräch (dafür braucht es kein CSS).
|
||||
===================================================================== */
|
||||
|
||||
/* Ein Link in einer Nachricht ist unterstrichen, nicht farbig -- eine
|
||||
Blase hat schon eine Farbe, und zwei Farben in einer Blase lesen sich
|
||||
wie zwei Sachen. */
|
||||
.chat-nachricht__link {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
text-decoration-color: color-mix(in srgb, currentColor 55%, transparent);
|
||||
word-break: break-word;
|
||||
}
|
||||
.chat-nachricht__link:hover { text-decoration-color: currentColor; }
|
||||
.chat-nachricht__link:focus-visible {
|
||||
outline: 2px solid var(--akzent); outline-offset: 2px; border-radius: 3px;
|
||||
}
|
||||
|
||||
/* Der Kopier-Knopf sieht aus wie "antworten" -- es ist dieselbe Sorte
|
||||
Handgriff an derselben Stelle. Ein anders gestalteter Knopf daneben
|
||||
waere eine zweite Sprache in derselben Zeile. */
|
||||
.chat-nachricht__kopie-knopf {
|
||||
appearance: none; border: 0; background: none; padding: 0;
|
||||
font: inherit; font-size: .72rem; font-weight: 600;
|
||||
color: inherit; cursor: pointer;
|
||||
text-decoration: underline; text-underline-offset: 2px;
|
||||
}
|
||||
.chat-nachricht__kopie-knopf:hover { color: var(--text); }
|
||||
.chat-nachricht__kopie-knopf:focus-visible {
|
||||
outline: 2px solid var(--akzent); outline-offset: 2px; border-radius: 4px;
|
||||
}
|
||||
|
||||
/* ---- Emoji ---------------------------------------------------------- */
|
||||
.chat__emoji {
|
||||
flex: none;
|
||||
width: 40px; height: 40px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
appearance: none; border: 1px solid rgba(150, 186, 220, .18);
|
||||
border-radius: 11px;
|
||||
background: rgba(255, 255, 255, .04);
|
||||
color: var(--text-leise);
|
||||
font-size: 1.15rem; line-height: 1; cursor: pointer;
|
||||
transition: color var(--tempo), border-color var(--tempo);
|
||||
}
|
||||
.chat__emoji:hover { color: var(--text); border-color: rgba(150, 186, 220, .34); }
|
||||
.chat__emoji:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
|
||||
|
||||
/* Die Tafel steht ÜBER der Eingabe, nicht darunter: Darunter läge sie
|
||||
auf dem Handy hinter der Bildschirmtastatur. */
|
||||
.emoji-tafel {
|
||||
position: absolute;
|
||||
right: 14px; bottom: calc(100% - 6px);
|
||||
z-index: 5;
|
||||
display: grid; grid-template-columns: repeat(10, 1fr); gap: 2px;
|
||||
padding: 10px;
|
||||
border-radius: 14px;
|
||||
background: rgba(8, 12, 20, .97);
|
||||
border: 1px solid rgba(150, 186, 220, .2);
|
||||
box-shadow: 0 18px 40px -18px rgba(0, 0, 0, .9);
|
||||
}
|
||||
.emoji-tafel__knopf {
|
||||
appearance: none; border: 0; background: none;
|
||||
width: 34px; height: 34px; border-radius: 8px;
|
||||
font-size: 1.15rem; line-height: 1; cursor: pointer;
|
||||
transition: background var(--tempo);
|
||||
}
|
||||
.emoji-tafel__knopf:hover { background: rgba(255, 255, 255, .1); }
|
||||
.emoji-tafel__knopf:focus-visible { outline: 2px solid var(--akzent); outline-offset: -2px; }
|
||||
|
||||
@media (max-width: 620px) {
|
||||
.emoji-tafel { left: 14px; right: 14px; grid-template-columns: repeat(8, 1fr); }
|
||||
}
|
||||
|
||||
/* ---- Zeichenzähler --------------------------------------------------- */
|
||||
.chat__zeichen {
|
||||
flex: none; align-self: center;
|
||||
font-size: .72rem; font-weight: 700; letter-spacing: .04em;
|
||||
color: var(--text-still);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
/* Eng heisst rot -- aber erst dann. Ein dauerhaft roter Zähler ist eine
|
||||
Warnung, die niemand mehr liest. */
|
||||
.chat__zeichen[data-eng="ja"] { color: var(--warn, #ff9aa2); }
|
||||
|
||||
/* ---- Zum neuesten ---------------------------------------------------- */
|
||||
.chat__zum-neuesten {
|
||||
position: absolute; left: 50%; bottom: 96px;
|
||||
transform: translateX(-50%);
|
||||
z-index: 4;
|
||||
padding: 9px 18px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid color-mix(in srgb, var(--akzent) 40%, transparent);
|
||||
background: rgba(8, 12, 20, .95);
|
||||
color: var(--text);
|
||||
font: inherit; font-size: .8rem; font-weight: 700;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 10px 26px -12px rgba(0, 0, 0, .9);
|
||||
}
|
||||
.chat__zum-neuesten:hover { border-color: var(--akzent); }
|
||||
.chat__zum-neuesten:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.chat__emoji, .emoji-tafel__knopf { transition: none; }
|
||||
}
|
||||
@media (forced-colors: active) {
|
||||
.emoji-tafel, .chat__zum-neuesten { border: 1px solid CanvasText; background: Canvas; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user