diff --git a/TODO.md b/TODO.md index 3d218b3..ee8dee5 100644 --- a/TODO.md +++ b/TODO.md @@ -1,89 +1,6 @@ -# TODO - -- [x] Replace inline alert CSS in admin.css with floating bottom-center toast styles (fixed, z-index, animation) -- [x] Update flash-messages.php partial to output `.toast` markup in hidden container for footer JS -- [x] Add toast container HTML + JS to admin footer.php (centralised, 4s auto-dismiss with fade-out) -- [x] Remove redundant flash-messages.php includes from all admin pages (8 files) -- [x] Convert hardcoded alerts in login.php, thanks.php, index.php import to `.toast` class -- [x] Update admin.css dialog rule from `[role=alert/status]` to `.toast` -- [x] Commit with jj - -- [x] Move DB export from admin/index.php to admin/parametres.php (maintenance section) - -- [x] Reorganize src/ - move 7 controllers to src/Controllers/ - - [x] Create Controllers directory - - [x] Move controller files (Home, Tfe, Search, ThesisCreate, ThesisEdit, Export, System) - - [x] Update all require_once paths across codebase - -- [x] Move stray test.db from root to storage/ - -- [x] Store admin password hash in DB (site_settings) instead of config file - - [x] Create migration 013 - - [x] Update AdminAuth to read hash from DB - - [x] Update bootstrap.php — remove credential file loading - - [x] Update parametres.php — status check from DB - - [x] Update actions/account.php — write hash to DB - - [x] Update login.php — dev-mode check - - [x] Update header.php — dev check - - [x] Delete config/admin_credentials.example.php - -## Now: Single Entry Point Routing - -### Phase 1: Dispatcher refinement -- [x] MediaController: extract media.php logic into MediaController class - - [x] Create src/Controllers/MediaController.php - - [x] Move path validation + storage jail + MIME check + streaming - - [x] Wire into Dispatcher for /media route - - [x] Delete app/public/media.php -- [ ] Update Dispatcher to handle all routes directly (no require APP_ROOT/public/*.php) - -### Phase 2: Single entry point -- [x] Create app/public/index.php as front controller - - [x] Move bootstrap logic into entry point (bootstrap.php stays for admin) - - [x] Load and invoke Dispatcher -- [x] Move old public/*.php views into templates/public/ - - [x] search.php → templates/public/search.php - - [x] tfe.php → templates/public/tfe.php - - [x] apropos.php → templates/public/about.php - - [x] repertoire.php → templates/public/repertoire.php -- [x] Delete old direct-access public/*.php files - - [x] Delete public/index.php (replaced by front controller) - - [x] Delete public/search.php - - [x] Delete public/tfe.php - - [x] Delete public/apropos.php - - [x] Delete public/licence.php - - [x] Delete public/repertoire.php -- [x] Update Dispatcher.render to use templates/public/ views -- [x] Update Dispatcher to render full pages (head + header + view + footer) instead of requiring bootstrap -- [x] Ensure admin/index.php bootstraps its own path (not affected by front controller) - -- [x] Fix config/config.php path mess — inline getDatabasePath() into Database.php, delete config/config.php - -### Phase 3: Server config -- [ ] Update router.php — route all PHP requests to Dispatcher -- [ ] Update nginx config — point all public routes to index.php via try_files - - [ ] Replace per-file `location ~ \.php$` with front-controller pattern -- [x] Clean URL updates - - [x] Remove .php from all internal links (header, views, controllers) - - [x] Add clean routes to Dispatcher (/search, /tfe, /media) - - [x] Update og:url tags in controllers to use clean URLs - - [x] Update TfeController redirect to / - - [x] Update header.php action URLs -- [x] Commit current state -- [ ] Test all routes (/, /search, /tfe, /repertoire, /apropos, /licence, /media, /live-reload) - -# Now: Confirmation email on student form submission -- [x] Create src/StudentEmail.php — builds HTML recap email, extracts email from contact field, uses SmtpRelay to send -- [x] Wire StudentEmail::sendConfirmation() into partage/index.php handleShareLinkSubmission() after successful thesis creation -- [x] Pass email-sent flag via session to /partage/thanks.php -- [x] Update partage/thanks.php — show "email sent" notice with styled green badge when confirmation was sent - -- [x] Add "Visiter" (👁 Visit) button to student link action row in acces-etudiante.php - - [x] Add link (target _blank) to /partage/ - - [x] Add .admin-btn-visit / .admin-btn-visit:hover CSS in admin.css - -- [x] Add required confirmation_email field to both student forms (partage/index.php + admin/add.php) - - [x] New fieldset at end of form with type="email", required - - [x] ThesisCreateController validates confirmation_email is present and valid - - [x] StudentEmail uses confirmation_email directly (no more extractEmail hack) - - [x] Autofocus mapping added for confirmation_email validation errors +[x] Audit required fields in both admin and student forms +[x] Fix: `checkbox-list.php` partial supports `$required` (fieldset gets `required` + `aria-required`) +[x] Mark `languages` checkbox list as required in both forms +[x] Added visual `*` indicator on all required fields (CSS bold labels + red asterisk) +[x] Added "* Champs obligatoires" note at top of both forms +[x] Verified: all server-side required fields match client-side `required` attrs and visual indicators diff --git a/app/public/admin/add.php b/app/public/admin/add.php index a288d2d..7cc6956 100644 --- a/app/public/admin/add.php +++ b/app/public/admin/add.php @@ -59,6 +59,7 @@ include APP_ROOT . '/templates/header.php'; +

