Drei Ringe, klappbare Gruppen -- und die Calls-Seite endlich wirklich umgebaut
DU HATTEST RECHT (Bildschirmfoto 3). Beim letzten Mal habe ich an der Calls-Seite nur das MATERIAL der Karten getauscht und die Aufstellung gelassen. Drei Gruppen untereinander, und weil "Steht an" 27 Eintraege hat, lagen die beiden anderen ausserhalb des Bildes -- man SAH die Aenderung gar nicht, weil man nie so weit kam. Das war Lackieren, kein Umbauen. JETZT EIN BRETT AUS ZWEI SPALTEN. Die Gruppen sind eigenstaendige Tafeln in einem Raster; "Protokoll fehlt" (kurz, dringend) und "Festgehalten" (Archiv) liegen NEBEN der langen Liste statt darunter. `align-items: start` ist dabei der Punkt: Ohne ihn waeren alle Tafeln so hoch wie die hoechste, und neben der langen Liste stuenden zwei fast leere Kaesten. Welche Tafel wo landet, entscheidet die Breite und nicht das Skript -- eine festgeschriebene Spalte waere eine Zahl, die beim naechsten Fenster falsch ist. Jede Tafel klappt zu, und der Zustand wird gemerkt. Vorgabe: "Festgehalten" ist zu -- es ist das Archiv; wer die Seite oeffnet, will wissen, was ansteht. DIE GRUPPEN AUF DER STARTSEITE genauso. Der Kopf IST der Schalter, nicht ein Dreieck daneben: Die ganze Zeile ist ein Ziel von 40 Pixeln statt eines von vierzehn. <button> statt <div>, damit Tastaturbedienung und Ansage nicht mit tabindex und role nachgebaut werden muessen. Gemerkt wird je Gruppe UND je angesehener Rolle -- DogFather, der sich einen Creator ansieht, hat dort eine andere Aufteilung im Kopf. DIE UHR: drei Ringe statt zwei. Aussen die Stunde in Schwarzsilber, in der Mitte die Minute in Blau, innen die Sekunde in Rot -- von aussen nach innen immer schneller, so liest man eine Uhr ohne nachzudenken. UND SIE IST SCHARF. Kein blur(), kein drop-shadow mehr auf den Boegen -- an der alten lag beides drauf, und der Vorwurf stimmte. Der Glanz kommt jetzt aus dem VERLAUF: Echtes Metall glaenzt nicht, weil es leuchtet, sondern weil es das Licht abwechselnd hell und dunkel zurueckwirft. Fuenf Stopps statt zwei -- ein zweifarbiger Verlauf waere ein Farbverlauf, erst der Wechsel ist Metall. Dazu `shape-rendering="geometricPrecision"` (sonst rastert der Browser duenne Boegen grober) und Kappen auf `butt` statt `round`: Eine runde Kappe steht ueber das Ende hinaus, bei null Sekunden saehe man trotzdem einen Punkt. Minute und Stunde laufen WEICH mit: die Minute bekommt die Sekunden anteilig, die Stunde die Minuten. Ein Minutenring, der einmal pro Minute springt, sieht aus wie eine haengende Anzeige. Gruen: css-klassen (15), call-kategorien (17), start-ansicht (136), handy (59), breiten (23), buehne (38), struktur (32). NOCH OFFEN: der neue Kachelstil fuer die ganze Website und die Rolle "Spicy Media". Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -139,13 +139,51 @@
|
||||
if (!meine.length) continue;
|
||||
|
||||
const abschnitt = el('section', 'gruppe');
|
||||
const kopf = el('div', 'gruppe__kopf');
|
||||
/* Manche Gruppen heißen für einen Creator anders -- siehe GRUPPEN. */
|
||||
const istCreator = zeigt.rolle === 'creator';
|
||||
|
||||
/* ===============================================================
|
||||
JEDE GRUPPE LAESST SICH ZUKLAPPEN (07.09.2026)
|
||||
|
||||
Wunsch Filipe: "diese kategorien soll man auch zu und aufmachen
|
||||
koennen so wie es einem lieb ist gerade."
|
||||
|
||||
DER KOPF IST DER SCHALTER, nicht ein Knopf daneben. Eine
|
||||
Ueberschrift, neben der ein kleines Dreieck sitzt, laedt zum
|
||||
Zielen ein; eine Ueberschrift, die SELBST der Schalter ist,
|
||||
trifft man immer. Deshalb <button> statt <div> -- damit kommt
|
||||
die Tastaturbedienung und die Ansage fuer Vorleseprogramme
|
||||
geschenkt, statt sie mit tabindex und role nachzubauen.
|
||||
|
||||
DER ZUSTAND WIRD GEMERKT. "So wie es einem lieb ist" heisst:
|
||||
Er muss den naechsten Aufruf ueberleben. Gespeichert wird je
|
||||
Gruppe und je ANGESEHENER Rolle -- DogFather, der sich einen
|
||||
Creator ansieht, hat dort eine andere Aufteilung im Kopf als
|
||||
auf seiner eigenen Seite.
|
||||
|
||||
Faellt localStorage aus (privates Fenster, volle Ablage), ist
|
||||
das kein Fehler: Dann steht eben alles offen. Ein Merker, der
|
||||
die Seite mitreisst, waere schlimmer als ein vergessener. */
|
||||
const kopf = el('button', 'gruppe__kopf');
|
||||
kopf.type = 'button';
|
||||
const schluessel = `gruppe:${zeigt.rolle}:${gruppe.name}`;
|
||||
let zu = false;
|
||||
try { zu = localStorage.getItem(schluessel) === 'zu'; } catch { zu = false; }
|
||||
|
||||
kopf.append(el('h2', 'gruppe__name',
|
||||
(istCreator && gruppe.nameCreator) || gruppe.name));
|
||||
kopf.append(el('span', 'gruppe__unter',
|
||||
(istCreator && gruppe.unterCreator) || gruppe.unter));
|
||||
/* Die Zahl sagt, was hinter einer zugeklappten Gruppe steckt --
|
||||
ohne sie klappt man drei Gruppen auf, um zu suchen. */
|
||||
kopf.append(el('span', 'gruppe__zahl', String(meine.length)));
|
||||
const pfeil = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
pfeil.setAttribute('class', 'gruppe__pfeil');
|
||||
pfeil.setAttribute('viewBox', '0 0 24 24');
|
||||
pfeil.setAttribute('aria-hidden', 'true');
|
||||
pfeil.innerHTML = '<path d="m6 9.5 6 6 6-6" fill="none" stroke="currentColor"'
|
||||
+ ' stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>';
|
||||
kopf.append(pfeil);
|
||||
abschnitt.append(kopf);
|
||||
|
||||
const liste = el('ul', 'kacheln');
|
||||
@@ -216,6 +254,23 @@
|
||||
liste.append(li);
|
||||
}
|
||||
abschnitt.append(liste);
|
||||
|
||||
/* Das Aufklappen laeuft ueber ein Merkmal am Abschnitt, nicht ueber
|
||||
`hidden` an der Liste: So kann das CSS den Uebergang zeichnen
|
||||
und den Pfeil drehen, ohne dass das Skript etwas davon wissen
|
||||
muss. */
|
||||
const stand = (istZu) => {
|
||||
abschnitt.dataset.zu = istZu ? 'ja' : 'nein';
|
||||
kopf.setAttribute('aria-expanded', istZu ? 'false' : 'true');
|
||||
liste.hidden = istZu;
|
||||
};
|
||||
stand(zu);
|
||||
kopf.addEventListener('click', () => {
|
||||
zu = !zu;
|
||||
stand(zu);
|
||||
try { localStorage.setItem(schluessel, zu ? 'zu' : 'auf'); } catch { /* egal */ }
|
||||
});
|
||||
|
||||
ziel.append(abschnitt);
|
||||
}
|
||||
/* KEIN eigener Aufruf mehr: kopf.js stellt das Licht einmal fuer das
|
||||
@@ -294,32 +349,57 @@
|
||||
Sekunden weiter. Stattdessen wird jedes Mal bis zur NÄCHSTEN vollen
|
||||
Sekunde gewartet -- die Anzeige bleibt für immer im Takt der
|
||||
Systemuhr. */
|
||||
const UHR_UMFANG = 276.46;
|
||||
/* Drei Umfaenge, ausgerechnet und nicht als Formel im Stil: Aendert
|
||||
jemand einen Radius im HTML, faellt der Ring sofort auf, statt sich
|
||||
stillschweigend zu verrechnen. U = 2 * pi * r */
|
||||
const UMFANG = { stunde: 285.88, minute: 241.90, sekunde: 197.92 }; // r = 45.5 / 38.5 / 31.5
|
||||
|
||||
function uhrStarten() {
|
||||
const zeit = $('uhr-zeit'), sek = $('uhr-sek');
|
||||
const zeiger = $('uhr-zeiger'), minute = $('uhr-minute');
|
||||
if (!zeit || !zeiger) return;
|
||||
const ringe = {
|
||||
stunde: $('uhr-stunde'), minute: $('uhr-minute'), sekunde: $('uhr-sekunde'),
|
||||
};
|
||||
if (!zeit || !ringe.sekunde) return;
|
||||
const p = (n) => String(n).padStart(2, '0');
|
||||
|
||||
const kopf = $('uhr-kopf');
|
||||
/* Voll = kein Versatz. Die Ringe wachsen im Uhrzeigersinn, weil das
|
||||
SVG im Stil um 90 Grad zurueckgedreht ist. */
|
||||
const setze = (welcher, anteil) => {
|
||||
const el = ringe[welcher];
|
||||
if (el) el.style.strokeDashoffset = String(UMFANG[welcher] * (1 - anteil));
|
||||
};
|
||||
|
||||
const takt = () => {
|
||||
const j = new Date();
|
||||
zeit.textContent = `${p(j.getHours())}:${p(j.getMinutes())}`;
|
||||
sek.textContent = p(j.getSeconds());
|
||||
/* Voll = kein Versatz. Der Ring wächst im Uhrzeigersinn, weil das
|
||||
SVG im Stil um 90 Grad zurückgedreht ist. */
|
||||
zeiger.style.strokeDashoffset = String(UHR_UMFANG * (1 - j.getSeconds() / 60));
|
||||
if (minute) minute.style.strokeDashoffset = String(UHR_UMFANG * (1 - j.getMinutes() / 60));
|
||||
/* Der leuchtende Kopf sitzt am ENDE des Sekundenbogens. Er wird um
|
||||
die Mitte gedreht -- 6 Grad je Sekunde. Die Drehung passiert im
|
||||
SVG-Koordinatensystem (0..100), NICHT im Stil: Dort liegt schon
|
||||
die -90-Grad-Drehung des ganzen Rings, und zwei Drehungen an
|
||||
zwei Stellen laufen beim nächsten Umbau auseinander. */
|
||||
if (kopf) kopf.setAttribute('transform', `rotate(${j.getSeconds() * 6} 50 50)`);
|
||||
/* Der volle Zeitpunkt für Vorleseprogramme -- sichtbar steht dort
|
||||
const std = j.getHours(), min = j.getMinutes(), sk = j.getSeconds();
|
||||
zeit.textContent = `${p(std)}:${p(min)}`;
|
||||
sek.textContent = p(sk);
|
||||
|
||||
/* JEDER RING LAEUFT WEICH IN SEINER EIGENEN EINHEIT.
|
||||
|
||||
Die Sekunde springt (sie ist die Anzeige selbst), Minute und
|
||||
Stunde nicht: Ein Minutenring, der einmal pro Minute einen
|
||||
Sprung macht, sieht aus wie eine haengende Anzeige. Er bekommt
|
||||
deshalb die Sekunden anteilig dazu -- und die Stunde die
|
||||
Minuten. Genau das hat Filipe verlangt ("die minuten sollen
|
||||
auch den minuten entsprechen mitlaufen").
|
||||
|
||||
Die Stunde ueber ZWOELF, nicht ueber 24: Ein Zifferblatt hat
|
||||
zwoelf Stunden, und der Ring soll sich wie eines lesen. */
|
||||
setze('sekunde', sk / 60);
|
||||
setze('minute', (min + sk / 60) / 60);
|
||||
setze('stunde', ((std % 12) + min / 60) / 12);
|
||||
|
||||
/* Der volle Zeitpunkt fuer Vorleseprogramme -- sichtbar steht dort
|
||||
nur die Uhrzeit, vorgelesen wird der ganze Satz. */
|
||||
const uhr = $('uhr');
|
||||
if (uhr) uhr.setAttribute('aria-label', `${p(j.getHours())}:${p(j.getMinutes())} Uhr`);
|
||||
if (uhr) uhr.setAttribute('aria-label', `${p(std)}:${p(min)} Uhr`);
|
||||
|
||||
/* KEIN setInterval(1000). Ein fester Takt laeuft mit der Zeit aus
|
||||
dem Tritt (jeder Durchlauf kostet Millisekunden) und
|
||||
ueberspringt dann gelegentlich eine Sekunde. Gewartet wird bis
|
||||
zur naechsten VOLLEN Sekunde -- die Anzeige bleibt fuer immer im
|
||||
Takt der Systemuhr. */
|
||||
setTimeout(takt, 1000 - (Date.now() % 1000) + 8);
|
||||
};
|
||||
takt();
|
||||
|
||||
Reference in New Issue
Block a user