Personen als Kacheln statt Zeilen
Filipe: "gestalte diese seite auch anders bitte. viel krasser geiler uebersichtlicher." Auf das Angebot, die Rollen als Kacheln statt Zeilen zu bauen: "will ich." Entwurf gezeigt, Antwort: "so live". Eine Person war eine Zeile ueber die volle Breite -- links der Name, darunter fuenf halbe Saetze, rechts die Knoepfe. Gemessen: 1128 x 74 px, eine pro Reihe, mit achthundert Pixeln Luft in der Mitte. Jetzt 368 x 221 px, drei nebeneinander: sechs Creator brauchen zwei Reihen statt sechs. Die Angaben stehen in einem Zahlenband statt als Satzreihe -- aus "offene Aufgaben: 0 · 2 offene Sitzung(en) · betreut 3 Creator" werden Felder mit grosser Zahl und kleinem Wort, in jeder Kachel an derselben Stelle. Man vergleicht zwei Personen mit dem Auge, statt in jeder Zeile an einer anderen Stelle nach derselben Zahl zu suchen. Dazu: "vor 21 Tagen" statt "2026-09-15 00:26" (das genaue Datum bleibt als Titel dran), ein Namenszeichen in der Rollenfarbe mit schmalem Farbstreifen oben, und "gesperrt" als Marke in der Warnfarbe statt als graues Wort zwischen fuenf grauen Woertern. ES FAELLT NICHTS WEG. Name, Rolle, gesperrt, Anmeldung, Aufgaben, Sitzungen, betreute Creator, zugeteilte Scouts, "gehoert zu", die Zustaendigkeitsauswahl und alle Knoepfe -- die Messung prueft das ausdruecklich mit, huebsch und unvollstaendig waere schlechter als vorher. Keine feste Spaltenzahl: "auto-fill" laesst den Browser rechnen, bei 1160 px sind es drei, bei 390 px eine. Eine Zahl waere die sechste Wiederholung desselben Fehlers in diesem Haus. Nebenbei zwei Altlasten: .marke-rolle und .betreuung__schild standen auf 11,2 px, unter der Hausgrenze von 11,5. Mit Gegenprobe belegt, dass das schon vorher so war -- jetzt .75rem. Gemessen: 14 Messungen, 0 Befunde (1765 px und 390 px). Gruen: pruef-personen-kachel (45), pruef-personen-liste, pruef-css-klassen. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+115
-15
@@ -439,23 +439,101 @@ Der Code gilt einmal fuer die `
|
||||
return (teile[0][0] + teile[teile.length - 1][0]).toUpperCase();
|
||||
}
|
||||
|
||||
/* WIE LANGE IST DAS HER? (24.09.2026)
|
||||
|
||||
Dastand "letzte Anmeldung: 2026-09-14 08:12". Das ist eine genaue
|
||||
Angabe und eine schlechte Antwort -- die Frage, die man an eine
|
||||
letzte Anmeldung stellt, lautet "ist der noch dabei?", und dafuer
|
||||
muss man das Datum erst im Kopf gegen heute rechnen. "vor drei
|
||||
Tagen" beantwortet sie sofort.
|
||||
|
||||
Das genaue Datum geht nicht verloren, es steht als Titel dran --
|
||||
wer den Zeitpunkt braucht, faehrt mit der Maus darueber. */
|
||||
function herZeit(iso) {
|
||||
if (!iso) return 'noch nie';
|
||||
const ms = Date.now() - Date.parse(iso);
|
||||
if (!Number.isFinite(ms)) return '—';
|
||||
const min = Math.floor(ms / 60000);
|
||||
if (min < 2) return 'gerade eben';
|
||||
if (min < 60) return `vor ${min} Min.`;
|
||||
const std = Math.floor(min / 60);
|
||||
if (std < 24) return `vor ${std} Std.`;
|
||||
const tage = Math.floor(std / 24);
|
||||
if (tage === 1) return 'gestern';
|
||||
if (tage < 31) return `vor ${tage} Tagen`;
|
||||
const monate = Math.floor(tage / 30.44);
|
||||
if (monate < 12) return `vor ${monate} Mon.`;
|
||||
const jahre = Math.floor(tage / 365);
|
||||
return `vor ${jahre} ${jahre === 1 ? 'Jahr' : 'Jahren'}`;
|
||||
}
|
||||
|
||||
/** Ein Feld im Zahlenband: die Zahl gross, das Wort klein darunter. */
|
||||
function wertFeld(ziel, wert, wort, titel) {
|
||||
const f = el('div', 'person__wert');
|
||||
f.append(el('span', 'person__wert-zahl', String(wert)));
|
||||
f.append(el('span', 'person__wert-wort', wort));
|
||||
if (titel) f.title = titel;
|
||||
ziel.append(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
function zeile(p) {
|
||||
const k = el('div', 'person');
|
||||
k.dataset.aktiv = p.aktiv ? 'ja' : 'nein';
|
||||
/* DIE ROLLENFARBE GEHOERT AN DIE KACHEL, nicht nur an die kleine
|
||||
Marke. In einem Raster sucht das Auge zuerst die Farbe und liest
|
||||
erst danach -- dieselben Rollenfarben, die das Haus ohnehin
|
||||
fuehrt. Alles Weitere macht das CSS. */
|
||||
k.dataset.rolle = p.rolle;
|
||||
|
||||
const links = el('div');
|
||||
links.append(el('div', 'person__name', p.name + (p.id === ich.id ? ' (du)' : '')));
|
||||
const links = el('div', 'person__innen');
|
||||
|
||||
const z = el('div', 'person__zeile');
|
||||
/* ---- Kopf: Zeichen, Name, Rolle ---------------------------------
|
||||
Das Namenszeichen gab es bisher nur in der Ueberschrift einer
|
||||
zugeklappten Gruppe. In der Kachel ist es der Anker, an dem man
|
||||
eine Person wiedererkennt, bevor man den Namen gelesen hat. */
|
||||
const kopf = el('div', 'person__kopf');
|
||||
const zeichen = el('div', 'person__zeichen', initialen(p.name));
|
||||
zeichen.dataset.rolle = p.rolle;
|
||||
zeichen.setAttribute('aria-hidden', 'true');
|
||||
kopf.append(zeichen);
|
||||
|
||||
const wer = el('div', 'person__wer');
|
||||
wer.append(el('div', 'person__name', p.name + (p.id === ich.id ? ' (du)' : '')));
|
||||
const marken = el('div', 'person__marken');
|
||||
const rolle = el('span', 'marke-rolle', ROLLENNAME[p.rolle] || p.rolle);
|
||||
rolle.dataset.rolle = p.rolle;
|
||||
z.append(rolle);
|
||||
if (!p.aktiv) z.append(el('span', null, 'gesperrt'));
|
||||
z.append(el('span', null, `letzte Anmeldung: ${datum(p.letzter_login)}`));
|
||||
z.append(el('span', null, `offene Aufgaben: ${p.offene_aufgaben}`));
|
||||
if (p.sitzungen) z.append(el('span', null, `${p.sitzungen} offene Sitzung(en)`));
|
||||
marken.append(rolle);
|
||||
/* GESPERRT WAR BISHER EIN WORT IN GRAUER SCHRIFT zwischen fuenf
|
||||
anderen grauen Woertern -- auf einer Kachel, die ohnehin blasser
|
||||
ist, hat es niemand gesehen. Jetzt ist es eine Marke in der
|
||||
Warnfarbe. */
|
||||
if (!p.aktiv) {
|
||||
const g = el('span', 'marke-rolle', 'gesperrt');
|
||||
g.dataset.rolle = 'gesperrt';
|
||||
marken.append(g);
|
||||
}
|
||||
wer.append(marken);
|
||||
kopf.append(wer);
|
||||
links.append(kopf);
|
||||
|
||||
/* ---- Das Zahlenband ---------------------------------------------
|
||||
DIESELBEN ANGABEN WIE VORHER, nichts faellt weg -- nur nicht
|
||||
mehr als Reihe halber Saetze ("offene Aufgaben: 7 · 2 offene
|
||||
Sitzung(en) · betreut 3 Creator"). In einem Raster stehen sie
|
||||
damit in jeder Kachel an derselben Stelle: Man vergleicht zwei
|
||||
Personen mit dem Auge, statt in jeder Zeile an einer anderen
|
||||
Stelle nach derselben Zahl zu suchen. */
|
||||
const werte = el('div', 'person__werte');
|
||||
wertFeld(werte, p.offene_aufgaben,
|
||||
p.offene_aufgaben === 1 ? 'Aufgabe' : 'Aufgaben', 'offene Aufgaben');
|
||||
if (p.sitzungen) {
|
||||
wertFeld(werte, p.sitzungen,
|
||||
p.sitzungen === 1 ? 'Sitzung' : 'Sitzungen', 'offene Sitzungen');
|
||||
}
|
||||
if (p.betreut_anzahl) {
|
||||
z.append(el('span', null, `betreut ${p.betreut_anzahl} Creator`));
|
||||
wertFeld(werte, p.betreut_anzahl, 'betreut',
|
||||
`betreut ${p.betreut_anzahl} Creator`);
|
||||
}
|
||||
/* Bei einem Manager: wie viele Scouts an ihm haengen. Ohne diese Zahl
|
||||
muesste man die ganze Liste durchgehen, um zu sehen, ob eine
|
||||
@@ -465,14 +543,25 @@ Der Code gilt einmal fuer die `
|
||||
Element haette eine eigene Klasse gebraucht, die es im Stil nicht
|
||||
gibt, und waere als nackter Text erschienen. */
|
||||
if (p.rolle === 'manager' && p.scouts_anzahl) {
|
||||
z.append(el('span', null,
|
||||
`${p.scouts_anzahl} ${p.scouts_anzahl === 1 ? 'Scout' : 'Scouts'} zugeteilt`));
|
||||
wertFeld(werte, p.scouts_anzahl,
|
||||
p.scouts_anzahl === 1 ? 'Scout' : 'Scouts', 'Scouts zugeteilt');
|
||||
}
|
||||
/* Beim Scout umgekehrt: zu wem er gehoert. */
|
||||
|
||||
/* DIE ZEIT STEHT ALS LETZTES FELD im selben Band. Sie ist keine
|
||||
Zahl und darf deshalb nicht so schreien wie eine -- aber sie
|
||||
gehoert dorthin, wo alles andere ueber diese Person steht. */
|
||||
const zuletzt = el('div', 'person__wert person__wert--zeit');
|
||||
zuletzt.append(el('span', 'person__wert-zahl', herZeit(p.letzter_login)));
|
||||
zuletzt.append(el('span', 'person__wert-wort', 'angemeldet'));
|
||||
zuletzt.title = `letzte Anmeldung: ${datum(p.letzter_login)}`;
|
||||
werte.append(zuletzt);
|
||||
links.append(werte);
|
||||
|
||||
/* Beim Scout: zu wem er gehoert. Das ist keine Zahl, sondern ein
|
||||
Name -- der steht als eigene Zeile unter dem Band. */
|
||||
if (p.rolle === 'scout' && p.manager_name) {
|
||||
z.append(el('span', null, `gehört zu ${p.manager_name}`));
|
||||
links.append(el('div', 'person__bezug', `gehört zu ${p.manager_name}`));
|
||||
}
|
||||
links.append(z);
|
||||
|
||||
/* Zuständigkeit. Steht nur bei Creator und nur dann, wenn es
|
||||
überhaupt einen Scout gibt, dem man sie geben könnte. */
|
||||
@@ -1016,7 +1105,18 @@ Der Code gilt einmal fuer die `
|
||||
});
|
||||
block.append(kopf);
|
||||
|
||||
if (auf) for (const p of abschnitt.drin) block.append(zeile(p));
|
||||
/* DIE KACHELN STEHEN IN EINEM RASTER, nicht untereinander.
|
||||
|
||||
"auto-fill" statt einer festen Spaltenzahl: Wie viele
|
||||
nebeneinander passen, weiss der Browser besser als jede Zahl,
|
||||
die ich hier hinschreiben koennte -- und dieselbe Regel gilt
|
||||
auf dem Handy wie auf 1765 px. Eine feste Zahl waere die
|
||||
sechste Wiederholung desselben Fehlers in diesem Haus. */
|
||||
if (auf) {
|
||||
const raster = el('div', 'gruppe__raster');
|
||||
for (const p of abschnitt.drin) raster.append(zeile(p));
|
||||
block.append(raster);
|
||||
}
|
||||
ziel.append(block);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user