mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-07 03:29:19 +02:00
admin: semantic HTML pass — checkbox fieldset, landmarks, dl/dt, autocomplete, inline styles
checkbox-list.php partial:
- Replace outer <div>/<label> with <div>/<span class="admin-row-label"> + inner
<fieldset class="admin-checkbox-group"><legend class="sr-only"> to satisfy
WCAG 1.3.1 (group label for multi-checkbox rows without duplicating visible text)
- Replace <div class="admin-checkbox-list"> with <ul>; each checkbox wrapped in <li>
admin.css:
- Drop .admin-checkbox-list; add .admin-body fieldset.admin-checkbox-group rules
(border/padding reset so it doesn't inherit jury-fieldset box styling)
- Extend form-row label rule to span.admin-row-label
- .admin-inline-form + .admin-inline-form { margin-top:.35rem } replaces inline style
- .admin-input--inline / .admin-select--inline get width:160px (was inline style)
- .admin-tags-count + table th sizing via :has() replaces th inline styles
login.php: wrap content in <main id="main-content"> (missing landmark)
account.php:
- <div class="admin-account-status"> → <dl>; __label <span> → <dt>
- <div class="admin-danger-zone__description"> → <p>
index.php: <div class="admin-maintenance-bar"> → <aside role="status" aria-label="Statut du site">
add.php / edit.php: autocomplete="name" on author field, autocomplete="email" on
contact field (WCAG 1.3.5 / input purpose)
tags.php: all inline style= attributes removed (width, text-align, margin-top,
display:inline); all moved to CSS classes
This commit is contained in:
11
TODO.md
11
TODO.md
@@ -8,3 +8,14 @@ Pending tasks have been split into topic files under [`todo/`](todo/README.md):
|
|||||||
| [todo/02-php-components.md](todo/02-php-components.md) | Form field partials, shared UI partials, controller extraction, backend maintenance |
|
| [todo/02-php-components.md](todo/02-php-components.md) | Form field partials, shared UI partials, controller extraction, backend maintenance |
|
||||||
| [todo/03-system-cache.md](todo/03-system-cache.md) | `system_cache` table, `SystemCache` class, `system.php` refactor |
|
| [todo/03-system-cache.md](todo/03-system-cache.md) | `system_cache` table, `SystemCache` class, `system.php` refactor |
|
||||||
| [todo/04-accessibility.md](todo/04-accessibility.md) | WCAG 2.1 AA — remaining failures grouped by success criterion |
|
| [todo/04-accessibility.md](todo/04-accessibility.md) | WCAG 2.1 AA — remaining failures grouped by success criterion |
|
||||||
|
|
||||||
|
## Recently completed (this session)
|
||||||
|
|
||||||
|
- [x] `checkbox-list.php` — replaced `<div class="admin-checkbox-list">` with `<fieldset class="admin-checkbox-group"><legend class="sr-only">…</legend><ul>` (WCAG 1.3.1 fix)
|
||||||
|
- [x] `admin.css` — replaced `.admin-checkbox-list` with `.admin-body fieldset.admin-checkbox-group > ul` semantic selectors; added `span.admin-row-label` as visible label column counterpart
|
||||||
|
- [x] `login.php` — wrapped content in `<main id="main-content">` landmark
|
||||||
|
- [x] `account.php` — `<div class="admin-account-status">` → `<dl>`; `__row` divs kept; `__label` spans → `<dt>`; `admin-danger-zone__description` div → `<p>`
|
||||||
|
- [x] `index.php` — maintenance bar `<div>` → `<aside role="status" aria-label="Statut du site">`
|
||||||
|
- [x] `add.php` / `edit.php` — `autocomplete="name"` on author field, `autocomplete="email"` on contact field
|
||||||
|
- [x] `tags.php` — all inline `style=` attributes removed; sizing/spacing moved to CSS (`.admin-input--inline`, `.admin-select--inline`, `.admin-inline-form + .admin-inline-form`, `.admin-tags-count`)
|
||||||
|
- [x] Marked already-done items in todo files: stats `<dl>`, `thanks.php` `<section>`, `scope="col"` on both tables, `tfe.php` inline styles, `role="alert"` on flash messages
|
||||||
|
|||||||
@@ -23,15 +23,17 @@ if (empty($_SESSION['csrf_token'])) {
|
|||||||
<?php include APP_ROOT . '/templates/partials/flash-messages.php'; ?>
|
<?php include APP_ROOT . '/templates/partials/flash-messages.php'; ?>
|
||||||
|
|
||||||
<!-- Status info -->
|
<!-- Status info -->
|
||||||
<div class="admin-account-status">
|
<dl class="admin-account-status">
|
||||||
<div class="admin-account-status__row">
|
<div class="admin-account-status__row">
|
||||||
<span class="admin-account-status__label">Authentification PHP</span>
|
<dt class="admin-account-status__label">Authentification PHP</dt>
|
||||||
<?php $badgeType = 'ok'; $badgeValue = $hasPassword; $badgeOkLabel = 'Active'; $badgeWarnLabel = 'Non configurée'; include APP_ROOT . '/templates/partials/status-badge.php'; ?>
|
<dd><?php $badgeType = 'ok'; $badgeValue = $hasPassword; $badgeOkLabel = 'Active'; $badgeWarnLabel = 'Non configurée'; include APP_ROOT . '/templates/partials/status-badge.php'; ?></dd>
|
||||||
</div>
|
</div>
|
||||||
<div class="admin-account-status__row">
|
<div class="admin-account-status__row">
|
||||||
<span class="admin-account-status__label">Fichier de configuration</span>
|
<dt class="admin-account-status__label">Fichier de configuration</dt>
|
||||||
|
<dd>
|
||||||
<code class="admin-account-status__code">config/admin_credentials.php</code>
|
<code class="admin-account-status__code">config/admin_credentials.php</code>
|
||||||
<?php $badgeType = 'ok'; $badgeValue = file_exists($credentialsFile); $badgeOkLabel = 'Présent'; $badgeWarnLabel = 'Absent'; include APP_ROOT . '/templates/partials/status-badge.php'; ?>
|
<?php $badgeType = 'ok'; $badgeValue = file_exists($credentialsFile); $badgeOkLabel = 'Présent'; $badgeWarnLabel = 'Absent'; include APP_ROOT . '/templates/partials/status-badge.php'; ?>
|
||||||
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<?php if (!$hasPassword): ?>
|
<?php if (!$hasPassword): ?>
|
||||||
<p class="admin-account-status__note">
|
<p class="admin-account-status__note">
|
||||||
@@ -39,7 +41,7 @@ if (empty($_SESSION['csrf_token'])) {
|
|||||||
<code>config/admin_credentials.php</code> avec un hash bcrypt.
|
<code>config/admin_credentials.php</code> avec un hash bcrypt.
|
||||||
</p>
|
</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</dl>
|
||||||
|
|
||||||
<!-- Password change form -->
|
<!-- Password change form -->
|
||||||
<h2 class="admin-section-title"><?= $hasPassword ? 'Changer le mot de passe' : 'Définir le mot de passe' ?></h2>
|
<h2 class="admin-section-title"><?= $hasPassword ? 'Changer le mot de passe' : 'Définir le mot de passe' ?></h2>
|
||||||
@@ -86,13 +88,13 @@ if (empty($_SESSION['csrf_token'])) {
|
|||||||
<!-- Danger zone: remove password -->
|
<!-- Danger zone: remove password -->
|
||||||
<h2 class="admin-section-title admin-section-title--danger">Zone de danger</h2>
|
<h2 class="admin-section-title admin-section-title--danger">Zone de danger</h2>
|
||||||
<div class="admin-danger-zone">
|
<div class="admin-danger-zone">
|
||||||
<div class="admin-danger-zone__description">
|
<p class="admin-danger-zone__description">
|
||||||
<strong>Supprimer la configuration du mot de passe PHP</strong><br>
|
<strong>Supprimer la configuration du mot de passe PHP</strong><br>
|
||||||
<small>
|
<small>
|
||||||
Supprime <code>config/admin_credentials.php</code>. L'accès admin
|
Supprime <code>config/admin_credentials.php</code>. L'accès admin
|
||||||
dépendra uniquement de l'authentification nginx Basic Auth si elle est configurée.
|
dépendra uniquement de l'authentification nginx Basic Auth si elle est configurée.
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</p>
|
||||||
<form method="post" action="/admin/actions/account.php"
|
<form method="post" action="/admin/actions/account.php"
|
||||||
onsubmit="return confirm('Supprimer le fichier de mot de passe PHP ? L\'accès admin ne sera protégé que par nginx Basic Auth.')">
|
onsubmit="return confirm('Supprimer le fichier de mot de passe PHP ? L\'accès admin ne sera protégé que par nginx Basic Auth.')">
|
||||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ function wasSelected($key, $value) {
|
|||||||
|
|
||||||
<?php $name = 'titre'; $label = 'Titre :'; $value = old('titre'); $required = true; include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
<?php $name = 'titre'; $label = 'Titre :'; $value = old('titre'); $required = true; include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
||||||
<?php $name = 'subtitle'; $label = 'Sous-titre (si applicable) :'; $value = old('subtitle'); $required = false; include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
<?php $name = 'subtitle'; $label = 'Sous-titre (si applicable) :'; $value = old('subtitle'); $required = false; include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
||||||
<?php $name = 'auteurice'; $label = 'Auteur·ice(s) :'; $value = old('auteurice'); $required = true; include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
<?php $name = 'auteurice'; $label = 'Auteur·ice(s) :'; $value = old('auteurice'); $required = true; $attrs = ['autocomplete' => 'name']; include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
||||||
<?php $name = 'mail'; $label = 'Contact(s) (optionnel) [mail/site/insta/etc.] :'; $value = old('mail'); include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
<?php $name = 'mail'; $label = 'Contact(s) (optionnel) [mail/site/insta/etc.] :'; $value = old('mail'); $attrs = ['autocomplete' => 'email']; include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
||||||
|
|
||||||
<?php require APP_ROOT . '/templates/partials/form/jury-fieldset.php'; ?>
|
<?php require APP_ROOT . '/templates/partials/form/jury-fieldset.php'; ?>
|
||||||
|
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ try {
|
|||||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
||||||
<input type="hidden" name="thesis_id" value="<?= $thesisId ?>">
|
<input type="hidden" name="thesis_id" value="<?= $thesisId ?>">
|
||||||
|
|
||||||
<?php $name = 'auteurice'; $label = 'Auteur·ice(s) :'; $value = htmlspecialchars($thesis['authors']); $required = true; include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
<?php $name = 'auteurice'; $label = 'Auteur·ice(s) :'; $value = htmlspecialchars($thesis['authors']); $required = true; $attrs = ['autocomplete' => 'name']; include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
||||||
<?php $name = 'mail'; $label = 'Contact :'; $value = ''; include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
<?php $name = 'mail'; $label = 'Contact :'; $value = ''; $attrs = ['autocomplete' => 'email']; include APP_ROOT . '/templates/partials/form/text-field.php'; ?>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
$name = 'année'; $label = 'Année :'; $value = htmlspecialchars((string)$thesis['year']); $required = true;
|
$name = 'année'; $label = 'Année :'; $value = htmlspecialchars((string)$thesis['year']); $required = true;
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
<!-- Maintenance mode toggle -->
|
<!-- Maintenance mode toggle -->
|
||||||
<?php $maintenanceOn = file_exists(APP_ROOT . '/storage/maintenance.flag'); ?>
|
<?php $maintenanceOn = file_exists(APP_ROOT . '/storage/maintenance.flag'); ?>
|
||||||
<div class="admin-maintenance-bar <?= $maintenanceOn ? 'admin-maintenance-bar--active' : '' ?>">
|
<aside role="status" class="admin-maintenance-bar <?= $maintenanceOn ? 'admin-maintenance-bar--active' : '' ?>" aria-label="Statut du site">
|
||||||
<?php if ($maintenanceOn): ?>
|
<?php if ($maintenanceOn): ?>
|
||||||
<span>⚠ Mode maintenance <strong>activé</strong> — le site public est inaccessible.</span>
|
<span>⚠ Mode maintenance <strong>activé</strong> — le site public est inaccessible.</span>
|
||||||
<form method="post" action="actions/maintenance.php" style="display:inline;">
|
<form method="post" action="actions/maintenance.php" style="display:inline;">
|
||||||
@@ -90,7 +90,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</aside>
|
||||||
|
|
||||||
<!-- Stats (always reflects full DB, independent of active filters) -->
|
<!-- Stats (always reflects full DB, independent of active filters) -->
|
||||||
<dl class="admin-stats">
|
<dl class="admin-stats">
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ $pageTitle = 'Connexion';
|
|||||||
<?php $isAdmin = true; $bodyClass = 'admin-body'; require_once APP_ROOT . '/templates/head.php'; ?>
|
<?php $isAdmin = true; $bodyClass = 'admin-body'; require_once APP_ROOT . '/templates/head.php'; ?>
|
||||||
<?php include APP_ROOT . '/templates/header.php'; ?>
|
<?php include APP_ROOT . '/templates/header.php'; ?>
|
||||||
|
|
||||||
|
<main id="main-content">
|
||||||
<div class="admin-login-wrap">
|
<div class="admin-login-wrap">
|
||||||
<div class="admin-login-box">
|
<div class="admin-login-box">
|
||||||
<h2>Administration</h2>
|
<h2>Administration</h2>
|
||||||
@@ -43,5 +44,6 @@ $pageTitle = 'Connexion';
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
<?php require_once APP_ROOT . '/templates/admin/footer.php'; ?>
|
<?php require_once APP_ROOT . '/templates/admin/footer.php'; ?>
|
||||||
|
|||||||
@@ -31,16 +31,16 @@ try {
|
|||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col" style="width:40%;">Nom</th>
|
<th scope="col">Nom</th>
|
||||||
<th scope="col" style="width:12%;text-align:center;">TFE associés</th>
|
<th scope="col">TFE associés</th>
|
||||||
<th scope="col" style="width:48%;">Actions</th>
|
<th scope="col">Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($tags as $tag): ?>
|
<?php foreach ($tags as $tag): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?= htmlspecialchars($tag['name']) ?></td>
|
<td><?= htmlspecialchars($tag['name']) ?></td>
|
||||||
<td style="text-align:center;"><?= (int)$tag['thesis_count'] ?></td>
|
<td class="admin-tags-count"><?= (int)$tag['thesis_count'] ?></td>
|
||||||
<td>
|
<td>
|
||||||
<!-- Rename -->
|
<!-- Rename -->
|
||||||
<form method="post" action="actions/tag.php" class="admin-inline-form">
|
<form method="post" action="actions/tag.php" class="admin-inline-form">
|
||||||
@@ -48,16 +48,16 @@ try {
|
|||||||
<input type="hidden" name="action" value="rename">
|
<input type="hidden" name="action" value="rename">
|
||||||
<input type="hidden" name="tag_id" value="<?= (int)$tag['id'] ?>">
|
<input type="hidden" name="tag_id" value="<?= (int)$tag['id'] ?>">
|
||||||
<input class="admin-input--inline" type="text" name="new_name"
|
<input class="admin-input--inline" type="text" name="new_name"
|
||||||
value="<?= htmlspecialchars($tag['name']) ?>" required style="width:160px;">
|
value="<?= htmlspecialchars($tag['name']) ?>" required>
|
||||||
<button type="submit" class="admin-btn admin-btn--sm">Renommer</button>
|
<button type="submit" class="admin-btn admin-btn--sm">Renommer</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!-- Merge into another tag -->
|
<!-- Merge into another tag -->
|
||||||
<form method="post" action="actions/tag.php" class="admin-inline-form" style="margin-top:.35rem;">
|
<form method="post" action="actions/tag.php" class="admin-inline-form">
|
||||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
||||||
<input type="hidden" name="action" value="merge">
|
<input type="hidden" name="action" value="merge">
|
||||||
<input type="hidden" name="source_id" value="<?= (int)$tag['id'] ?>">
|
<input type="hidden" name="source_id" value="<?= (int)$tag['id'] ?>">
|
||||||
<select name="target_id" class="admin-select--inline" style="width:160px;" required>
|
<select name="target_id" class="admin-select--inline" required>
|
||||||
<option value="">— Fusionner dans… —</option>
|
<option value="">— Fusionner dans… —</option>
|
||||||
<?php foreach ($tags as $other): ?>
|
<?php foreach ($tags as $other): ?>
|
||||||
<?php if ($other['id'] !== $tag['id']): ?>
|
<?php if ($other['id'] !== $tag['id']): ?>
|
||||||
@@ -72,7 +72,7 @@ try {
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!-- Delete -->
|
<!-- Delete -->
|
||||||
<form method="post" action="actions/tag.php" class="admin-inline-form" style="margin-top:.35rem;display:inline;">
|
<form method="post" action="actions/tag.php" class="admin-inline-form">
|
||||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
||||||
<input type="hidden" name="action" value="delete">
|
<input type="hidden" name="action" value="delete">
|
||||||
<input type="hidden" name="tag_id" value="<?= (int)$tag['id'] ?>">
|
<input type="hidden" name="tag_id" value="<?= (int)$tag['id'] ?>">
|
||||||
|
|||||||
@@ -54,7 +54,8 @@
|
|||||||
border-bottom: 1px solid var(--border-primary);
|
border-bottom: 1px solid var(--border-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-form > div:not(.admin-submit-wrap) > label {
|
.admin-form > div:not(.admin-submit-wrap) > label,
|
||||||
|
.admin-form > div:not(.admin-submit-wrap) > span.admin-row-label {
|
||||||
font-size: 0.92rem;
|
font-size: 0.92rem;
|
||||||
padding-top: 0.5rem;
|
padding-top: 0.5rem;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
@@ -140,12 +141,28 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checkboxes */
|
/* Checkbox group fieldset (languages, formats)
|
||||||
.admin-checkbox-list {
|
Wraps the <ul> of checkboxes; the visible label is a sibling <span>
|
||||||
|
in the grid row. The <legend> repeats the label text for AT only (sr-only).
|
||||||
|
.admin-body scope ensures this overrides the generic .admin-body fieldset rule. */
|
||||||
|
.admin-body fieldset.admin-checkbox-group {
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-body fieldset.admin-checkbox-group > ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding-top: 0.3rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.35rem;
|
gap: 0.35rem;
|
||||||
padding-top: 0.3rem;
|
}
|
||||||
|
|
||||||
|
.admin-body fieldset.admin-checkbox-group > ul > li {
|
||||||
|
display: contents; /* let the inner label handle layout */
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-checkbox-label {
|
.admin-checkbox-label {
|
||||||
@@ -754,13 +771,26 @@
|
|||||||
.admin-input--inline,
|
.admin-input--inline,
|
||||||
.admin-inline-form input[type="text"] {
|
.admin-inline-form input[type="text"] {
|
||||||
font-size: 0.82rem;
|
font-size: 0.82rem;
|
||||||
|
width: 160px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-select--inline,
|
.admin-select--inline,
|
||||||
.admin-inline-form select {
|
.admin-inline-form select {
|
||||||
font-size: 0.82rem;
|
font-size: 0.82rem;
|
||||||
|
width: 160px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Stack secondary forms (merge, delete) below the rename form */
|
||||||
|
.admin-inline-form + .admin-inline-form {
|
||||||
|
margin-top: 0.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tags table column sizing */
|
||||||
|
.admin-body table:has(.admin-tags-count) th:nth-child(1) { width: 40%; }
|
||||||
|
.admin-body table:has(.admin-tags-count) th:nth-child(2) { width: 12%; }
|
||||||
|
.admin-body table:has(.admin-tags-count) th:nth-child(3) { width: 48%; }
|
||||||
|
.admin-tags-count { text-align: center; }
|
||||||
|
|
||||||
/* ── Banner preview ─────────────────────────────────────────────────────── */
|
/* ── Banner preview ─────────────────────────────────────────────────────── */
|
||||||
.admin-banner-preview img {
|
.admin-banner-preview img {
|
||||||
max-width: 320px;
|
max-width: 320px;
|
||||||
|
|||||||
@@ -2,9 +2,14 @@
|
|||||||
/**
|
/**
|
||||||
* Checkbox list partial — renders a group of checkboxes (e.g. languages, formats).
|
* Checkbox list partial — renders a group of checkboxes (e.g. languages, formats).
|
||||||
*
|
*
|
||||||
|
* The group label uses a visible <span> as the first column (matching other form
|
||||||
|
* rows), while a <fieldset>/<legend> in the second column provides the accessible
|
||||||
|
* grouping required by WCAG 1.3.1. The <legend> is visually hidden (sr-only) to
|
||||||
|
* avoid duplicating the visible label text.
|
||||||
|
*
|
||||||
* Variables consumed:
|
* Variables consumed:
|
||||||
* string $name — input name attribute (will be posted as array: name[])
|
* string $name — input name attribute (will be posted as array: name[])
|
||||||
* string $label — group label (rendered as plain <label>, not associated with any single input)
|
* string $label — group label text
|
||||||
* array $options — each element must have 'id' and 'name' keys
|
* array $options — each element must have 'id' and 'name' keys
|
||||||
* array $checked — array of 'id' values that are currently checked
|
* array $checked — array of 'id' values that are currently checked
|
||||||
*/
|
*/
|
||||||
@@ -12,9 +17,12 @@
|
|||||||
$checked = $checked ?? [];
|
$checked = $checked ?? [];
|
||||||
?>
|
?>
|
||||||
<div>
|
<div>
|
||||||
<label><?= htmlspecialchars($label) ?></label>
|
<span class="admin-row-label"><?= htmlspecialchars($label) ?></span>
|
||||||
<div class="admin-checkbox-list">
|
<fieldset class="admin-checkbox-group">
|
||||||
|
<legend class="sr-only"><?= htmlspecialchars($label) ?></legend>
|
||||||
|
<ul>
|
||||||
<?php foreach ($options as $opt): ?>
|
<?php foreach ($options as $opt): ?>
|
||||||
|
<li>
|
||||||
<label class="admin-checkbox-label">
|
<label class="admin-checkbox-label">
|
||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
name="<?= htmlspecialchars($name) ?>[]"
|
name="<?= htmlspecialchars($name) ?>[]"
|
||||||
@@ -22,8 +30,10 @@ $checked = $checked ?? [];
|
|||||||
<?= in_array((string)$opt['id'], array_map('strval', $checked)) ? 'checked' : '' ?>>
|
<?= in_array((string)$opt['id'], array_map('strval', $checked)) ? 'checked' : '' ?>>
|
||||||
<?= htmlspecialchars($opt['name']) ?>
|
<?= htmlspecialchars($opt['name']) ?>
|
||||||
</label>
|
</label>
|
||||||
|
</li>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</ul>
|
||||||
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
unset($checked);
|
unset($checked);
|
||||||
|
|||||||
@@ -29,29 +29,28 @@
|
|||||||
|
|
||||||
## Scattered inline styles in templates
|
## Scattered inline styles in templates
|
||||||
|
|
||||||
- [ ] `tfe.php` line 146: `style="align-items:start;"` → `.tfe-meta-item--top` in `tfe.css`
|
- [x] `tfe.php` inline styles — already extracted (no `style=` attributes remain in `public/tfe.php`)
|
||||||
- [ ] `tfe.php` lines 148, 170-172, 193: `font-style:italic`, `margin-top:1.5rem`, `font-size:.88rem;color:#666`, `color:#999;font-style:italic` → `.tfe-note-value`, `.tfe-back-link`, `.tfe-restricted` in `tfe.css`
|
|
||||||
- [ ] `admin/edit.php`: multiple `style=` on `.admin-form-row` and banner preview → modifier classes in `admin.css`
|
- [ ] `admin/edit.php`: multiple `style=` on `.admin-form-row` and banner preview → modifier classes in `admin.css`
|
||||||
|
|
||||||
## Admin semantic HTML (sections IX–XVI)
|
## Admin semantic HTML (sections IX–XVI)
|
||||||
|
|
||||||
- [ ] **`add.php`/`edit.php`**: Replace `<div class="admin-form-row">` with CSS grid on `<form>` children (~20 divs in add.php, ~22 in edit.php)
|
- [ ] **`add.php`/`edit.php`**: Replace `<div class="admin-form-row">` with CSS grid on `<form>` children (~20 divs in add.php, ~22 in edit.php)
|
||||||
- [ ] **`add.php`/`edit.php`**: Replace inner wrapper `<div>` in multi-control rows — use `<small>` for hints, remove the wrapper div
|
- [ ] **`add.php`/`edit.php`**: Replace inner wrapper `<div>` in multi-control rows — use `<small>` for hints, remove the wrapper div
|
||||||
- [ ] **`add.php`/`edit.php`**: Replace `<div class="admin-checkbox-list">` with `<ul>`; each `<label class="admin-checkbox-label">` becomes `<li>` containing `<label>`
|
- [x] **`add.php`/`edit.php`**: Replace `<div class="admin-checkbox-list">` with `<ul>`; each `<label class="admin-checkbox-label">` becomes `<li>` containing `<label>`
|
||||||
- [ ] **`add.php`/`edit.php`**: Replace `<div class="admin-submit-wrap">` — remove; apply styles directly to `form > button:last-child`
|
- [ ] **`add.php`/`edit.php`**: Replace `<div class="admin-submit-wrap">` — remove; apply styles directly to `form > button:last-child`
|
||||||
- [ ] **`add.php`/`edit.php`**: Replace `<div class="admin-alert admin-alert--error/--success">` with `<p role="alert">` / `<p role="status">`
|
- [ ] **`add.php`/`edit.php`**: Replace `<div class="admin-alert admin-alert--error/--success">` with `<p role="alert">` / `<p role="status">`
|
||||||
- [ ] **`index.php`**: Replace `<div class="admin-stats">` / `<div class="admin-stat">` children with `<dl>/<dt>/<dd>`
|
- [x] **`index.php`**: Replace `<div class="admin-stats">` / `<div class="admin-stat">` children with `<dl>/<dt>/<dd>`
|
||||||
- [ ] **`index.php`**: Replace `<div class="admin-maintenance-bar">` with `<aside role="status">` or `<p role="status">`
|
- [x] **`index.php`**: Replace `<div class="admin-maintenance-bar">` with `<aside role="status">` or `<p role="status">`
|
||||||
- [x] **`index.php`**: Add `role="toolbar" aria-label="Actions groupées"` to `<div class="admin-bulk-actions">`
|
- [x] **`index.php`**: Add `role="toolbar" aria-label="Actions groupées"` to `<div class="admin-bulk-actions">`
|
||||||
- [ ] **`index.php`**: Add `scope="col"` to all `<th>` cells in the admin table
|
- [x] **`index.php`**: Add `scope="col"` to all `<th>` cells in the admin table
|
||||||
- [ ] **`index.php`**: Add non-colour indicator + `aria-label="Statut : …"` to status badge `<span>` elements
|
- [ ] **`index.php`**: Add non-colour indicator + `aria-label="Statut : …"` to status badge `<span>` elements
|
||||||
- [ ] **`tags.php`**: Add `scope="col"` to `<th>` cells
|
- [x] **`tags.php`**: Add `scope="col"` to `<th>` cells
|
||||||
- [ ] **`tags.php`**: Move inline `style="margin-top:.35rem;"` on forms → `.admin-inline-form + .admin-inline-form` selector
|
- [x] **`tags.php`**: Move inline `style="margin-top:.35rem;"` on forms → `.admin-inline-form + .admin-inline-form` selector
|
||||||
- [ ] **`thanks.php`**: Replace `<div class="admin-thesis-info">` with `<section>` + `<h2>` heading; CSS targets `main > section`
|
- [x] **`thanks.php`**: Replace `<div class="admin-thesis-info">` with `<section>` + `<h2>` heading; CSS targets `main > section`
|
||||||
- [ ] **`account.php`**: Replace `<div class="admin-account-status">` with `<dl>`; `__row` → `<div>`, `__label` → `<dt>`
|
- [x] **`account.php`**: Replace `<div class="admin-account-status">` with `<dl>`; `__row` → `<div>`, `__label` → `<dt>`
|
||||||
- [ ] **`account.php`**: Replace `<div class="admin-danger-zone__description">` with `<p>`
|
- [x] **`account.php`**: Replace `<div class="admin-danger-zone__description">` with `<p>`
|
||||||
- [ ] **`account.php`**: Move `style="margin-top:3rem;"` on danger zone heading → CSS modifier class
|
- [x] **`account.php`**: Move `style="margin-top:3rem;"` on danger zone heading → CSS modifier class
|
||||||
- [ ] **`login.php`**: Wrap login content in `<main>` (currently no main landmark)
|
- [x] **`login.php`**: Wrap login content in `<main>` (currently no main landmark)
|
||||||
- [ ] **`login.php`**: Extract inline styles on `.admin-form-row` and `.admin-submit-wrap` → `.admin-form-row--compact` modifier in `admin.css`
|
- [ ] **`login.php`**: Extract inline styles on `.admin-form-row` and `.admin-submit-wrap` → `.admin-form-row--compact` modifier in `admin.css`
|
||||||
|
|
||||||
## Favicon
|
## Favicon
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
|
|
||||||
## 1.3.1 Info and relationships
|
## 1.3.1 Info and relationships
|
||||||
|
|
||||||
- [ ] **Admin form rows: multi-input rows (languages, formats)** — `<label class="admin-label">` without `for` labels a group of checkboxes; replace with `<fieldset>/<legend>`
|
- [x] **Admin form rows: multi-input rows (languages, formats)** — `checkbox-list.php` partial now wraps checkboxes in `<fieldset class="admin-checkbox-group">` with a `<legend class="sr-only">` for AT grouping
|
||||||
|
|
||||||
- [ ] **Status badges in `admin/index.php` convey state by colour alone** — add visible non-colour distinction (prefix icon with `aria-hidden="true"`) and `aria-label="Statut : Publié"` on badge `<span>`
|
- [ ] **Status badges in `admin/index.php` convey state by colour alone** — add visible non-colour distinction (prefix icon with `aria-hidden="true"`) and `aria-label="Statut : Publié"` on badge `<span>`
|
||||||
|
|
||||||
## 1.3.4 / 1.3.5 Orientation & Input purpose
|
## 1.3.4 / 1.3.5 Orientation & Input purpose
|
||||||
|
|
||||||
- [ ] **No `autocomplete` attributes on personal data fields** — `add.php`/`edit.php`: add `autocomplete="name"` on author fields, `autocomplete="email"` on mail fields
|
- [x] **No `autocomplete` attributes on personal data fields** — `add.php`/`edit.php`: `autocomplete="name"` on author fields, `autocomplete="email"` on mail fields (via `$attrs` in `text-field.php`)
|
||||||
|
|
||||||
## 1.4.1 Use of colour
|
## 1.4.1 Use of colour
|
||||||
|
|
||||||
@@ -57,7 +57,8 @@
|
|||||||
|
|
||||||
## 3.3.1 Error identification
|
## 3.3.1 Error identification
|
||||||
|
|
||||||
- [ ] **`add.php`/`formulaire.php` validation errors** — add `role="alert"` to error div; add `autofocus` to first invalid field when re-rendering form with session error data
|
- [x] **`add.php`/`edit.php` validation errors** — `flash-messages.php` already emits `<p role="alert" data-type="error">` for errors and `<p role="status">` for success
|
||||||
|
- [ ] **`add.php`/`edit.php` `autofocus` on first invalid field** — requires controller to pass back which field failed; deferred (larger refactor)
|
||||||
|
|
||||||
## 3.3.2 Labels or instructions
|
## 3.3.2 Labels or instructions
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user