import { type Bibliothek } from '../../api'; import { icon, type IconName } from '../../icons'; import { dashboard, serverbereich, speicherbereich } from './uebersicht'; import { bibliotheksbereich, vermisstenbereich } from './mediatheken'; import { pruefbereich } from './pruefung'; import { ohneZuordnungBereich, unzugeordnetbereich } from './zuordnung'; import { wiedergabebereich } from './wiedergabe'; import { sprachbereich } from './metadaten'; import { benutzerbereich } from './benutzer'; import { protokollbereich } from './protokolle'; /** Welcher Teil der Verwaltung offen ist. */ export type Bereich = | 'uebersicht' | 'mediatheken' | 'pruefung' | 'zuordnung' | 'wiedergabe' | 'metadaten' | 'benutzer' | 'protokolle'; const BEREICHE: { wert: Bereich; text: string; bild: IconName }[] = [ { wert: 'uebersicht', text: 'Übersicht', bild: 'verwaltung' }, { wert: 'mediatheken', text: 'Mediatheken', bild: 'filme' }, { wert: 'pruefung', text: 'Zu prüfen', bild: 'hakenKreis' }, { wert: 'zuordnung', text: 'Zuordnung', bild: 'suche' }, { wert: 'wiedergabe', text: 'Wiedergabe', bild: 'stufen' }, { wert: 'metadaten', text: 'Metadaten', bild: 'stift' }, { wert: 'benutzer', text: 'Benutzer', bild: 'person' }, { wert: 'protokolle', text: 'Protokolle', bild: 'protokoll' }, ]; /** Macht aus einem Adressteil einen Bereich — Unbekanntes wird zur Übersicht. */ export function alsBereich(wert: string | undefined): Bereich { return BEREICHE.some(b => b.wert === wert) ? wert as Bereich : 'uebersicht'; } /** Die Verwaltung. * * **Was etwas anlegt oder ändert, steht in einem Dialog**, nicht als Block * in der Seite. Ein Formular, das immer dasteht, nimmt Platz für etwas weg, * das man einmal im Monat braucht — und sieht aus wie eine Eingabe, die * noch aussteht. * * **Warum eine zweite Leiste.** Vorher hingen elf Abschnitte untereinander in * einer Seite — 1786 Zeilen, und jede neue Einstellung machte sie länger. Wer * das Protokoll sehen wollte, scrollte an den Mediatheken, der Prüfliste und * dem Speicher vorbei. Jetzt hat jeder Bereich seine eigene Adresse: man kann * ihn als Lesezeichen ablegen, und ein Neuladen bleibt dort stehen. * * **Nur der offene Bereich wird gebaut.** Das ist nicht nur sparsamer — das * Abspielfenster der Übersicht fragt im Takt von fünf Sekunden nach, und die * Mediathekenliste beobachtet laufende Scans. Was nicht dasteht, fragt auch * nicht. * * `geaendert` wird gerufen, wenn sich die Mediathekenliste geändert hat; die * Seitenleiste steht auf ihr und muss dann neu gezeichnet werden. */ export function verwaltung( welcher: Bereich = 'uebersicht', geaendert: (bekannt?: Bibliothek[]) => void = () => {}, signal: AbortSignal = new AbortController().signal, ): HTMLElement { const wurzel = document.createElement('div'); wurzel.className = 'verwaltung'; const leiste = document.createElement('nav'); leiste.className = 'verw-leiste'; leiste.setAttribute('aria-label', 'Bereiche der Verwaltung'); BEREICHE.forEach(b => { const k = document.createElement('button'); k.type = 'button'; k.className = 'verw-eintrag' + (b.wert === welcher ? ' check' : ''); k.appendChild(icon(b.bild)); k.append(document.createTextNode(b.text)); if (b.wert === welcher) k.setAttribute('aria-current', 'page'); k.onclick = () => { location.hash = `#/verwaltung/${b.wert}`; }; leiste.appendChild(k); }); const buehne = document.createElement('div'); buehne.className = 'verw-buehne'; inhalt().forEach(a => buehne.appendChild(a)); wurzel.append(leiste, buehne); return wurzel; function inhalt(): HTMLElement[] { switch (welcher) { case 'mediatheken': return [bibliotheksbereich(geaendert, signal), vermisstenbereich(geaendert)]; case 'pruefung': { // **Die Prüfliste hört auf sich selbst.** Wird etwas freigegeben, // ändert sich der Bestand — und die Liste darüber muss nachziehen. const p = pruefbereich(() => { geaendert(); p.auffrischen(); }); return [p.wurzel]; } case 'zuordnung': return [ohneZuordnungBereich(), unzugeordnetbereich()]; case 'wiedergabe': return [wiedergabebereich()]; case 'metadaten': return [sprachbereich()]; case 'benutzer': return [benutzerbereich()]; case 'protokolle': return [protokollbereich()]; default: return [dashboard(signal), serverbereich(geaendert), speicherbereich()]; } } }