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:
parent
850a04d628
commit
7f1d93debd
21 changed files with 716 additions and 632 deletions
|
|
@ -105,7 +105,7 @@ $currentPage = 'dashboard';
|
|||
<span id="liveStatus">DB</span>
|
||||
</span>
|
||||
<button onclick="refreshData('live')" class="btn btn-secondary btn-sm" id="refreshBtn">
|
||||
<i class="fas fa-sync-alt"></i> <?= __('dashboard_live_refresh') ?>
|
||||
<i class="fas fa-sync-alt" aria-hidden="true"></i> <?= __('dashboard_live_refresh') ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -114,21 +114,21 @@ $currentPage = 'dashboard';
|
|||
<div class="stat-card">
|
||||
<div class="stat-card-header">
|
||||
<div class="stat-card-title"><?= __('dashboard_active_sites') ?></div>
|
||||
<div class="stat-card-icon info"><i class="fas fa-location-dot"></i></div>
|
||||
<div class="stat-card-icon info"><i class="fas fa-location-dot" aria-hidden="true"></i></div>
|
||||
</div>
|
||||
<div class="stat-card-value"><?= $stats['total_sites'] ?></div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-card-header">
|
||||
<div class="stat-card-title"><?= __('dashboard_users') ?></div>
|
||||
<div class="stat-card-icon accent"><i class="fas fa-users"></i></div>
|
||||
<div class="stat-card-icon accent"><i class="fas fa-users" aria-hidden="true"></i></div>
|
||||
</div>
|
||||
<div class="stat-card-value"><?= $stats['total_users'] ?></div>
|
||||
</div>
|
||||
<div class="stat-card live">
|
||||
<div class="stat-card-header">
|
||||
<div class="stat-card-title"><?= __('dashboard_valid') ?></div>
|
||||
<div class="stat-card-icon success"><i class="fas fa-circle-check"></i></div>
|
||||
<div class="stat-card-icon success"><i class="fas fa-circle-check" aria-hidden="true"></i></div>
|
||||
</div>
|
||||
<div class="stat-card-value valid" id="liveValid"><?= (int)($voucherStats['valid']??0) ?></div>
|
||||
<div class="stat-card-sub" id="subValid"><?= $lastCronSync ? date('H:i', strtotime($lastCronSync)) : __('never') ?></div>
|
||||
|
|
@ -136,21 +136,21 @@ $currentPage = 'dashboard';
|
|||
<div class="stat-card live">
|
||||
<div class="stat-card-header">
|
||||
<div class="stat-card-title"><?= __('dashboard_used') ?></div>
|
||||
<div class="stat-card-icon warning"><i class="fas fa-user-check"></i></div>
|
||||
<div class="stat-card-icon warning"><i class="fas fa-user-check" aria-hidden="true"></i></div>
|
||||
</div>
|
||||
<div class="stat-card-value used" id="liveUsed"><?= (int)($voucherStats['used']??0) ?></div>
|
||||
</div>
|
||||
<div class="stat-card live">
|
||||
<div class="stat-card-header">
|
||||
<div class="stat-card-title"><?= __('dashboard_expired') ?></div>
|
||||
<div class="stat-card-icon danger"><i class="fas fa-circle-xmark"></i></div>
|
||||
<div class="stat-card-icon danger"><i class="fas fa-circle-xmark" aria-hidden="true"></i></div>
|
||||
</div>
|
||||
<div class="stat-card-value expired" id="liveExpired"><?= (int)($voucherStats['expired']??0) ?></div>
|
||||
</div>
|
||||
<div class="stat-card live">
|
||||
<div class="stat-card-header">
|
||||
<div class="stat-card-title"><?= __('dashboard_total') ?></div>
|
||||
<div class="stat-card-icon"><i class="fas fa-ticket"></i></div>
|
||||
<div class="stat-card-icon"><i class="fas fa-ticket" aria-hidden="true"></i></div>
|
||||
</div>
|
||||
<div class="stat-card-value" id="liveTotal"><?= (int)($voucherStats['total']??0) ?></div>
|
||||
</div>
|
||||
|
|
@ -183,9 +183,9 @@ $currentPage = 'dashboard';
|
|||
<?php endforeach; ?>
|
||||
<?php if (empty($sites)): ?>
|
||||
<div class="empty-state" style="grid-column:1/-1;">
|
||||
<div class="empty-icon"><i class="fas fa-location-dot"></i></div>
|
||||
<div class="empty-icon"><i class="fas fa-location-dot" aria-hidden="true"></i></div>
|
||||
<p><?= __('dashboard_no_data') ?></p>
|
||||
<a href="sites.php" class="btn btn-primary" style="margin-top:15px;"><i class="fas fa-plus"></i> <?= __('sites_add') ?></a>
|
||||
<a href="sites.php" class="btn btn-primary" style="margin-top:15px;"><i class="fas fa-plus" aria-hidden="true"></i> <?= __('sites_add') ?></a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
|
@ -204,7 +204,7 @@ $currentPage = 'dashboard';
|
|||
<div class="card-header"><h2 class="card-title"><?= __('dashboard_top_users') ?></h2></div>
|
||||
<div class="card-body">
|
||||
<?php if (empty($topUsers)): ?>
|
||||
<div class="empty-state"><i class="fas fa-users"></i><p><?= __('dashboard_no_data') ?></p></div>
|
||||
<div class="empty-state"><i class="fas fa-users" aria-hidden="true"></i><p><?= __('dashboard_no_data') ?></p></div>
|
||||
<?php else: ?>
|
||||
<ul class="top-users-list">
|
||||
<?php foreach ($topUsers as $u): ?>
|
||||
|
|
@ -225,21 +225,21 @@ $currentPage = 'dashboard';
|
|||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header"><h2 class="card-title"><?= __('dashboard_recent') ?></h2><a href="vouchers.php" class="btn btn-secondary btn-sm"><i class="fas fa-arrow-up-right-from-square"></i> Live</a></div>
|
||||
<div class="card-header"><h2 class="card-title"><?= __('dashboard_recent') ?></h2><a href="vouchers.php" class="btn btn-secondary btn-sm"><i class="fas fa-arrow-up-right-from-square" aria-hidden="true"></i> Live</a></div>
|
||||
<div class="card-body" style="padding:0;">
|
||||
<?php if (empty($recentVouchers)): ?>
|
||||
<div class="empty-state"><i class="fas fa-ticket-alt"></i><p><?= __('dashboard_no_vouchers') ?></p></div>
|
||||
<div class="empty-state"><i class="fas fa-ticket-alt" aria-hidden="true"></i><p><?= __('dashboard_no_vouchers') ?></p></div>
|
||||
<?php else: ?>
|
||||
<div class="table-container">
|
||||
<table class="table">
|
||||
<table class="table table-stack">
|
||||
<thead><tr><th><?= __('label_created') ?></th><th><?= __('label_code') ?></th><th><?= __('label_site') ?></th><th><?= __('label_status') ?></th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($recentVouchers as $v): ?>
|
||||
<tr>
|
||||
<td style="font-size:12px;"><?= date('d.m H:i', strtotime($v['created_at'])) ?></td>
|
||||
<td><code><?= htmlspecialchars($v['voucher_code']) ?></code></td>
|
||||
<td><span class="badge badge-info"><?= htmlspecialchars($v['site_name']??'') ?></span></td>
|
||||
<td>
|
||||
<td data-label="<?= __('label_created') ?>" style="font-size:12px;"><?= date('d.m H:i', strtotime($v['created_at'])) ?></td>
|
||||
<td data-label="<?= __('label_code') ?>"><code><?= htmlspecialchars($v['voucher_code']) ?></code></td>
|
||||
<td data-label="<?= __('label_site') ?>"><span class="badge badge-info"><?= htmlspecialchars($v['site_name']??'') ?></span></td>
|
||||
<td data-label="<?= __('label_status') ?>">
|
||||
<?php $st=$v['status']??'valid'; ?>
|
||||
<span class="badge badge-<?= $st==='valid'?'success':($st==='used'?'warning':'danger') ?>"><?= __('status_'.$st) ?></span>
|
||||
</td>
|
||||
|
|
@ -255,7 +255,7 @@ $currentPage = 'dashboard';
|
|||
|
||||
</main>
|
||||
|
||||
<div id="toast-container"></div>
|
||||
<div id="toast-container" role="status" aria-live="polite"></div>
|
||||
<script src="../assets/global.js"></script>
|
||||
<script>
|
||||
const rootStyles = getComputedStyle(document.documentElement);
|
||||
|
|
@ -302,7 +302,7 @@ async function refreshData(mode='db') {
|
|||
liveBadge.className = 'live-badge loading';
|
||||
liveStatus.textContent = '...';
|
||||
refreshBtn.disabled = true;
|
||||
refreshBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
|
||||
refreshBtn.innerHTML = '<i class="fas fa-spinner fa-spin" aria-hidden="true"></i>';
|
||||
try {
|
||||
const url = `index.php?ajax_stats=1${mode==='live'?'&sync=1':''}`;
|
||||
const result = await fetch(url).then(r=>r.json());
|
||||
|
|
@ -340,7 +340,7 @@ async function refreshData(mode='db') {
|
|||
}
|
||||
isLoading = false;
|
||||
refreshBtn.disabled = false;
|
||||
refreshBtn.innerHTML = '<i class="fas fa-sync-alt"></i> <?= __('dashboard_live_refresh') ?>';
|
||||
refreshBtn.innerHTML = '<i class="fas fa-sync-alt" aria-hidden="true"></i> <?= __('dashboard_live_refresh') ?>';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue