Barrierefreiheit und mobile Darstellung

- Kontrast: gedämpfter Text war mit 3,1:1 unter WCAG AA, jetzt 4,9:1
  (hell) bzw. 6,4:1 (dunkel)
- Sprungmarke „Zum Inhalt springen" in Admin-Shell und Voucher-Seite
- aria-label für alle reinen Icon-Schaltflächen (Theme, Menü, Abmelden,
  Zeilenaktionen), aria-current auf dem aktiven Navigationspunkt,
  role="group" für den Sprachumschalter
- 194 dekorative Icons mit aria-hidden versehen, damit Screenreader sie
  nicht vorlesen
- Toast-Container als aria-live-Bereich ausgezeichnet
- prefers-reduced-motion schaltet Animationen und Übergänge ab

Tabellen (Benutzer, Vouchers, Profile, Audit-Log, Dashboard, API-Keys)
werden unter 720 px zu Karten: die Spaltenüberschrift steht per
data-label vor dem Wert, statt horizontal zu scrollen.

Datums- und Zeitformat in der Voucher-Liste folgen jetzt der gewählten
Sprache statt fest de-DE.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Friederich Loheide 2026-09-23 06:38:08 +00:00
parent 850a04d628
commit 7f1d93debd
21 changed files with 716 additions and 632 deletions

View file

