Das Licht folgt dem Zeiger - auf jeder Karte, und der Rand mit
Auf der Startseite gab es einen Lichtfleck unter dem Zeiger. Jetzt auf
JEDER Karte im ganzen Workspace -- und mit zwei Schichten statt einer:
der FLECK ein weicher Schein unter dem Zeiger, in der Farbe des
Bereichs (--ton). Eine Aufgabenkarte leuchtet orange, eine
Kalenderkarte tuerkis.
der RAND eine helle Stelle, die auf der KANTE mitwandert.
Der Rand ist der Teil, der den Unterschied macht. Er entsteht aus einem
Farbverlauf, von dem eine Maske nur den ein Pixel breiten Saum stehen
laesst: zwei Ebenen, eine ueber die Innenflaeche, eine ueber den ganzen
Kasten, und mask-composite: exclude laesst genau die Differenz uebrig --
den Rahmen. Dadurch leuchtet wirklich die Kante an der Stelle, an der
der Zeiger steht, statt eines Rechtecks, das so tut als ob.
Beides steckt in einem eingefuegten <span class="licht">. Ein eigenes
Element statt ::before/::after am Kasten selbst, weil die bei fast
allen Karten schon belegt sind (Akzentstreifen, Wasserzeichen) -- ein
Pseudo-Element doppelt zu benutzen geht nicht, und der Fehler faellt
erst auf, wenn eines von beiden verschwindet.
Kosten: EIN Zuhoerer fuer das ganze Dokument, gedrosselt auf einen
Bildaufbau, passiv angemeldet. Das Licht-Element wird beim ersten
Ueberfahren eingesetzt, nicht beim Laden -- Karten entstehen laufend
neu, wenn Listen sich aktualisieren. Ohne feinen Zeiger (Handy) und bei
"weniger Bewegung" laeuft gar nichts und es wird auch nichts eingefuegt.
pointerout feuert auch beim Wechsel zwischen Kindern INNERHALB einer
Karte. Ohne die Pruefung auf relatedTarget haette das Licht bei jeder
Bewegung ueber ein Wort hinweg geflackert.
DIE ALTE FASSUNG IN start.js IST WEG. Sie stehen zu lassen haette zwei
Zuhoerer auf denselben Bewegungen bedeutet -- doppelte Arbeit bei jedem
Zeigerzucken, und der Fehler waere erst aufgefallen, wenn jemand die
eine geaendert haette und sich nichts tat.
GEPRUEFT AN ECHTEN BILDPUNKTEN, nicht am Quelltext: Der Zeiger wird in
die Mitte einer Kachel gesetzt, dann wird die Helligkeit der Kante
direkt darueber gegen dieselbe Kante an der fernen Ecke gemessen.
Ergebnis 50 gegen 17. Geht die Maske jemals verloren, waere die ganze
Karte eingefaerbt und der Text unlesbar -- das faellt damit sofort auf.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -128,6 +128,97 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ---------- Das Licht folgt dem Zeiger ---------------------------------
|
||||
|
||||
Auf der Startseite gab es das schon, aber nur dort und nur als
|
||||
Lichtfleck. Jetzt auf JEDER Karte im ganzen Workspace -- und mit
|
||||
zwei Schichten:
|
||||
|
||||
der FLECK ein weicher Schein unter dem Zeiger, in der Farbe des
|
||||
Bereichs
|
||||
der RAND eine helle Stelle, die auf der Kante mitwandert
|
||||
|
||||
Der Rand ist der Teil, der den Unterschied macht. Er entsteht aus
|
||||
einem Farbverlauf, von dem eine Maske nur den ein Pixel breiten
|
||||
Saum stehen laesst (mask-composite: exclude). Dadurch leuchtet
|
||||
wirklich die KANTE an der Stelle, an der der Zeiger ist -- nicht
|
||||
ein Rechteck, das so tut als ob.
|
||||
|
||||
Beides steckt in einem eingefuegten <span class="licht">. Ein
|
||||
eigenes Element statt ::before/::after, weil die bei fast allen
|
||||
Karten schon fuer etwas anderes gebraucht werden (Akzentstreifen,
|
||||
Wasserzeichen) -- ein Pseudo-Element doppelt zu belegen geht nicht,
|
||||
und der Fehler faellt erst auf, wenn eines der beiden verschwindet.
|
||||
|
||||
Kosten: EIN Zuhoerer fuer das ganze Dokument, gedrosselt auf einen
|
||||
Bildaufbau. Ohne feinen Zeiger (Handy) und bei "weniger Bewegung"
|
||||
laeuft gar nichts -- dann wird auch kein Element eingefuegt. */
|
||||
|
||||
const LICHT_KARTEN = [
|
||||
'.kachel', '.karte', '.spalte', '.k-anlasskarte', '.k-tag', '.k-wochentag',
|
||||
'.dran__punkt', '.zahl', '.datei', '.person', '.eintrag', '.thema',
|
||||
'.listentag', '.k-listentag', '.steckbrief', '.leer-hinweis', '.block',
|
||||
'.saeule', '.karte-gross', '.kandidat', '.punkt', '.call', '.report',
|
||||
].join(', ');
|
||||
|
||||
window.lichtFolgen = function (wurzel = document) {
|
||||
const feinerZeiger = window.matchMedia('(hover: hover) and (pointer: fine)').matches;
|
||||
const ruhig = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
if (!feinerZeiger || ruhig) return;
|
||||
|
||||
/* Jede Karte bekommt ihr Licht-Element -- einmal. Karten kommen
|
||||
nachtraeglich dazu (Listen werden neu aufgebaut), deshalb wird das
|
||||
beim ersten Ueberfahren nachgeholt statt einmalig beim Laden. */
|
||||
const vorbereiten = (karte) => {
|
||||
if (karte.dataset.lichtBereit) return;
|
||||
karte.dataset.lichtBereit = 'ja';
|
||||
const l = document.createElement('span');
|
||||
l.className = 'licht';
|
||||
l.setAttribute('aria-hidden', 'true');
|
||||
/* Als ERSTES Kind: Bei gleichem Stapelwert gewinnt das spaetere
|
||||
Element -- so liegt aller Inhalt ueber dem Licht. */
|
||||
karte.prepend(l);
|
||||
};
|
||||
|
||||
let warten = false;
|
||||
let letzte = null;
|
||||
|
||||
wurzel.addEventListener('pointermove', (e) => {
|
||||
const karte = e.target.closest?.(LICHT_KARTEN);
|
||||
if (!karte) return;
|
||||
letzte = { karte, x: e.clientX, y: e.clientY };
|
||||
if (warten) return;
|
||||
warten = true;
|
||||
requestAnimationFrame(() => {
|
||||
warten = false;
|
||||
if (!letzte) return;
|
||||
const { karte: k, x, y } = letzte;
|
||||
vorbereiten(k);
|
||||
const r = k.getBoundingClientRect();
|
||||
k.style.setProperty('--mx', ((x - r.left) / r.width * 100).toFixed(1) + '%');
|
||||
k.style.setProperty('--my', ((y - r.top) / r.height * 100).toFixed(1) + '%');
|
||||
k.dataset.licht = 'an';
|
||||
});
|
||||
}, { passive: true });
|
||||
|
||||
/* Beim Verlassen zurueck in die Ruhelage. Ohne das bliebe der Fleck
|
||||
dort stehen, wo der Zeiger die Karte verlassen hat -- und die
|
||||
Karten saehen nach einer Weile alle unterschiedlich beleuchtet
|
||||
aus, ohne dass jemand wuesste, warum. */
|
||||
wurzel.addEventListener('pointerout', (e) => {
|
||||
const karte = e.target.closest?.(LICHT_KARTEN);
|
||||
if (!karte) return;
|
||||
/* pointerout feuert auch beim Wechsel zwischen Kindern INNERHALB
|
||||
derselben Karte. Nur wenn der Zeiger die Karte wirklich
|
||||
verlaesst, wird geloescht -- sonst flackerte das Licht bei jeder
|
||||
Bewegung ueber ein Wort hinweg. */
|
||||
if (karte.contains(e.relatedTarget)) return;
|
||||
karte.removeAttribute('data-licht');
|
||||
karte.style.removeProperty('--mx');
|
||||
karte.style.removeProperty('--my');
|
||||
}, { capture: true, passive: true });
|
||||
};
|
||||
|
||||
/* ---------- Jede Seite trägt Zeichen und Farbe ihrer Kachel -------------
|
||||
|
||||
Auf der Startseite hat jeder Bereich sein eigenes Zeichen und seinen
|
||||
@@ -250,6 +341,10 @@
|
||||
marke.dataset.rang = 'ja';
|
||||
}
|
||||
|
||||
/* Das Licht auf dem ganzen Dokument scharfstellen -- ein Zuhoerer
|
||||
fuer alle Karten, auch fuer die, die erst spaeter dazukommen. */
|
||||
window.lichtFolgen(document);
|
||||
|
||||
/* Die Startseite hat den Knopf gar nicht erst im Dokument -- dort gibt
|
||||
es kein "davor". Deshalb genügt hier die Prüfung, ob er existiert. */
|
||||
const knopf = document.getElementById('zurueck');
|
||||
|
||||
Reference in New Issue
Block a user