diff --git a/TODO.md b/TODO.md index 09ab492..de69c4f 100644 --- a/TODO.md +++ b/TODO.md @@ -347,7 +347,7 @@ Goal: rename the tables and column to the canonical M2M pattern (`tags`, `thesis ### A — SQLite / Query performance -- [ ] **WAL mode** — set `PRAGMA journal_mode = WAL` and `PRAGMA synchronous = NORMAL` in `Database::__construct()` after `foreign_keys = ON`. +- [x] **WAL mode** — set `PRAGMA journal_mode = WAL` and `PRAGMA synchronous = NORMAL` in `Database::__construct()` after `foreign_keys = ON`. Eliminates full-database read-locks on every write; makes concurrent PHP-FPM workers safe. Also add `PRAGMA cache_size = -8000` (≈8 MB page cache) while there. @@ -1308,27 +1308,14 @@ Current state: **zero ARIA attributes, zero skip links, zero focus-visible style These are things that must be added once and apply everywhere: -- [ ] **Add `.sr-only` utility class to `common.css`** — needed for skip links, visually-hidden - labels, and screen-reader-only context text referenced throughout this audit: - ```css - .sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0,0,0,0); - white-space: nowrap; - border: 0; - } - ``` +- [x] **Add `.sr-only` utility class to `common.css`** — needed for skip links, visually-hidden + labels, and screen-reader-only context text referenced throughout this audit. -- [ ] **Add skip-to-content link in all page templates** — as described in 2.4.1 above. This - one change has the highest impact-per-line-of-code ratio of any item in this audit. +- [x] **Add skip-to-content link in all page templates** — added to all 5 public pages and + admin head template; `id="main-content"` added to every `
` in the codebase. -- [ ] **Add global `:focus-visible` rule in `common.css` and `admin.css`** — as described in - 2.4.7. Second highest impact item. +- [x] **Add global `:focus-visible` rule in `common.css` and `admin.css`** — consistent + 2px purple outline with 2px offset; `prefers-reduced-motion` guard also added. -- [ ] **Remove all `outline: none` declarations that have no replacement focus style** — - `common.css:125`, `admin.css:121`, `admin.css:323`, `search.css:241`. +- [x] **Remove all `outline: none` declarations that have no replacement focus style** — + removed from `common.css`, `admin.css` (×2), and `search.css`. diff --git a/public/admin/account.php b/public/admin/account.php index d60af2f..c203ef9 100644 --- a/public/admin/account.php +++ b/public/admin/account.php @@ -18,7 +18,7 @@ if (empty($_SESSION['csrf_token'])) { ?> -
+

Compte administrateur

diff --git a/public/admin/add.php b/public/admin/add.php index a853187..175ac7d 100644 --- a/public/admin/add.php +++ b/public/admin/add.php @@ -41,7 +41,7 @@ function wasSelected($key, $value) { ?> -
+

Ajouter un TFE

diff --git a/public/admin/edit.php b/public/admin/edit.php index 1562721..a295d3c 100644 --- a/public/admin/edit.php +++ b/public/admin/edit.php @@ -234,7 +234,7 @@ try { ?> -
+

Modifier un TFE

diff --git a/public/admin/import.php b/public/admin/import.php index 1231882..10ed528 100644 --- a/public/admin/import.php +++ b/public/admin/import.php @@ -279,7 +279,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) { ?> -
+

Importer une liste de TFE

diff --git a/public/admin/index.php b/public/admin/index.php index 881a644..e99cad0 100644 --- a/public/admin/index.php +++ b/public/admin/index.php @@ -62,7 +62,7 @@ document.addEventListener('DOMContentLoaded', () => { }); -
+

Liste des TFE

diff --git a/public/admin/pages-edit.php b/public/admin/pages-edit.php index df999c7..5bfd8db 100644 --- a/public/admin/pages-edit.php +++ b/public/admin/pages-edit.php @@ -33,7 +33,7 @@ $pageTitle = "Éditer : " . htmlspecialchars($page['title']); -
+

Éditer :

diff --git a/public/admin/pages.php b/public/admin/pages.php index 7f01879..904080c 100644 --- a/public/admin/pages.php +++ b/public/admin/pages.php @@ -20,7 +20,7 @@ unset($_SESSION['success']); ?> -
+

Pages statiques

diff --git a/public/admin/system.php b/public/admin/system.php index a8b12d2..ce58af3 100644 --- a/public/admin/system.php +++ b/public/admin/system.php @@ -601,7 +601,7 @@ require_once APP_ROOT . '/templates/admin/head.php'; .nginx-location { color: #79dac8; } -
+

Système

diff --git a/public/admin/tags.php b/public/admin/tags.php index 235270b..f668022 100644 --- a/public/admin/tags.php +++ b/public/admin/tags.php @@ -24,7 +24,7 @@ unset($_SESSION['admin_error'], $_SESSION['admin_success']); ?> -

+

Mots-clés ()

diff --git a/public/admin/thanks.php b/public/admin/thanks.php index bd37dce..0e51e31 100644 --- a/public/admin/thanks.php +++ b/public/admin/thanks.php @@ -73,7 +73,7 @@ $pageTitle = "Récapitulatif TFE"; ?> -
+

Récapitulatif TFE

diff --git a/public/apropos.php b/public/apropos.php index f5f5758..6755582 100644 --- a/public/apropos.php +++ b/public/apropos.php @@ -46,11 +46,12 @@ $aboutHtml = $pd->text($rawContent); + -
+
diff --git a/public/assets/admin.css b/public/assets/admin.css index 1c8e048..f9f83d5 100644 --- a/public/assets/admin.css +++ b/public/assets/admin.css @@ -118,7 +118,6 @@ html, body { font-size: 0.92rem; font-family: inherit; padding: 0.4rem 0; - outline: none; border-radius: 0; transition: border-color 0.15s; -webkit-appearance: none; @@ -320,7 +319,6 @@ html, body { font-size: 0.88rem; font-family: inherit; padding: 0.45rem 0.75rem; - outline: none; cursor: pointer; } @@ -808,3 +806,42 @@ html, body { font-size: 0.9rem; line-height: 1.5; } + +/* ============================================================ + ACCESSIBILITY UTILITIES + ============================================================ */ + +/* Consistent keyboard-focus outline for admin interactive elements */ +:focus-visible { + outline: 2px solid var(--admin-purple); + outline-offset: 2px; +} + +/* Skip-to-admin-content link */ +.skip-link { + position: absolute; + top: -999px; + left: 1rem; + z-index: 9999; + padding: 0.5rem 1rem; + background: var(--admin-purple); + color: #fff; + font-size: 0.9rem; + font-weight: 600; + text-decoration: none; + border-radius: 0 0 4px 4px; +} + +.skip-link:focus { + top: 0; +} + +/* Respect user motion preferences */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + transition-duration: 0.01ms !important; + animation-duration: 0.01ms !important; + } +} diff --git a/public/assets/common.css b/public/assets/common.css index 1104d3d..5ce5329 100644 --- a/public/assets/common.css +++ b/public/assets/common.css @@ -122,7 +122,6 @@ a:hover { .site-search__input { flex: 1; border: none; - outline: none; font-size: 0.95rem; color: var(--black); background: transparent; @@ -133,3 +132,55 @@ a:hover { .site-search__input::placeholder { color: #aaa; } + +/* ============================================================ + ACCESSIBILITY UTILITIES + ============================================================ */ + +/* Visually-hidden but screen-reader-accessible */ +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +/* Skip-to-content link (visible only on keyboard focus) */ +.skip-link { + position: absolute; + top: -999px; + left: 1rem; + z-index: 9999; + padding: 0.5rem 1rem; + background: var(--purple); + color: var(--white); + font-size: 0.9rem; + font-weight: 600; + text-decoration: none; + border-radius: 0 0 4px 4px; +} + +.skip-link:focus { + top: 0; +} + +/* Consistent keyboard-focus outline for all interactive elements */ +:focus-visible { + outline: 2px solid var(--purple); + outline-offset: 2px; +} + +/* Respect user motion preferences */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + transition-duration: 0.01ms !important; + animation-duration: 0.01ms !important; + } +} diff --git a/public/assets/search.css b/public/assets/search.css index 1d08c1a..3caa90f 100644 --- a/public/assets/search.css +++ b/public/assets/search.css @@ -238,7 +238,6 @@ html, body { padding: 0.2rem 0.5rem; background: var(--white); color: var(--black); - outline: none; font-family: inherit; cursor: pointer; } diff --git a/public/index.php b/public/index.php index ae3e5fd..222fc77 100644 --- a/public/index.php +++ b/public/index.php @@ -82,6 +82,7 @@ $currentNav = ''; + @@ -97,7 +98,7 @@ $currentNav = '';
-
+
" class="card-link"> diff --git a/public/licence.php b/public/licence.php index a02ad5a..6e4bee2 100644 --- a/public/licence.php +++ b/public/licence.php @@ -41,11 +41,12 @@ $html = $pd->text($content); + -
+
diff --git a/public/search.php b/public/search.php index 5909088..4e22096 100644 --- a/public/search.php +++ b/public/search.php @@ -83,6 +83,7 @@ $searchBarValue = $_GET['query'] ?? ''; + @@ -140,7 +141,7 @@ $searchBarValue = $_GET['query'] ?? ''; Réinitialiser -
+

résultat 1 ? 's' : '' ?>

@@ -173,7 +174,7 @@ $searchBarValue = $_GET['query'] ?? ''; -
+
diff --git a/public/tfe.php b/public/tfe.php index 9e44183..27e0304 100644 --- a/public/tfe.php +++ b/public/tfe.php @@ -39,11 +39,12 @@ $currentNav = ''; + -
+
diff --git a/src/Database.php b/src/Database.php index d7e8b04..173d97f 100644 --- a/src/Database.php +++ b/src/Database.php @@ -24,8 +24,11 @@ class Database { $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); - // Enable foreign key constraints + // Enable foreign key constraints + performance pragmas $this->pdo->exec('PRAGMA foreign_keys = ON'); + $this->pdo->exec('PRAGMA journal_mode = WAL'); + $this->pdo->exec('PRAGMA synchronous = NORMAL'); + $this->pdo->exec('PRAGMA cache_size = -8000'); } catch (PDOException $e) { error_log("Database connection failed: " . $e->getMessage()); throw new Exception("Impossible de se connecter à la base de données."); diff --git a/src/cache/rate_limit/ad921d60486366258809553a3db49a4a.json b/src/cache/rate_limit/ad921d60486366258809553a3db49a4a.json index 196b222..a2b2955 100644 --- a/src/cache/rate_limit/ad921d60486366258809553a3db49a4a.json +++ b/src/cache/rate_limit/ad921d60486366258809553a3db49a4a.json @@ -1 +1 @@ -[1774547615,1774547646] \ No newline at end of file +[1774615474] \ No newline at end of file diff --git a/storage/test.db b/storage/test.db index 916a045..cfe9a81 100644 Binary files a/storage/test.db and b/storage/test.db differ diff --git a/templates/admin/head.php b/templates/admin/head.php index 74e287e..16ae287 100644 --- a/templates/admin/head.php +++ b/templates/admin/head.php @@ -18,7 +18,8 @@ -