@ -107,15 +107,15 @@ $adminBase = '';
<p class="page-subtitle"><?= __('templates_subtitle') ?></p>
</div>
<button onclick="openAddModal()" class="btn btn-primary">
<i class="fas fa-plus"></i> <?= __('templates_add') ?>
<i class="fas fa-plus" aria-hidden="true"></i> <?= __('templates_add') ?>
</button>
</div>
<?php if ($error): ?>
<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> <?= htmlspecialchars($error) ?></div>
<div class="alert alert-error"><i class="fas fa-exclamation-circle" aria-hidden="true"></i> <?= htmlspecialchars($error) ?></div>
<?php endif; ?>
<?php if ($success): ?>
<div class="alert alert-success"><i class="fas fa-check-circle"></i> <?= htmlspecialchars($success) ?></div>
<div class="alert alert-success"><i class="fas fa-check-circle" aria-hidden="true"></i> <?= htmlspecialchars($success) ?></div>
<?php endif; ?>
<div class="card">
@ -125,15 +125,15 @@ $adminBase = '';
</div>
<?php if (empty($templates)): ?>
<div class="empty-state">
<i class="fas fa-layer-group"></i>
<i class="fas fa-layer-group" aria-hidden="true"></i>
<p style="font-size: 15px; margin-bottom: 8px;"><?= __('templates_none') ?></p>
<p style="font-size: 13px;"><?= __('templates_add_hint') ?></p>
<button onclick="openAddModal()" class="btn btn-primary" style="margin-top: 20px;"><i class="fas fa-plus"></i> <?= __('templates_add') ?></button>
<button onclick="openAddModal()" class="btn btn-primary" style="margin-top: 20px;"><i class="fas fa-plus" aria-hidden="true"></i> <?= __('templates_add') ?></button>
</div>
<?php else: ?>
<div style="overflow-x: auto;">
<div class="table-container">
<table class="table">
<table class="table table-stack">
<thead>
<tr>
<th><?= __('templates_name') ?></th>
@ -147,11 +147,11 @@ $adminBase = '';
<tbody>
<?php foreach ($templates as $t): ?>
<tr>
<td><strong><?= htmlspecialchars($t['name']) ?></strong></td>
<td>
<span class="duration-badge"><i class="fas fa-mobile-alt"></i> <?= (int)$t['max_uses'] ?></span>
<td data-label="<?= __('templates_name') ?>"><strong><?= htmlspecialchars($t['name']) ?></strong></td>
<td data-label="<?= __('templates_devices') ?>">
<span class="duration-badge"><i class="fas fa-mobile-alt" aria-hidden="true"></i> <?= (int)$t['max_uses'] ?></span>
</td>
<td>
<td data-label="<?= __('templates_duration') ?>">
<?php
$m = (int)$t['expire_minutes'];
if ($m >= 1440 && $m % 1440 === 0) {
@ -162,22 +162,22 @@ $adminBase = '';
$durLabel = $m . ' Min.';
}
?>
<span class="duration-badge"><i class="fas fa-clock"></i> <?= $durLabel ?></span>
<span class="duration-badge"><i class="fas fa-clock" aria-hidden="true"></i> <?= $durLabel ?></span>
</td>
<td style="color: var(--text-secondary);"><?= htmlspecialchars($t['description'] ?? '-') ?></td>
<td>
<td data-label="<?= __('templates_desc') ?>" style="color: var(--text-secondary);"><?= htmlspecialchars($t['description'] ?? '-') ?></td>
<td data-label="<?= __('label_status') ?>">
<?php if ($t['is_active']): ?>
<span class="badge badge-success"><?= __('status_active') ?></span>
<?php else: ?>
<span class="badge badge-secondary"><?= __('status_inactive') ?></span>
<?php endif; ?>
</td>
<td>
<td data-label="<?= __('label_actions') ?>">
<button onclick="openEditModal(<?= $t['id'] ?>, '<?= htmlspecialchars($t['name'], ENT_QUOTES) ?>', <?= (int)$t['max_uses'] ?>, <?= (int)$t['expire_minutes'] ?>, '<?= htmlspecialchars($t['description'] ?? '', ENT_QUOTES) ?>', <?= (int)$t['is_active'] ?>, <?= (int)($t['qos_rate_max_down'] ?? 0) ?>, <?= (int)($t['qos_rate_max_up'] ?? 0) ?>, <?= (int)($t['qos_usage_quota'] ?? 0) ?>)"
class="btn btn-secondary btn-small"><i class="fas fa-edit"></i></button>
class="btn btn-secondary btn-small"><i class="fas fa-edit" aria-hidden="true"></i></button>
<a href="?delete=<?= $t['id'] ?>&token=<?= $auth->getCsrfToken() ?>"
onclick="return confirm('<?= __('js_confirm_delete_template') ?>')"
class="btn btn-danger-soft btn-small"><i class="fas fa-trash"></i></a>
class="btn btn-danger-soft btn-small"><i class="fas fa-trash" aria-hidden="true"></i></a>
</td>
</tr>
<?php endforeach; ?>
@ -194,7 +194,7 @@ $adminBase = '';
<div id="addModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title"><i class="fas fa-plus-circle" style="color: var(--accent);"></i> <?= __('templates_add') ?></h2>
<h2 class="modal-title"><i class="fas fa-plus-circle" style="color: var(--accent);" aria-hidden="true"></i> <?= __('templates_add') ?></h2>
<button class="modal-close" onclick="closeModal('addModal')">&times;</button>
</div>
<div class="modal-body">
@ -220,7 +220,7 @@ $adminBase = '';
<div class="form-group"><label>Datenlimit (MB)</label><input type="number" name="qos_usage_quota" min="0" placeholder="0 = unbegrenzt"></div>
</div>
<div style="display:flex;gap:10px;margin-top:20px;">
<button type="submit" name="add_template" class="btn btn-primary" style="flex:1;"><i class="fas fa-save"></i> <?= __('btn_save') ?></button>
<button type="submit" name="add_template" class="btn btn-primary" style="flex:1;"><i class="fas fa-save" aria-hidden="true"></i> <?= __('btn_save') ?></button>
<button type="button" onclick="closeModal('addModal')" class="btn btn-secondary"><?= __('btn_cancel') ?></button>
</div>
</form>
@ -232,7 +232,7 @@ $adminBase = '';
<div id="editModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title"><i class="fas fa-edit" style="color: var(--accent);"></i> <?= __('templates_edit') ?></h2>
<h2 class="modal-title"><i class="fas fa-edit" style="color: var(--accent);" aria-hidden="true"></i> <?= __('templates_edit') ?></h2>
<button class="modal-close" onclick="closeModal('editModal')">&times;</button>
</div>
<div class="modal-body">
@ -261,7 +261,7 @@ $adminBase = '';
<label for="editActive" style="margin:0;"><?= __('status_active') ?></label>
</div>
<div style="display:flex;gap:10px;">
<button type="submit" name="edit_template" class="btn btn-primary" style="flex:1;"><i class="fas fa-save"></i> <?= __('btn_save') ?></button>
<button type="submit" name="edit_template" class="btn btn-primary" style="flex:1;"><i class="fas fa-save" aria-hidden="true"></i> <?= __('btn_save') ?></button>
<button type="button" onclick="closeModal('editModal')" class="btn btn-secondary"><?= __('btn_cancel') ?></button>
</div>
</form>