Wissen: Kategoriewahl und Filter ohne Systemmenue
Filipe: "wieso sieht das so scheisse aus?" -- zum aufgeklappten Auswahlmenue der Kategorie. Er hat recht, und die Ursache ist dieselbe wie bei der Rollenwahl: Ein AUFGEKLAPPTES <select> laesst sich nicht gestalten. Es kommt vom Betriebssystem, in Windows-Weiss, mitten in einer dunklen Oberflaeche. Bei zwanzig Eintraegen kam dazu, dass man in so einer Liste nichts findet. KATEGORIEWAHL: jetzt dieselben sechs Welten, dieselben Farben und dieselben Symbole wie die Kacheln auf der Seite. Man waehlt aus demselben Regal, in dem man sonst stoebert. Unter der Wahl steht die Beschreibung der gewaehlten Kategorie -- die Zeile, die beim Einsortieren die eigentliche Frage beantwortet. Nichts ist vorausgewaehlt (ausser man laedt aus einer Kategorie heraus hoch). Die stille Vorbelegung war der Grund, warum eine PDF ueber TikTok LIVE Studio unter "TikTok - Grundlagen" landete. FILTER Stufe und Geraet: ebenfalls Schalter statt Menue. Zwei bis vier Werte, die sich nie aendern -- dafuer ein Menue zu oeffnen ist ein Klick zu viel. Der Tag-Filter bleibt bewusst ein Auswahlfeld: Tags wachsen mit dem Bestand, eine Schalterreihe waere irgendwann zwei Zeilen lang. Geprueft: 20 Kategorien in 6 Welten, nichts vorausgewaehlt, Filter setzen die Adresse (?stufe=einsteiger), Handy ohne Ueberlauf, 0 Konsolenfehler. Testeintrag landete unter der gewaehlten Kategorie.
This commit is contained in:
@@ -324,3 +324,88 @@
|
||||
border: 1px solid rgba(95, 201, 154, .3);
|
||||
border-radius: var(--radius-klein);
|
||||
}
|
||||
|
||||
/* ===================================================================
|
||||
Kategoriewahl und Filterschalter (31.08.2026).
|
||||
|
||||
Beides ersetzt ein <select>. Der Grund ist derselbe wie bei der
|
||||
Rollenwahl: Ein AUFGEKLAPPTES Systemmenue laesst sich nicht
|
||||
gestalten -- es kam als weisses Windows-Menue mitten in der dunklen
|
||||
Oberflaeche. Bei zwanzig Kategorien kam dazu, dass man in so einer
|
||||
Liste nichts findet.
|
||||
|
||||
Hier stehen dieselben sechs Welten und dieselben Farben wie auf den
|
||||
Kacheln der Seite: Man waehlt aus demselben Regal, in dem man sonst
|
||||
stoebert.
|
||||
=================================================================== */
|
||||
|
||||
.katwahl { display: grid; gap: 14px; margin-top: 4px; }
|
||||
|
||||
.katwahl__welt { --w: var(--akzent); }
|
||||
.katwahl__welt[data-welt="tiktok"] { --w: #3fbdf5; }
|
||||
.katwahl__welt[data-welt="aufbau"] { --w: #8a76ff; }
|
||||
.katwahl__welt[data-welt="bildton"] { --w: #5fc99a; }
|
||||
.katwahl__welt[data-welt="technik"] { --w: #e8b877; }
|
||||
.katwahl__welt[data-welt="inhalt"] { --w: #e88fb4; }
|
||||
.katwahl__welt[data-welt="hilfe"] { --w: #8e9cb0; }
|
||||
|
||||
.katwahl__weltname {
|
||||
margin: 0 0 6px; font-size: .7rem; font-weight: 700;
|
||||
letter-spacing: .08em; text-transform: uppercase;
|
||||
color: color-mix(in srgb, var(--w) 55%, #ffffff);
|
||||
}
|
||||
.katwahl__reihe { display: flex; gap: 6px; flex-wrap: wrap; }
|
||||
|
||||
.katwahl__knopf {
|
||||
display: inline-flex; align-items: center; gap: 8px;
|
||||
padding: 8px 13px; cursor: pointer; text-align: left;
|
||||
background: linear-gradient(#1a2230, #151c28);
|
||||
border: 1px solid var(--rand); border-radius: 10px;
|
||||
color: var(--text-leise); font: inherit; font-size: .83rem;
|
||||
transition: border-color .16s ease, background .16s ease, color .16s ease;
|
||||
}
|
||||
.katwahl__knopf:hover { color: var(--text); border-color: color-mix(in srgb, var(--w) 45%, transparent); }
|
||||
.katwahl__knopf:focus-visible {
|
||||
outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--w) 32%, transparent);
|
||||
}
|
||||
.katwahl__knopf[data-an="ja"] {
|
||||
color: #fff; font-weight: 600;
|
||||
border-color: color-mix(in srgb, var(--w) 65%, transparent);
|
||||
background: linear-gradient(color-mix(in srgb, var(--w) 20%, #1a2230),
|
||||
color-mix(in srgb, var(--w) 11%, #151c28));
|
||||
box-shadow: 0 4px 14px -9px var(--w);
|
||||
}
|
||||
.katwahl__symbol {
|
||||
width: 17px; height: 17px; flex: none;
|
||||
fill: none; stroke: var(--w); stroke-width: 1.7;
|
||||
stroke-linecap: round; stroke-linejoin: round;
|
||||
}
|
||||
.katwahl__name { white-space: nowrap; }
|
||||
|
||||
/* ---------- Filterschalter ------------------------------------------------ */
|
||||
|
||||
.filterreihe { display: inline-flex; gap: 4px; }
|
||||
.filterreihe__knopf {
|
||||
padding: 7px 12px; cursor: pointer;
|
||||
background: rgba(255, 255, 255, .04);
|
||||
border: 1px solid var(--rand); border-radius: 8px;
|
||||
color: var(--text-still); font: inherit; font-size: .82rem;
|
||||
transition: color .16s ease, border-color .16s ease, background .16s ease;
|
||||
}
|
||||
.filterreihe__knopf:hover { color: var(--text); border-color: rgba(255, 255, 255, .22); }
|
||||
.filterreihe__knopf[data-an="ja"] {
|
||||
color: #fff; font-weight: 600;
|
||||
border-color: rgba(63, 189, 245, .55);
|
||||
background: rgba(63, 189, 245, .16);
|
||||
}
|
||||
.filterreihe__knopf:focus-visible {
|
||||
outline: none; box-shadow: 0 0 0 3px rgba(63, 189, 245, .3);
|
||||
}
|
||||
|
||||
@media (max-width: 620px) {
|
||||
.katwahl__knopf { flex: 1 1 100%; }
|
||||
.filterreihe { flex-wrap: wrap; }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.katwahl__knopf, .filterreihe__knopf { transition: none; }
|
||||
}
|
||||
|
||||
@@ -284,28 +284,44 @@
|
||||
let filterGefuellt = false;
|
||||
function fuelleFilter() {
|
||||
const z = zustand();
|
||||
const setz = (id, eintraege, wert) => {
|
||||
/* Stufe und Geraet als Schalterreihe: zwei bis vier Werte, die sich
|
||||
nie aendern -- dafuer ein Auswahlmenue zu oeffnen ist ein Klick zu
|
||||
viel, und aufgeklappt liesse es sich ohnehin nicht gestalten. */
|
||||
const reihe = (id, eintraege, wert, feldname) => {
|
||||
const f = $(id);
|
||||
f.textContent = '';
|
||||
const alle = document.createElement('option');
|
||||
alle.value = ''; alle.textContent = 'Alle';
|
||||
f.append(alle);
|
||||
for (const [w, name] of eintraege) {
|
||||
const o = document.createElement('option');
|
||||
o.value = w; o.textContent = name;
|
||||
f.append(o);
|
||||
for (const [w, name] of [['', 'Alle'], ...eintraege]) {
|
||||
const b = el('button', 'filterreihe__knopf', name);
|
||||
b.type = 'button';
|
||||
b.setAttribute('role', 'radio');
|
||||
const an = (wert || '') === w;
|
||||
b.setAttribute('aria-checked', an ? 'true' : 'false');
|
||||
if (an) b.dataset.an = 'ja';
|
||||
if (w) b.dataset.wert = w;
|
||||
b.addEventListener('click', () => setzeZustand({ [feldname]: w }));
|
||||
f.append(b);
|
||||
}
|
||||
f.value = wert || '';
|
||||
};
|
||||
setz('f-stufe', Object.entries(aufbau.stufen), z.stufe);
|
||||
setz('f-geraet', [['pc', 'PC'], ['handy', 'Handy']], z.geraet);
|
||||
setz('f-tag', aufbau.tags.map((t) => [t, '#' + t]), z.tag);
|
||||
reihe('f-stufe', Object.entries(aufbau.stufen), z.stufe, 'stufe');
|
||||
reihe('f-geraet', [['pc', 'PC'], ['handy', 'Handy']], z.geraet, 'geraet');
|
||||
|
||||
/* Die Tags wachsen mit dem Bestand -- dafuer bleibt ein Auswahlfeld
|
||||
richtig, eine Schalterreihe waere irgendwann zwei Zeilen lang. */
|
||||
const f = $('f-tag');
|
||||
f.textContent = '';
|
||||
const alle = document.createElement('option');
|
||||
alle.value = ''; alle.textContent = 'Alle';
|
||||
f.append(alle);
|
||||
for (const tg of aufbau.tags) {
|
||||
const o = document.createElement('option');
|
||||
o.value = tg; o.textContent = '#' + tg;
|
||||
f.append(o);
|
||||
}
|
||||
f.value = z.tag || '';
|
||||
$('q').value = z.q;
|
||||
|
||||
if (filterGefuellt) return;
|
||||
filterGefuellt = true;
|
||||
$('f-stufe').addEventListener('change', () => setzeZustand({ stufe: $('f-stufe').value }));
|
||||
$('f-geraet').addEventListener('change', () => setzeZustand({ geraet: $('f-geraet').value }));
|
||||
$('f-tag').addEventListener('change', () => setzeZustand({ tag: $('f-tag').value }));
|
||||
$('f-weg').addEventListener('click', () => setzeZustand({ k: '', q: '', stufe: '', geraet: '', tag: '' }));
|
||||
let warte = null;
|
||||
@@ -317,6 +333,24 @@
|
||||
|
||||
window.addEventListener('popstate', laden_);
|
||||
|
||||
/* ---------- Kategoriewahl ------------------------------------------------ */
|
||||
|
||||
function setzeKategorie(schluessel) {
|
||||
for (const b of document.querySelectorAll('.katwahl__knopf')) {
|
||||
const an = b.dataset.kategorie === schluessel;
|
||||
if (an) b.dataset.an = 'ja'; else delete b.dataset.an;
|
||||
b.setAttribute('aria-checked', an ? 'true' : 'false');
|
||||
}
|
||||
const hinweis = $('n-kat-hinweis');
|
||||
if (hinweis) {
|
||||
const k = aufbau?.kategorien.find((x) => x.schluessel === schluessel);
|
||||
hinweis.textContent = k ? k.beschreibung : 'Noch keine Kategorie gewählt.';
|
||||
}
|
||||
}
|
||||
|
||||
const gewaehlteKategorie = () =>
|
||||
document.querySelector('.katwahl__knopf[data-an="ja"]')?.dataset.kategorie || '';
|
||||
|
||||
/* ---------- Formular ------------------------------------------------------ */
|
||||
|
||||
function formularOeffnen(eintrag) {
|
||||
@@ -335,7 +369,7 @@
|
||||
nicht bewusst aendert, merkt es nicht. Vorbelegt wird nur, wenn
|
||||
man aus EINER Kategorie heraus hochlaedt -- dann ist es eine
|
||||
informierte Annahme, keine geratene. */
|
||||
$('n-kategorie').value = eintrag ? eintrag.kategorie : (zustand().k || '');
|
||||
setzeKategorie(eintrag ? eintrag.kategorie : (zustand().k || ''));
|
||||
$('n-stufe').value = eintrag ? eintrag.stufe : 'einsteiger';
|
||||
$('n-geraet').value = eintrag ? eintrag.geraet : 'egal';
|
||||
$('n-tags').value = eintrag ? eintrag.tags.join(', ') : '';
|
||||
@@ -366,25 +400,32 @@
|
||||
f.append(o);
|
||||
}
|
||||
};
|
||||
/* Nach Welten gruppiert -- dieselbe Gliederung wie auf der Seite.
|
||||
Zwanzig Eintraege in einer flachen Liste findet man nicht. */
|
||||
/* Nach Welten gruppiert -- dieselbe Gliederung und dieselben Farben
|
||||
wie die Kacheln auf der Seite. Man waehlt aus demselben Regal, in
|
||||
dem man sonst stoebert. */
|
||||
const kf = $('n-kategorie');
|
||||
kf.textContent = '';
|
||||
const platzhalter = document.createElement('option');
|
||||
platzhalter.value = '';
|
||||
platzhalter.textContent = '— Kategorie wählen —';
|
||||
platzhalter.disabled = true;
|
||||
kf.append(platzhalter);
|
||||
for (const welt of aufbau.welten) {
|
||||
const gruppe = document.createElement('optgroup');
|
||||
gruppe.label = welt.name;
|
||||
for (const k of aufbau.kategorien.filter((x) => x.welt === welt.schluessel)) {
|
||||
const o = document.createElement('option');
|
||||
o.value = k.schluessel;
|
||||
o.textContent = k.name;
|
||||
gruppe.append(o);
|
||||
const kats = aufbau.kategorien.filter((x) => x.welt === welt.schluessel);
|
||||
if (!kats.length) continue;
|
||||
const gruppe = el('div', 'katwahl__welt');
|
||||
gruppe.dataset.welt = welt.schluessel;
|
||||
gruppe.append(el('p', 'katwahl__weltname', welt.name));
|
||||
const reihe = el('div', 'katwahl__reihe');
|
||||
for (const k of kats) {
|
||||
const b = el('button', 'katwahl__knopf');
|
||||
b.type = 'button';
|
||||
b.dataset.kategorie = k.schluessel;
|
||||
b.setAttribute('role', 'radio');
|
||||
b.setAttribute('aria-checked', 'false');
|
||||
b.title = k.beschreibung;
|
||||
b.append(symbol(k.symbol, 'katwahl__symbol'));
|
||||
b.append(el('span', 'katwahl__name', k.name));
|
||||
b.addEventListener('click', () => setzeKategorie(k.schluessel));
|
||||
reihe.append(b);
|
||||
}
|
||||
if (gruppe.children.length) kf.append(gruppe);
|
||||
gruppe.append(reihe);
|
||||
kf.append(gruppe);
|
||||
}
|
||||
setz('n-stufe', Object.entries(aufbau.stufen));
|
||||
setz('n-geraet', Object.entries(aufbau.geraete));
|
||||
@@ -466,7 +507,7 @@
|
||||
const angaben = {
|
||||
titel: $('n-titel').value.trim(),
|
||||
beschreibung: $('n-beschreibung').value.trim(),
|
||||
kategorie: $('n-kategorie').value,
|
||||
kategorie: gewaehlteKategorie(),
|
||||
stufe: $('n-stufe').value,
|
||||
geraet: $('n-geraet').value,
|
||||
tags: $('n-tags').value,
|
||||
@@ -476,7 +517,8 @@
|
||||
if (angaben.titel.length < 3) { $('n-fehler').textContent = 'Der Titel fehlt.'; return; }
|
||||
if (!angaben.kategorie) {
|
||||
$('n-fehler').textContent = 'Wähle die Kategorie aus, in der die Anleitung stehen soll.';
|
||||
$('n-kategorie').focus();
|
||||
$('n-kategorie').scrollIntoView({ block: 'center', behavior: 'smooth' });
|
||||
$('n-kategorie').querySelector('.katwahl__knopf')?.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user