admin: semantic HTML improvements — dl stats, section cards, th scope

- admin/index.php: replace <div class="admin-stats"> with <dl>; inner
  <div class="admin-stat__number"> → <dd>, <div class="admin-stat__label"> → <dt>;
  use CSS order to keep number visually first; add scope="col" to all 9 <th> cells

- admin/thanks.php: replace all four <div class="admin-thesis-info"> wrappers
  with <section> elements; remove the class entirely; add scope="col" to
  the files table <th> cells

- admin/tags.php: add scope="col" to all 3 <th> cells

- admin/pages.php: add scope="col" to all 4 <th> cells

- admin.css: rename .admin-thesis-info selectors to .admin-main > section
  (element + context selector — no class needed); add display:flex +
  flex-direction:column to .admin-stat so CSS order property works correctly

Addresses TODO items: section X (admin-stats dl, th scope), XI (tags th scope),
XII (admin-thesis-info → section), XIII (pages.php th scope)
This commit is contained in:
Pontoporeia
2026-04-01 16:50:53 +02:00
parent 8e36f98139
commit 573747303f
6 changed files with 49 additions and 44 deletions

10
TODO.md
View File

@@ -907,7 +907,7 @@ Once the above is applied, the following classes become deletable (element name
### X - `public/admin/index.php` (TFE list)
- [ ] **`<div class="admin-stats">` with `<div class="admin-stat">` children** - the stats
- [x] **`<div class="admin-stats">` with `<div class="admin-stat">` children** - the stats
(total, published, pending) are a set of key-value pairs. Replace with `<dl>`:
`<div class="admin-stats">``<dl class="admin-stats">`;
each `<div class="admin-stat">``<div>` kept (valid `<dl>` child for grouping, per spec);
@@ -923,7 +923,7 @@ Once the above is applied, the following classes become deletable (element name
with `<div role="toolbar" aria-label="Actions groupées">`. Not a full semantic element
replacement, but adds correct ARIA role for the keyboard/AT pattern of a toolbar.
- [ ] **`<table class="admin-table">` is correct** - tabular data, right element. No change
- [x] **`<table class="admin-table">` is correct** - tabular data, right element. No change
needed. The `<thead>`, `<tbody>`, `<tr>`, `<th>`, `<td>` structure is correct.
Minor: `<th>` cells have no `scope="col"` attribute - add it for screen reader column
association (`<th scope="col">`).
@@ -940,15 +940,15 @@ Once the above is applied, the following classes become deletable (element name
`style="margin-top:.35rem;"` on two of the three forms → move to CSS (e.g.
`.admin-inline-form + .admin-inline-form` selector in `admin.css`).
- [ ] **`<table>` with `<th>` cells lacking `scope="col"`** - same as `index.php`.
- [x] **`<table>` with `<th>` cells lacking `scope="col"`** - same as `index.php`.
### XII - `public/admin/thanks.php`
- [ ] **`<div class="admin-thesis-info">` blocks** - each is a labelled section with a `<dl>`
- [x] **`<div class="admin-thesis-info">` blocks** - each is a labelled section with a `<dl>`
inside it (already using `<dl>/<dt>/<dd>` correctly - good!). The outer wrapper `<div>`
could be a `<section>` with the `<h2>` as its heading, making the structure
`<section><h2>...</h2><dl>...</dl></section>`. Removes `.admin-thesis-info` class; CSS targets
`main > section`.
`.admin-main > section`.
### XIII - `public/admin/account.php`

View File

@@ -98,20 +98,20 @@ document.addEventListener('DOMContentLoaded', () => {
</div>
<!-- Stats (always reflects full DB, independent of active filters) -->
<div class="admin-stats">
<dl class="admin-stats">
<div class="admin-stat">
<div class="admin-stat__number"><?= $stats['total'] ?></div>
<div class="admin-stat__label">TFE total</div>
<dt class="admin-stat__label">TFE total</dt>
<dd class="admin-stat__number"><?= $stats['total'] ?></dd>
</div>
<div class="admin-stat">
<div class="admin-stat__number"><?= $stats['published'] ?></div>
<div class="admin-stat__label">Publiés</div>
<dt class="admin-stat__label">Publiés</dt>
<dd class="admin-stat__number"><?= $stats['published'] ?></dd>
</div>
<div class="admin-stat">
<div class="admin-stat__number"><?= $stats['pending'] ?></div>
<div class="admin-stat__label">En attente</div>
<dt class="admin-stat__label">En attente</dt>
<dd class="admin-stat__number"><?= $stats['pending'] ?></dd>
</div>
</div>
</dl>
<!-- Filters -->
<form class="admin-filters" method="get" action="/admin/">
@@ -160,15 +160,15 @@ document.addEventListener('DOMContentLoaded', () => {
<table class="admin-table">
<thead>
<tr>
<th><input type="checkbox" onchange="toggleAll(this)"></th>
<th>ID</th>
<th>Titre</th>
<th>Auteur(s)</th>
<th>Année</th>
<th>Orientation</th>
<th>AP</th>
<th>Statut</th>
<th>Actions</th>
<th scope="col"><input type="checkbox" onchange="toggleAll(this)"></th>
<th scope="col">ID</th>
<th scope="col">Titre</th>
<th scope="col">Auteur(s)</th>
<th scope="col">Année</th>
<th scope="col">Orientation</th>
<th scope="col">AP</th>
<th scope="col">Statut</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>

View File

@@ -31,10 +31,10 @@ unset($_SESSION['success']);
<table class="admin-table">
<thead>
<tr>
<th>Slug</th>
<th>Titre</th>
<th>Mis à jour</th>
<th>Action</th>
<th scope="col">Slug</th>
<th scope="col">Titre</th>
<th scope="col">Mis à jour</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>

View File

@@ -38,9 +38,9 @@ unset($_SESSION['admin_error'], $_SESSION['admin_success']);
<table class="admin-table" style="margin-top:1.5rem;">
<thead>
<tr>
<th style="width:40%;">Nom</th>
<th style="width:12%;text-align:center;">TFE associés</th>
<th style="width:48%;">Actions</th>
<th scope="col" style="width:40%;">Nom</th>
<th scope="col" style="width:12%;text-align:center;">TFE associés</th>
<th scope="col" style="width:48%;">Actions</th>
</tr>
</thead>
<tbody>

View File

@@ -73,7 +73,7 @@ $pageTitle = "Récapitulatif TFE";
<p><a href="/admin/add.php" class="admin-btn-secondary">Retour au formulaire</a></p>
<?php elseif ($thesis): ?>
<div class="admin-thesis-info">
<section>
<h2>Informations de base</h2>
<dl>
<dt>Identifiant</dt><dd><?= htmlspecialchars($thesis['identifier']) ?></dd>
@@ -84,9 +84,9 @@ $pageTitle = "Récapitulatif TFE";
<dt>Auteur·ice(s)</dt><dd><?= htmlspecialchars($thesis['authors']) ?></dd>
<dt>Année</dt><dd><?= htmlspecialchars($thesis['year']) ?></dd>
</dl>
</div>
</section>
<div class="admin-thesis-info">
<section>
<h2>Détails académiques</h2>
<dl>
<dt>Orientation</dt><dd><?= htmlspecialchars($thesis['orientation'] ?? '') ?></dd>
@@ -96,9 +96,9 @@ $pageTitle = "Récapitulatif TFE";
<dt>Promoteur·ice(s)</dt><dd><?= htmlspecialchars($thesis['supervisors']) ?></dd>
<?php endif; ?>
</dl>
</div>
</section>
<div class="admin-thesis-info">
<section>
<h2>Contenu</h2>
<dl>
<?php if ($thesis['languages']): ?>
@@ -117,13 +117,13 @@ $pageTitle = "Récapitulatif TFE";
<dt>Lien</dt><dd><a href="<?= htmlspecialchars($thesis['baiu_link']) ?>" target="_blank" rel="noopener"><?= htmlspecialchars($thesis['baiu_link']) ?></a></dd>
<?php endif; ?>
</dl>
</div>
</section>
<?php if (!empty($files)): ?>
<div class="admin-thesis-info">
<section>
<h2>Fichiers</h2>
<table class="admin-table">
<thead><tr><th>Type</th><th>Fichier</th><th>Taille</th><th>Date</th></tr></thead>
<thead><tr><th scope="col">Type</th><th scope="col">Fichier</th><th scope="col">Taille</th><th scope="col">Date</th></tr></thead>
<tbody>
<?php foreach ($files as $f): ?>
<tr>
@@ -135,7 +135,7 @@ $pageTitle = "Récapitulatif TFE";
<?php endforeach; ?>
</tbody>
</table>
</div>
</section>
<?php endif; ?>
<div style="margin-top:1.5rem;display:flex;gap:.75rem;flex-wrap:wrap;">

View File

@@ -309,6 +309,8 @@
border-radius: 4px;
padding: 1rem 1.5rem;
min-width: 140px;
display: flex;
flex-direction: column;
}
.admin-stat__number {
@@ -316,12 +318,15 @@
font-weight: 700;
color: var(--admin-purple);
line-height: 1;
order: 1; /* visually first despite dt/dd semantic order */
margin: 0;
}
.admin-stat__label {
font-size: 0.82rem;
color: var(--admin-text-muted);
margin-top: 0.25rem;
order: 2; /* visually second */
}
/* ---- Filters bar ---- */
@@ -514,34 +519,34 @@
gap: 0.5rem;
}
/* Thesis info (thanks page) */
.admin-thesis-info {
/* Thesis info sections (thanks page) */
.admin-main > section {
border: 1px solid var(--admin-border);
border-radius: 6px;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.admin-thesis-info h2 {
.admin-main > section h2 {
margin: 0 0 1rem;
font-size: 1.2rem;
border-bottom: 1px solid var(--admin-border);
padding-bottom: 0.5rem;
}
.admin-thesis-info dl {
.admin-main > section dl {
display: grid;
grid-template-columns: 180px 1fr;
gap: 0.4rem 1rem;
}
.admin-thesis-info dt {
.admin-main > section dt {
font-weight: 600;
font-size: 0.88rem;
color: var(--admin-text-muted);
}
.admin-thesis-info dd {
.admin-main > section dd {
margin: 0;
font-size: 0.9rem;
}