* Champs obligatoires

"> @@ -107,7 +108,7 @@ include APP_ROOT . '/templates/header.php'; - + diff --git a/app/public/assets/css/admin.css b/app/public/assets/css/admin.css index 4840a0f..14b4ebb 100644 --- a/app/public/assets/css/admin.css +++ b/app/public/assets/css/admin.css @@ -147,6 +147,43 @@ padding-right: 1.2rem; } +/* Required-field indicator */ +.admin-form + input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not( + [type="hidden"] + ):not([type="submit"]):required, +.admin-form select:required, +.admin-form textarea:required { + border-bottom-style: dashed; +} + +.admin-form + div:has( + input:required:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="hidden"])) > label, +.admin-form div:has(select:required) > label, +.admin-form div:has(textarea:required) > label { + font-weight: 600; +} + +/* Required-field indicator (student form / generic labels) */ +label:has(+ input:required:not([type="hidden"]))::after, +label:has(+ select:required)::after, +label:has(+ textarea:required)::after, +label:has(+ div > input:required)::after { + content: " *"; + color: var(--error, #c00); +} + +/* Visually-hidden "required fields marked with *" note */ +.required-note { + font-size: var(--step--2); + color: var(--text-secondary); + margin-bottom: var(--space-xs); +} +.required-note .asterisk { + color: var(--error, #c00); +} + /* File inputs */ .admin-file-input { display: flex; diff --git a/app/public/partage/index.php b/app/public/partage/index.php index a26b169..15cbe9e 100644 --- a/app/public/partage/index.php +++ b/app/public/partage/index.php @@ -308,6 +308,7 @@ function renderShareLinkForm(string $slug, array $link): void +

* Champs obligatoires

@@ -376,7 +377,7 @@ function renderShareLinkForm(string $slug, array $link): void - + diff --git a/app/templates/partials/form/checkbox-list.php b/app/templates/partials/form/checkbox-list.php index 688b69a..3f4fcaa 100644 --- a/app/templates/partials/form/checkbox-list.php +++ b/app/templates/partials/form/checkbox-list.php @@ -12,13 +12,15 @@ * string $label — group label text * array $options — each element must have 'id' and 'name' keys * array $checked — array of 'id' values that are currently checked + * bool $required — whether at least one checkbox must be checked; default false */ -$checked = $checked ?? []; +$checked = $checked ?? []; +$required = $required ?? false; ?>
-
+
>
    diff --git a/app/public/assets/css/README.md b/docs/CSS.md similarity index 100% rename from app/public/assets/css/README.md rename to docs/CSS.md