Replace every <img src="/assets/icons/..."> with <?= icon('name') ?>
across 26 template files. The PHP helper inlines the SVG markup into the
DOM so CSS color cascades naturally through fill="currentColor".
- Add src/icon.php helper: reads SVG file, sets width/height to 1em,
injects aria-hidden, supports optional CSS class
- Fix 12 icon SVGs that had hardcoded fill="#000000" or missing fill attr
- Replace search.svg with Phosphor fill-based magnifying glass
- Add explicit SVG sizes for admin header nav icons (16px/20px)
- Scope public search icon CSS to form[role=search]:not(.header-search-form)
to avoid breaking admin header layout; change stroke to fill
- Remove <img> filter: brightness(0) invert(1) hacks from admin.css
- Rename 'Éditer Données Secondaires' → 'Données Secondaires', remove fieldset wrapper on Mots-clés link
- Create admin-toc.php partial: IntersectionObserver-based sidebar nav
- Include TOC on contenus.php, acces.php, parametres.php
- Add .admin-with-toc flex layout (sidebar + main) and .admin-toc CSS
- Fonts (Ductus, BBB DM Sans): verified loaded via variables.css → common.css import chain
- TOC: move inside <main> as <aside>, content in <article>, fix scrolling
- Lazy load: hx-trigger='load delay:100ms' with spinner (htmx-indicator) for tags/langues
- Inline rename: edit button in Nom cell, HTMX post for rename, validate+ cancel buttons
- Checkbox column: width:1% / fit-content
- Remove per-row merge forms/selects, only bulk merge when ≥2 checkboxes selected
- Remove per-row merge dialogs, keep only bulk merge and delete dialogs
- Add htmx-settling CSS transition for lazy-load fade-in
- Update acces.php/parametres.php: article layout, TOC inside main
- TOC: DOMContentLoaded guard, use <nav>+<a> directly instead of <ul>/<li>
- Section spacing: margin-bottom on sections and fieldsets in admin-main--toc
- Language dedup: GROUP BY LOWER(name) in getAllLanguagesWithCount and searchLanguages
- deduplicateLanguages() merges duplicate names and reassigns thesis_languages
- Sticky bulk-actions: position:sticky;top:0;z-index:10
- Tags toolbar: title left, stat count right (margin-left:auto), search bar under
- Tags count stat updated via hx-swap-oob from fragment
- Remove margin/max-width from .admin-main--toc
- Gap between TOC and article: --space-xs, sticky top: --space-xs
- Main padding: --space-s / --space-m / --space-xl (was --space-l/--space-l/--space-2xl)
- Article padding-top: --space-m
- Add DuplicateThesisException (typed, carries existing thesis metadata)
- Add Database::findDuplicateThesis(): matches on year + author + normalised
title (exact, prefix, Levenshtein ≤10% of longer string)
- ThesisCreateController::submit() runs duplicate check before any DB write
and throws DuplicateThesisException on match
- AppLogger::logDuplicate() writes status=duplicate entries to the JSON-lines
log for audit purposes
- App::flash/consumeFlash extended to support 'warning' flash type
- admin/actions/formulaire.php: catches DuplicateThesisException, logs it,
flashes an HTML warning toast with a clickable link to the existing thesis,
and repopulates the form fields
- partage/index.php: same catch block; surfaces a plain-text flash-warning
banner on the student form with identifier, title, and year of the match;
form is repopulated via session
- toast.php: renders toast--warning variant
- admin.css: .toast--warning + link colour rules
- form.css: .flash-warning style for the partage form