Das Web ist jetzt ein Projekt
Schritt 2 des Plans, fertig. Aus 1700 Zeilen in einer Datei sind zwölf Module geworden: api, prefs, contrast, icons, util, types und die Ansichten für Anmeldung, Startseite, Mediathek, Einstellungen, Kacheln und Player. Alles typgeprüft, und die Prüfung läuft scharf — noUncheckedIndexedAccess inbegriffen. An einer Stelle hat der Compiler mich zu Recht aufgehalten: Object.fromEntries verliert die Typen jedes einzelnen Feldes, und geblieben wäre nur ein doppelter Cast, der die Prüfung stilllegt statt sie zu bestehen. Jetzt steht es ausgeschrieben da. hls.js wird erst beim Abspielen geladen. Es ist größer als der ganze Rest zusammen, und wer nur stöbert, braucht es nie: der Start fällt damit von 632 auf 39 Kilobyte. Geprüft mit einem erfundenen Medienserver dahinter: Seite kommt an, gebaute Dateien werden ausgeliefert, Anfragen gehen weiter, und die Startseite zeichnet Insel, Aufmacher und Reihen. Die einzelne Datei bleibt liegen, bis das Projekt sich bewährt hat. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a04784ca15
commit
3af6c3112f
@@ -0,0 +1,50 @@
|
||||
import { anmelden } from '../api';
|
||||
import { esc } from '../util';
|
||||
|
||||
export function anmeldung(wurzel: HTMLElement, fertig: () => void): void {
|
||||
wurzel.innerHTML = `
|
||||
<form class="login-card" id="login-form">
|
||||
<h1>Flixy</h1>
|
||||
<p class="sub">Deine Mediathek, schöner.</p>
|
||||
<div class="field">
|
||||
<label for="user">Benutzer</label>
|
||||
<input id="user" type="text" autocomplete="username" required>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="pass">Passwort</label>
|
||||
<input id="pass" type="password" autocomplete="current-password">
|
||||
</div>
|
||||
<p class="error" id="login-error"></p>
|
||||
<button class="btn btn-primary" type="submit" id="login-btn">Anmelden</button>
|
||||
<p class="note">
|
||||
Der Zugangsschlüssel bleibt in diesem Browser. Das Passwort geht an
|
||||
deinen eigenen Server und wird nirgends gespeichert.
|
||||
</p>
|
||||
</form>`;
|
||||
|
||||
const form = wurzel.querySelector<HTMLFormElement>('#login-form')!;
|
||||
const knopf = wurzel.querySelector<HTMLButtonElement>('#login-btn')!;
|
||||
const fehler = wurzel.querySelector<HTMLElement>('#login-error')!;
|
||||
|
||||
form.onsubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
knopf.disabled = true;
|
||||
knopf.textContent = 'Verbinde …';
|
||||
fehler.textContent = '';
|
||||
try {
|
||||
await anmelden(
|
||||
wurzel.querySelector<HTMLInputElement>('#user')!.value,
|
||||
wurzel.querySelector<HTMLInputElement>('#pass')!.value,
|
||||
);
|
||||
fertig();
|
||||
} catch (e2) {
|
||||
// Die Serveradresse steht nicht mehr hier, sondern beim Server davor —
|
||||
// deshalb kann sie auch nicht mehr falsch eingetippt sein. Bleibt die
|
||||
// Anmeldung selbst, oder ein Server, der nicht läuft.
|
||||
fehler.textContent = 'Anmeldung fehlgeschlagen: ' + esc((e2 as Error).message);
|
||||
} finally {
|
||||
knopf.disabled = false;
|
||||
knopf.textContent = 'Anmelden';
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user