feat(ui): Serverseitig gerenderte Oberflaeche ohne Build-Schritt

Eigenes CSS statt Framework, Vanilla-JavaScript, heller und dunkler
Modus. Ohne JavaScript bleibt alles bedienbar; das Liniendiagramm
faellt auf eine selbst gezeichnete Balkendarstellung zurueck, wenn das
CDN nicht erreichbar ist.

Chart.js ist auf eine Version festgelegt und per Subresource Integrity
an seinen Hash gebunden.

Die Domain-Seite enthaelt eine Schritt-fuer-Schritt-Anleitung fuer DNS,
Hosting-Panel und Zertifikat samt Fehlersuche.
This commit is contained in:
2026-08-03 18:11:40 +02:00
parent 7238e7a937
commit fabaef1f2b
19 changed files with 2378 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
<?php
/**
* @var array<string,mixed>|null $domain
* @var array{base_url:string,label:string,is_default:string} $values
* @var array<string,string> $errors
* @var App\Security\Csrf $csrf
*/
$isEdit = $domain !== null;
$action = $isEdit
? $url('/admin/domains/' . (int) $domain['id'] . '/edit')
: $url('/admin/domains/new');
$isDefault = $isEdit && (int) $domain['is_default'] === 1;
?>
<div class="page-head">
<div>
<h1><?= $isEdit ? 'Domain bearbeiten' : 'Neue Domain' ?></h1>
<?php if ($isEdit): ?>
<p class="muted mono"><?= $e($domain['host']) ?></p>
<?php else: ?>
<p class="muted">Eine weitere Domain, unter der Kurzlinks ausgeliefert werden.</p>
<?php endif; ?>
</div>
<a href="<?= $e($url('/admin/domains')) ?>" class="btn btn--ghost">Zurück zur Liste</a>
</div>
<div class="card card--form">
<form method="post" action="<?= $e($action) ?>" class="form">
<?= $csrf->field() ?>
<div class="field <?= isset($errors['base_url']) ? 'field--error' : '' ?>">
<label for="base_url">Domain <span class="req">*</span></label>
<input type="text" id="base_url" name="base_url" value="<?= $e($values['base_url']) ?>"
placeholder="qr.example.de" required autofocus spellcheck="false" autocapitalize="off">
<p class="field__hint">
Genau so eintragen, wie die Domain im Browser aufgerufen wird. Ohne Schema wird
<code>https://</code> ergänzt – solange noch kein Zertifikat eingerichtet ist,
bitte <code>http://</code> voranstellen. Ein Unterverzeichnis ist erlaubt
(<code>example.de/kurz</code>), ein Port ebenfalls (<code>localhost:8088</code>).
Jede Domain darf nur einmal vorkommen.
</p>
<?php if (isset($errors['base_url'])): ?>
<p class="field__error"><?= $e($errors['base_url']) ?></p>
<?php endif; ?>
</div>
<div class="field">
<label for="label">Bezeichnung (optional)</label>
<input type="text" id="label" name="label" value="<?= $e($values['label']) ?>" maxlength="255"
placeholder="z. B. QR-Codes für Print">
<p class="field__hint">Nur zur eigenen Orientierung in der Auswahlliste.</p>
</div>
<div class="field field--check">
<label class="check">
<input type="checkbox" name="is_default" value="1"
<?= $values['is_default'] === '1' ? 'checked' : '' ?>
<?= $isDefault ? 'disabled' : '' ?>>
<span>Als Standarddomain verwenden</span>
</label>
<?php if ($isDefault): ?>
<input type="hidden" name="is_default" value="1">
<p class="field__hint">Dies ist bereits die Standarddomain.</p>
<?php else: ?>
<p class="field__hint">Die Standarddomain ist im Formular vorausgewählt und fängt Aufrufe
über unbekannte Hostnamen ab.</p>
<?php endif; ?>
</div>
<?php if ($isEdit): ?>
<div class="alert alert--warn">
Wird der Hostname geändert, sind bereits verteilte Links und gedruckte QR-Codes
dieser Domain nicht mehr erreichbar.
</div>
<?php else: ?>
<p class="field__hint">
Damit die Domain auch wirklich hier ankommt, sind noch Einstellungen bei Domain-Anbieter
und Hoster nötig – die
<a href="<?= $e($url('/admin/domains#anleitung')) ?>">Schritt-für-Schritt-Anleitung</a>
steht auf der Domain-Übersicht.
</p>
<?php endif; ?>
<div class="form__actions">
<button type="submit" class="btn btn--primary"><?= $isEdit ? 'Änderungen speichern' : 'Domain anlegen' ?></button>
<a href="<?= $e($url('/admin/domains')) ?>" class="btn btn--ghost">Abbrechen</a>
</div>
</form>
</div>