fix: various styling fixes; simplify tfe.php structure and CSS with grid

This commit is contained in:
Pontoporeia
2026-07-10 11:56:27 +02:00
parent 61029ea437
commit ce936e3b71
6 changed files with 1597 additions and 1674 deletions
+5 -36
View File
@@ -1,36 +1,5 @@
- [x] Remove "Mo" option from duration — keep only minutes and pages # TODO
- [x] Combine pages and minutes as separate fields (both can be set simultaneously)
- [x] Fix minutes input visibility (can't see what's typed) - [x] Simplify `tfe.php` HTML structure (remove `.tfe-layout` wrapper, remove `.tfe-synopsis-column` wrapper)
- [x] Add `has_annexes` checkbox to form + DB column - [x] Simplify `tfe.css` — replace flex-column with grid where possible, merge `.tfe-layout` into `.tfe-content-row`, remove dead wrappers
- [x] Display duration on admin backoffice recap page - [x] Commit changes
- [x] Update public TFE page duration display for new combined format
- [x] Fix `handleAutosaveResponse is not defined` — load `autosave-handler.js` on about_page edit view
- [x] Fix `handleAutosaveResponse is not defined` in admin add/edit — function was scoped inside IIFE bundle, not on window
- [x] Fix search result cards: title and author always below image/gradient, remove text overlay on placeholder gradient
- [x] Change search results to 10 per page with HTMX pagination (no-JS fallback preserved)
- [x] Bump to 15 results/page, make results area vertically scrollable, sticky pagination at viewport bottom
- [x] Fix HTMX targetError: move #search-results wrapper inside fragment so it survives outerHTML swaps
- [x] Add range counter to results header (e.g. "115 sur 112 résultats")
- [x] Collapsible filter controls with <details>/<summary> + active filter badge on mobile
- [x] Responsive paginator: hide first/last buttons on mobile, smaller touch targets
- [x] Compact range counter on mobile: "115 / 112" instead of full "115 sur 112 résultats"
- [x] Remove orientation display from search result card meta
- [x] Add bulk select/delete to tmp cleanup dialog (like admin/index.php pattern)
- [x] Move cleanup UI from modal to dedicated page (like add.php/edit.php)
- [x] Replace <details> with <fieldset>/<legend> in cleanup fragments (like contenus.php)
- [x] Standardise test group recipes: lint-php, lint-css, lint-js, test + add fix recipe + make lint pass clean
- [x] Remove Mot de passe column from acces.php, add key.svg icon button in Actions to copy password to clipboard, reorder actions (URL/password/edit/toggle/archive), switch URL icon to link-simple.svg
- [x] Fix CC2r: removed hidden seeds (were stale/overriding user input), render initial licence-choice from \$formData; Interne want_license unchecked clears CC2r+licence, switching from other modes preserves values; CC2r independent toggle; licence dropdown has no-licence placeholder
- [x] Dans le formulaire admin, le contact privé ne se sauvegarde pas.
- [x] Remove "Rendre le contact visible publiquement sur la fiche du TFE" from admin add/edit forms
- [x] Auto-show contact on public TFE page when contact_visible is filled (no checkbox needed)
- [x] Fix file size limits: align all layers (JS/FilepondHandler/ThesisFileHandler/validate-fragment) — video/audio 5 GB, default 500 MB, PDF 100 MB; fix JS fileValidateSizeFilter gate bug that rejected AV files >1 GB despite 8 GB per-ext cap
- [x] Fix: deleting contact groups in apropos form not persisted (no change event after DOM removal, autosave never triggered)
- [x] Improve h1, h2, h3 size difference in base.css heading scale
- [x] Rework TFE page desktop layout: two columns 35vw/1fr, left = author/title/meta/synopsis, right = files, media 100% width; columns scroll independently, content fits 100vw; no bottom padding on main; add &scrollbar=0 to PDF iframe URLs
- [x] 'Promoteur·ice ULB' remplacé par 'Promoteur·ice université' (changement juste l'étiquette)
- [x] PDF viewer: fix page navigation buttons (prev/next) — build toolbar after canvases exist & query canvases fresh in scroll handler
- [x] PDF viewer: render pages smaller by default (0.85× scale)
- [x] PDF viewer: add dark transparent violet background behind pages when expanded
- [x] pdf-viewer: expand to fill right column (not whole page), center pages, freeze column on expand
- [x] pdf-viewer: fix toolbar width (align-self:stretch), hide sibling file items when expanded
File diff suppressed because it is too large Load Diff
+35 -35
View File
@@ -7,83 +7,83 @@
/* Full-height flex layout: header → main → (optional footer) */ /* Full-height flex layout: header → main → (optional footer) */
html, html,
body { body {
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
} }
/* ── Discreet scrollbars ─────────────────────────────────────────── */ /* ── Discreet scrollbars ─────────────────────────────────────────── */
/* WebKit browsers */ /* WebKit browsers */
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 5px; width: 5px;
height: 5px; height: 5px;
} }
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
background: transparent; background: transparent;
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background: var(--text-tertiary); background: var(--text-tertiary);
border-radius: 3px; border-radius: 3px;
} }
::-webkit-scrollbar-thumb:hover { ::-webkit-scrollbar-thumb:hover {
background: var(--text-secondary); background: var(--text-secondary);
} }
/* Firefox */ /* Firefox */
* { * {
scrollbar-width: thin; scrollbar-width: thin;
scrollbar-color: var(--text-tertiary) transparent; scrollbar-color: var(--text-tertiary) transparent;
} }
body { body {
font-family: var(--font-body); font-family: var(--font-body);
font-weight: 300; font-weight: 300;
color: var(--text-primary); color: var(--text-primary);
background: linear-gradient( background: linear-gradient(
180deg, 180deg,
rgba(0, 0, 0, 0) 92%, rgba(0, 0, 0, 0) 85%,
rgba(149, 87, 181, 1) 100% rgba(149, 87, 181, 0.8) 100%
); );
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
main { main {
flex: 1; flex: 1;
min-height: 0; min-height: 0;
overflow-wrap: anywhere; overflow-wrap: anywhere;
} }
main * { main * {
overflow-wrap: anywhere; overflow-wrap: anywhere;
word-break: break-word; word-break: break-word;
} }
/* Global heading scale — used by admin + public pages */ /* Global heading scale — used by admin + public pages */
h1 { h1 {
font-size: var(--step-4); font-size: var(--step-4);
} }
h2 { h2 {
font-size: var(--step-3); font-size: var(--step-3);
} }
h3 { h3 {
font-size: var(--step-2); font-size: var(--step-2);
} }
h4 { h4 {
font-size: var(--step-1); font-size: var(--step-1);
} }
h5 { h5 {
font-size: var(--step--1); font-size: var(--step--1);
} }
h6 { h6 {
font-size: var(--step--2); font-size: var(--step--2);
} }
:where(h1, h2, h3, h4, h5, h6) { :where(h1, h2, h3, h4, h5, h6) {
font-family: var(--font-display); font-family: var(--font-display);
font-weight: 400; font-weight: 400;
margin: 0 0 var(--space-m) 0; margin: 0 0 var(--space-m) 0;
line-height: 1.15; line-height: 1.15;
} }
+304 -348
View File
@@ -4,341 +4,313 @@
============================================================ */ ============================================================ */
.tfe-main { .tfe-main {
flex: 1; flex: 1;
min-height: 0; min-height: 0;
overflow: hidden; overflow: hidden;
padding: 0 var(--space-m) 0 var(--space-m);
}
/* Stacked article layout — fills main height */
.tfe-layout {
display: flex;
flex-direction: column;
gap: var(--space-xl);
width: 100%;
height: 100%;
min-height: 0;
}
/* Row 1: Author above Title (kept for backward compat, no longer used) */
.tfe-header-row {
display: flex;
flex-direction: column;
gap: var(--space-3xs);
} }
/* Two-column layout: left 40vw (info), right fills remaining (files) */ /* Two-column layout: left 40vw (info), right fills remaining (files) */
.tfe-content-row { .tfe-content-row {
display: grid; display: grid;
grid-template-columns: 40vw 1fr; grid-template-columns: 49vw 1fr;
gap: var(--space-xl); /* gap: var(--space-xl); */
flex: 1; width: 100%;
min-height: 0; height: 100%;
min-height: 0;
} }
.tfe-left-column,
.tfe-left-column {
display: grid;
overflow-y: auto;
min-width: 0;
padding: var(--space-xl) var(--space-m) var(--space-xl) var(--space-m);
}
.tfe-right-column { .tfe-right-column {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow-y: auto; overflow-y: auto;
min-width: 0; min-width: 0;
padding-top: var(--space-l); padding: var(--space-xl) var(--space-m) var(--space-xl) var(--space-m);
padding-bottom: var(--space-xl);
} }
/* Left column: stacks author, title, meta, synopsis — scrolls independently */ /* Left column: stacks author, title, meta, synopsis — scrolls independently */
.tfe-left-column { .tfe-left-column {
gap: var(--space-m); gap: var(--space-m);
/* to space the edge of the text and the scrollbar */ /* to space the edge of the text and the scrollbar */
padding-right: 0.5ch; padding-right: 0.5ch;
} }
/* Files container inside right column */ /* Files container inside right column — flex kept for PDF expand-to-fill behavior */
.tfe-files { .tfe-files {
display: flex; display: grid;
flex-direction: column; gap: var(--space-m);
gap: var(--space-m); }
flex: 1;
min-height: 0; .tfe-files:has(.pdf-expanded) {
height: 100%;
} }
.tfe-file-item { .tfe-file-item {
width: 100%; width: 100%;
min-width: 0; min-width: 0;
overflow: hidden; border-radius: var(--radius);
border-radius: var(--radius); }
.tfe-file-item:last-of-type {
padding-bottom: 4ch;
} }
.tfe-file-item:has(.pdf-embed-wrapper) { .tfe-file-item:has(.pdf-embed-wrapper) {
overflow: visible; overflow: visible;
} }
.tfe-file-item:has(.pdf-expanded) { .tfe-file-item:has(.pdf-expanded) {
flex: 1; min-height: 0;
min-height: 0; overflow: visible;
overflow: visible;
} }
.tfe-file-item:has(.tfe-file-iframe) { .tfe-file-item:has(.tfe-file-iframe) {
flex: 1; min-height: 0;
min-height: 0; overflow: visible;
overflow: visible;
} }
/* When a PDF is expanded, freeze the right column and hide /* When a PDF is expanded, freeze the right column and hide
sibling file items so they can't render above the expanded view. sibling file items so they can't render above the expanded view.
Also trim column padding so the PDF fills more vertical space. */ Also trim column padding so the PDF fills more vertical space. */
.tfe-right-column:has(.pdf-expanded) { .tfe-right-column:has(.pdf-expanded) {
overflow: hidden; overflow: hidden;
padding-top: var(--space-xs); padding-top: var(--space-xs);
padding-bottom: var(--space-xs); padding-bottom: var(--space-xs);
} }
.tfe-right-column:has(.pdf-expanded) .tfe-file-item:not(:has(.pdf-expanded)) { .tfe-right-column:has(.pdf-expanded) .tfe-file-item:not(:has(.pdf-expanded)) {
display: none; display: none;
} }
.tfe-file-item img { .tfe-file-item img {
width: 100%; width: 100%;
height: auto; height: auto;
display: block; display: block;
border-radius: var(--radius); border-radius: var(--radius);
user-select: none; user-select: none;
-webkit-user-drag: none; -webkit-user-drag: none;
} }
.tfe-file-item embed, .tfe-file-item embed,
.tfe-file-item video { .tfe-file-item video {
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
display: block; display: block;
border: none; border: none;
} }
.tfe-file-item video { .tfe-file-item video {
max-height: 500px; max-height: 500px;
} }
.tfe-file-item embed, .tfe-file-item embed,
.tfe-file-iframe { .tfe-file-iframe {
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
height: 100%; height: 100%;
min-height: 400px; min-height: 400px;
display: block; display: block;
border: none; border: none;
} }
.tfe-website-link { .tfe-website-link {
display: inline-flex; display: inline-grid;
align-items: center; grid-auto-flow: column;
gap: var(--space-3xs); align-items: center;
padding: var(--space-2xs) var(--space-xs); gap: var(--space-3xs);
font-size: var(--step--1); padding: var(--space-2xs) var(--space-xs);
color: var(--accent-primary); font-size: var(--step--1);
text-decoration: none; color: var(--accent-primary);
border: 1px solid var(--border); text-decoration: none;
border-radius: var(--radius); border: 1px solid var(--border);
margin-bottom: var(--space-2xs); border-radius: var(--radius);
margin-bottom: var(--space-2xs);
} }
.tfe-website-link:hover { .tfe-website-link:hover {
background: color-mix(in srgb, var(--accent-primary) 10%, var(--bg-primary)); background: color-mix(in srgb, var(--accent-primary) 10%, var(--bg-primary));
} }
.tfe-file-item figcaption { .tfe-file-item figcaption {
font-size: var(--step--2); font-size: var(--step--2);
color: var(--text-secondary); color: var(--text-secondary);
margin: var(--space-3xs) 0 0; margin: var(--space-3xs) 0 0;
font-style: italic; font-style: italic;
}
/* Synopsis column wrapper (context note + synopsis) */
.tfe-synopsis-column {
display: flex;
flex-direction: column;
gap: var(--space-xs);
} }
/* Contextual note above synopsis */ /* Contextual note above synopsis */
.tfe-context-note { .tfe-context-note {
font-style: italic; font-style: italic;
font-size: var(--step--1); font-size: var(--step--1);
line-height: 1.6; line-height: 1.6;
color: var(--text-secondary); color: var(--text-secondary);
margin: 0; margin: 0;
padding: var(--space-xs) var(--space-s); padding: var(--space-xs) var(--space-s);
background: color-mix(in srgb, var(--accent-primary) 10%, var(--bg-primary)); background: color-mix(in srgb, var(--accent-primary) 10%, var(--bg-primary));
border-radius: var(--radius); border-radius: var(--radius);
}
.tfe-synopsis-empty {
/* placeholder to maintain grid column */
} }
/* Author (p) — inline with title */ /* Author (p) — inline with title */
.tfe-author { .tfe-author {
font-family: var(--font-display); font-size: var(--step-1);
font-size: var(--step-1); font-weight: 400;
font-weight: 400; color: var(--text-primary);
color: var(--text-primary); margin: 0;
margin: 0; line-height: 1.3;
line-height: 1.3;
} }
/* Title (h1) — inherits global scale from base.css */ /* Title (h1) — inherits global scale from base.css */
.tfe-title { .tfe-title {
margin: 0; margin: 0;
font-size: var(--step-2);
} }
/* Metadata block */ /* Metadata block */
.tfe-meta { .tfe-meta {
display: flex; display: grid;
flex-direction: column; gap: var(--space-3xs);
gap: var(--space-3xs); font-size: var(--step--1);
font-size: var(--step--1); line-height: 1.4;
line-height: 1.4; margin: 0;
margin: 0;
} }
/* Each metadata line */ /* Each metadata line */
.tfe-meta-item { .tfe-meta-item {
margin: 0; margin: 0;
font-weight: 700; font-weight: 700;
} }
.tfe-meta-label { .tfe-meta-label {
font-weight: 300; font-weight: 300;
} }
.tfe-meta-item a { .tfe-meta-item a {
color: inherit; color: inherit;
font-weight: 700; font-weight: 700;
text-decoration: none; text-decoration: none;
} }
.tfe-meta-item a:hover { .tfe-meta-item a:hover {
color: var(--accent-primary); color: var(--accent-primary);
} }
/* Note field: align label to top, value in italics */ /* Note field: align label to top, value in italics */
.tfe-meta-item.tfe-meta-note { .tfe-meta-item.tfe-meta-note {
align-items: start; align-items: start;
} }
.tfe-note-value { .tfe-note-value {
font-style: italic; font-style: italic;
} }
/* Synopsis paragraph */ /* Synopsis paragraph */
.tfe-synopsis-text { .tfe-synopsis-text {
font-size: var(--step--1); font-size: var(--step--1);
line-height: 1.7; line-height: 1.7;
color: var(--text-primary); color: var(--text-primary);
margin: 0; margin: 0;
} }
/* Audio player */ /* Audio player */
.tfe-audio { .tfe-audio {
width: 100%; width: 100%;
margin: 0; margin: 0;
display: block; display: block;
} }
/* "Not available" and "no files" notices */ /* "Not available" and "no files" notices */
.tfe-restricted, .tfe-restricted,
.tfe-no-files { .tfe-no-files {
font-size: var(--step--1); font-size: var(--step--1);
color: var(--text-secondary); color: var(--text-secondary);
font-style: italic; font-style: italic;
padding: var(--space-s) 0; padding: var(--space-s) 0;
margin: 0; margin: 0;
} }
/* ============================================================ /* ============================================================
RESTRICTED ACCESS UI RESTRICTED ACCESS UI
============================================================ */ ============================================================ */
.tfe-restricted-access { .tfe-restricted-access {
background: var(--surface); background: var(--surface);
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: var(--radius); border-radius: var(--radius);
padding: var(--space-m); padding: var(--space-m);
display: flex; display: grid;
flex-direction: column; gap: var(--space-m);
gap: var(--space-m);
} }
.tfe-restricted-message { .tfe-restricted-message {
font-size: var(--step--1); font-size: var(--step--1);
color: var(--text-secondary); color: var(--text-secondary);
line-height: 1.6; line-height: 1.6;
margin: 0; margin: 0;
} }
.tfe-restricted-message strong { .tfe-restricted-message strong {
color: var(--text-primary); color: var(--text-primary);
display: block; display: block;
margin-bottom: var(--space-3xs); margin-bottom: var(--space-3xs);
font-size: var(--step-0); font-size: var(--step-0);
} }
.tfe-access-request-form { .tfe-access-request-form {
display: flex; display: grid;
flex-direction: column; gap: var(--space-s);
gap: var(--space-s);
} }
.tfe-access-request-form .form-group { .tfe-access-request-form .form-group {
display: flex; display: grid;
flex-direction: column; gap: var(--space-3xs);
gap: var(--space-3xs);
} }
.tfe-access-request-form label { .tfe-access-request-form label {
font-size: var(--step--1); font-size: var(--step--1);
font-weight: 400; font-weight: 400;
color: var(--text-primary); color: var(--text-primary);
} }
.tfe-access-request-form input[type="email"], .tfe-access-request-form input[type="email"],
.tfe-access-request-form textarea { .tfe-access-request-form textarea {
padding: var(--space-2xs) var(--space-3xs); padding: var(--space-2xs) var(--space-3xs);
} }
.tfe-btn-request-access { .tfe-btn-request-access {
/* deprecated alias for .btn--primary; kept for backward-compat */ margin-top: var(--space-3xs);
margin-top: var(--space-3xs);
}
.tfe-btn-request-access:hover:not(:disabled) {
/* handled by .btn--primary */
} }
.tfe-btn-request-access:disabled { .tfe-btn-request-access:disabled {
opacity: 0.6; opacity: 0.6;
cursor: not-allowed; cursor: not-allowed;
} }
.tfe-access-message { .tfe-access-message {
font-size: var(--step--1); font-size: var(--step--1);
padding: var(--space-2xs); padding: var(--space-2xs);
border-radius: var(--radius); border-radius: var(--radius);
margin-top: var(--space-3xs); margin-top: var(--space-3xs);
} }
.tfe-access-success { .tfe-access-success {
background: #f0fff4; background: #f0fff4;
border: 1px solid #48bb78; border: 1px solid #48bb78;
color: #22543d; color: #22543d;
} }
.tfe-access-error { .tfe-access-error {
background: #fff5f5; background: #fff5f5;
border: 1px solid #fc8181; border: 1px solid #fc8181;
color: #742a2a; color: #742a2a;
} }
.tfe-access-request-form input.input-error { .tfe-access-request-form input.input-error {
border-color: #fc8181; border-color: #fc8181;
outline-color: #fc8181; outline-color: #fc8181;
} }
/* ============================================================ /* ============================================================
@@ -346,242 +318,226 @@
============================================================ */ ============================================================ */
/*── Base wrapper ───────────────────────────── */ /*── Base wrapper ───────────────────────────── */
.pdf-embed-wrapper { .pdf-embed-wrapper {
position: relative; position: relative;
width: 100%; width: 100%;
height: auto; height: auto;
display: flex; display: grid;
flex-direction: column; background: var(--surface);
background: var(--surface); border: 1px solid var(--border);
border: 1px solid var(--border); border-radius: var(--radius);
border-radius: var(--radius); transition: height 0.35s ease, border-color 0.35s ease;
transition: height 0.35s ease, border-color 0.35s ease; outline: none;
outline: none;
} }
/* ── Collapsed state: thumbnail tile ────────── */ /* ── Collapsed state: thumbnail tile ────────── */
.pdf-collapsed { .pdf-collapsed {
cursor: pointer; cursor: pointer;
overflow: hidden; overflow: hidden;
display: flex; display: grid;
align-items: center; place-items: center;
justify-content: center; min-height: 200px;
position: relative; max-height: 350px;
min-height: 200px;
max-height: 350px;
} }
.pdf-thumbnail { .pdf-thumbnail {
display: block; display: block;
max-width: 100%; max-width: 100%;
max-height: 100%; max-height: 100%;
object-fit: contain; object-fit: contain;
} }
/* ── Overlay veil + enter button ────────────── */ /* ── Overlay veil + enter button ────────────── */
.pdf-overlay { .pdf-overlay {
position: absolute; position: absolute;
inset: 0; inset: 0;
z-index: 1; z-index: 1;
display: flex; display: grid;
align-items: center; place-items: center;
justify-content: center; background: rgb(0 0 0 / 0.15);
background: rgb(0 0 0 / 0.15); backdrop-filter: blur(4px) saturate(0.6);
backdrop-filter: blur(4px) saturate(0.6); transition: background 0.2s;
transition: background 0.2s;
} }
.pdf-overlay:hover { .pdf-overlay:hover {
background: rgb(0 0 0 / 0.08); background: rgb(0 0 0 / 0.08);
} }
/* Document type pill — top-left of the overlay */ /* Document type pill — top-left of the overlay */
.pdf-overlay-badge { .pdf-overlay-badge {
position: absolute; position: absolute;
top: var(--space-xs); top: var(--space-xs);
left: var(--space-xs); left: var(--space-xs);
z-index: 2; z-index: 2;
display: inline-block; display: inline-block;
padding: 0.15em 0.6em; padding: 0.15em 0.6em;
font-size: var(--step--2); font-size: var(--step--2);
font-weight: 500; font-weight: 500;
line-height: 1.4; line-height: 1.4;
color: color-mix(in srgb, var(--accent-primary) 90%, #000); color: color-mix(in srgb, var(--accent-primary) 90%, #000);
background: color-mix(in srgb, var(--accent-primary) 12%, transparent); background: color-mix(in srgb, var(--accent-primary) 12%, transparent);
border: 1px solid color-mix(in srgb, var(--accent-primary) 25%, transparent); border: 1px solid color-mix(in srgb, var(--accent-primary) 25%, transparent);
border-radius: var(--radius); border-radius: var(--radius);
} }
.pdf-enter-btn { .pdf-enter-btn {
display: inline-flex; display: inline-grid;
align-items: center; grid-auto-flow: column;
gap: var(--space-2xs); align-items: center;
padding: var(--space-xs) var(--space-m); gap: var(--space-2xs);
background: var(--accent-primary); padding: var(--space-xs) var(--space-m);
color: #fff; background: var(--accent-primary);
border: none; color: #fff;
border-radius: var(--radius); border: none;
font-size: var(--step-0); border-radius: var(--radius);
font-weight: 500; font-size: var(--step-0);
cursor: pointer; font-weight: 500;
box-shadow: 0 2px 8px rgb(0 0 0 / 0.2); cursor: pointer;
transition: transform 0.15s, box-shadow 0.15s; box-shadow: 0 2px 8px rgb(0 0 0 / 0.2);
transition: transform 0.15s, box-shadow 0.15s;
} }
.pdf-enter-btn:hover { .pdf-enter-btn:hover {
transform: translateY(-1px); transform: translateY(-1px);
box-shadow: 0 4px 12px rgb(0 0 0 / 0.25); box-shadow: 0 4px 12px rgb(0 0 0 / 0.25);
} }
/* ── Expanded state: wrapper becomes scroll panel ── */ /* ── Expanded state: wrapper becomes scroll panel ── */
/* Disable root-level overscroll (rubberbanding) while a PDF is open. */ /* Disable root-level overscroll (rubberbanding) while a PDF is open. */
body.pdf-viewer-open { body.pdf-viewer-open {
overscroll-behavior: none; overscroll-behavior: none;
} }
.pdf-expanded { .pdf-expanded {
/* Fill the right column from top to bottom (under the header). */ height: 100%;
height: 100%; min-height: 400px;
min-height: 400px; overflow-y: auto;
overflow-y: auto; overflow-x: hidden;
overflow-x: hidden; overscroll-behavior-y: contain;
overscroll-behavior-y: contain; border: 2px solid var(--accent-primary);
border: 2px solid var(--accent-primary); display: grid;
display: flex; justify-items: center;
flex-direction: column; background: color-mix(in srgb, var(--accent-secondary) 22%, transparent);
align-items: center;
background: color-mix(in srgb, var(--accent-secondary) 22%, transparent);
} }
/* ── Toolbar ────────────────────────────────── */ /* ── Toolbar ────────────────────────────────── */
.pdf-toolbar { .pdf-toolbar {
position: sticky; position: sticky;
align-self: stretch; justify-self: stretch;
top: 0; top: 0;
z-index: 2; z-index: 2;
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--space-3xs); gap: var(--space-3xs);
padding: var(--space-2xs) var(--space-xs); padding: var(--space-2xs) var(--space-xs);
background: var(--bg-primary); background: var(--bg-primary);
border-bottom: 1px solid var(--border); border-bottom: 1px solid var(--border);
border-radius: var(--radius); border-radius: var(--radius);
flex-shrink: 0; flex-shrink: 0;
font-size: var(--step--1); font-size: var(--step--1);
user-select: none; user-select: none;
overscroll-behavior: none; overscroll-behavior: none;
} }
.pdf-toolbar-btn { .pdf-toolbar-btn {
display: inline-flex; display: inline-grid;
align-items: center; place-items: center;
justify-content: center; width: 2em;
width: 2em; height: 2em;
height: 2em; padding: 0;
padding: 0; border: 1px solid var(--border);
border: 1px solid var(--border); border-radius: var(--radius);
border-radius: var(--radius); background: var(--surface);
background: var(--surface); color: var(--text-primary);
color: var(--text-primary); cursor: pointer;
cursor: pointer; font-size: inherit;
font-size: inherit; line-height: 1;
line-height: 1; transition: background 0.15s;
transition: background 0.15s;
} }
.pdf-toolbar-btn:hover { .pdf-toolbar-btn:hover {
background: color-mix(in srgb, var(--accent-primary) 15%, var(--surface)); background: color-mix(in srgb, var(--accent-primary) 15%, var(--surface));
} }
.pdf-toolbar-close { .pdf-toolbar-close {
margin-right: var(--space-xs); margin-right: var(--space-xs);
} }
.pdf-toolbar-label { .pdf-toolbar-label {
min-width: 4.5em; min-width: 4.5em;
text-align: center; text-align: center;
color: var(--text-secondary); color: var(--text-secondary);
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
} }
.pdf-toolbar-scale { .pdf-toolbar-scale {
min-width: 3em; min-width: 3em;
} }
/* ── Scroll container ────────────────────────── */ /* ── Canvas ─────────────────────────────────── */
.pdf-canvas { .pdf-canvas {
display: block; display: block;
width: 100%; width: 100%;
height: auto; height: auto;
box-shadow: 0 1px 4px rgb(0 0 0 / 0.12); box-shadow: 0 1px 4px rgb(0 0 0 / 0.12);
background: #fff; background: #fff;
flex-shrink: 0; flex-shrink: 0;
} }
.pdf-canvas:first-of-type { .pdf-canvas:first-of-type {
margin-top: var(--space-xs); margin-top: var(--space-xs);
} }
.pdf-canvas:last-of-type { .pdf-canvas:last-of-type {
margin-bottom: var(--space-xs); margin-bottom: var(--space-xs);
} }
.pdf-canvas + .pdf-canvas { .pdf-canvas + .pdf-canvas {
margin-top: var(--space-2xs); margin-top: var(--space-2xs);
} }
/* Responsive */ /* ── Responsive ─────────────────────────────── */
@media (max-width: 900px) { @media (max-width: 900px) {
.tfe-main { .tfe-main {
overflow-y: auto; overflow-y: auto;
} }
.tfe-layout { .tfe-content-row {
height: auto; grid-template-columns: 1fr;
min-height: auto; height: auto;
} }
.tfe-content-row { .tfe-left-column,
grid-template-columns: 1fr; .tfe-right-column {
flex: none; overflow-y: visible;
} }
.tfe-left-column, .tfe-title {
.tfe-right-column { font-size: var(--step-2);
overflow-y: visible; }
}
.tfe-title { /* PDF expands to full viewport on mobile */
font-size: var(--step-2); .pdf-expanded {
} position: fixed;
inset: 0;
z-index: 100;
height: auto;
min-height: unset;
background: color-mix(in srgb, var(--accent-secondary) 92%, #000 8%);
}
/* PDF expands to full viewport height on mobile, above everything */ .tfe-file-iframe {
.pdf-expanded { height: 100dvh;
position: fixed; }
inset: 0;
z-index: 100;
height: auto;
min-height: unset;
background: color-mix(in srgb, var(--accent-secondary) 92%, #000 8%);
}
.tfe-file-iframe {
height: 100dvh;
}
} }
@media (max-width: 600px) { @media (max-width: 600px) {
.tfe-main { .tfe-main {
padding: var(--space-m) var(--space-s) var(--space-l); padding: var(--space-m) var(--space-s) var(--space-l);
} }
.tfe-title { .tfe-title {
font-size: var(--step-1); font-size: var(--step-1);
} }
} }
+1 -1
View File
@@ -50,7 +50,7 @@ $sortArrow = function(string $col) use ($sortCol, $sortDir): string {
<th scope="col"><input type="checkbox" onchange="toggleAll(this)"></th> <th scope="col"><input type="checkbox" onchange="toggleAll(this)"></th>
<th scope="col"><a href="<?= $sortLink('identifier') ?>" class="admin-sort-link" hx-get="<?= htmlspecialchars($sortLink('identifier')) ?>" hx-target="#admin-table-wrap" hx-swap="innerHTML" hx-indicator="#admin-search-indicator" hx-push-url="true">ID<?= $sortArrow('identifier') ?></a></th> <th scope="col"><a href="<?= $sortLink('identifier') ?>" class="admin-sort-link" hx-get="<?= htmlspecialchars($sortLink('identifier')) ?>" hx-target="#admin-table-wrap" hx-swap="innerHTML" hx-indicator="#admin-search-indicator" hx-push-url="true">ID<?= $sortArrow('identifier') ?></a></th>
<th scope="col"><a href="<?= $sortLink('title') ?>" class="admin-sort-link" hx-get="<?= htmlspecialchars($sortLink('title')) ?>" hx-target="#admin-table-wrap" hx-swap="innerHTML" hx-indicator="#admin-search-indicator" hx-push-url="true">Titre<?= $sortArrow('title') ?></a></th> <th scope="col"><a href="<?= $sortLink('title') ?>" class="admin-sort-link" hx-get="<?= htmlspecialchars($sortLink('title')) ?>" hx-target="#admin-table-wrap" hx-swap="innerHTML" hx-indicator="#admin-search-indicator" hx-push-url="true">Titre<?= $sortArrow('title') ?></a></th>
<th scope="col"><a href="<?= $sortLink('authors') ?>" class="admin-sort-link" hx-get="<?= htmlspecialchars($sortLink('authors')) ?>" hx-target="#admin-table-wrap" hx-swap="innerHTML" hx-indicator="#admin-search-indicator" hx-push-url="true">Auteur(s)<?= $sortArrow('authors') ?></a></th> <th scope="col"><a href="<?= $sortLink('authors') ?>" class="admin-sort-link" hx-get="<?= htmlspecialchars($sortLink('authors')) ?>" hx-target="#admin-table-wrap" hx-swap="innerHTML" hx-indicator="#admin-search-indicator" hx-push-url="true">Auteur·ice(s)<?= $sortArrow('authors') ?></a></th>
<th scope="col"><a href="<?= $sortLink('year') ?>" class="admin-sort-link" hx-get="<?= htmlspecialchars($sortLink('year')) ?>" hx-target="#admin-table-wrap" hx-swap="innerHTML" hx-indicator="#admin-search-indicator" hx-push-url="true">Année<?= $sortArrow('year') ?></a></th> <th scope="col"><a href="<?= $sortLink('year') ?>" class="admin-sort-link" hx-get="<?= htmlspecialchars($sortLink('year')) ?>" hx-target="#admin-table-wrap" hx-swap="innerHTML" hx-indicator="#admin-search-indicator" hx-push-url="true">Année<?= $sortArrow('year') ?></a></th>
<th scope="col"><a href="<?= $sortLink('orientation') ?>" class="admin-sort-link" hx-get="<?= htmlspecialchars($sortLink('orientation')) ?>" hx-target="#admin-table-wrap" hx-swap="innerHTML" hx-indicator="#admin-search-indicator" hx-push-url="true">Orientation<?= $sortArrow('orientation') ?></a></th> <th scope="col"><a href="<?= $sortLink('orientation') ?>" class="admin-sort-link" hx-get="<?= htmlspecialchars($sortLink('orientation')) ?>" hx-target="#admin-table-wrap" hx-swap="innerHTML" hx-indicator="#admin-search-indicator" hx-push-url="true">Orientation<?= $sortArrow('orientation') ?></a></th>
<th scope="col"><a href="<?= $sortLink('ap_program') ?>" class="admin-sort-link" hx-get="<?= htmlspecialchars($sortLink('ap_program')) ?>" hx-target="#admin-table-wrap" hx-swap="innerHTML" hx-indicator="#admin-search-indicator" hx-push-url="true">AP<?= $sortArrow('ap_program') ?></a></th> <th scope="col"><a href="<?= $sortLink('ap_program') ?>" class="admin-sort-link" hx-get="<?= htmlspecialchars($sortLink('ap_program')) ?>" hx-target="#admin-table-wrap" hx-swap="innerHTML" hx-indicator="#admin-search-indicator" hx-push-url="true">AP<?= $sortArrow('ap_program') ?></a></th>
+11 -17
View File
@@ -1,9 +1,7 @@
<main class="tfe-main" id="main-content"> <main class="tfe-main" id="main-content">
<article class="tfe-layout"> <article class="tfe-content-row">
<!-- Two-column layout: left 40% (info), right 60% (files) --> <div class="tfe-left-column">
<div class="tfe-content-row">
<div class="tfe-left-column">
<p class="tfe-author"><?= htmlspecialchars( <p class="tfe-author"><?= htmlspecialchars(
$data["authors"] ?? "Auteur inconnu", $data["authors"] ?? "Auteur inconnu",
@@ -258,19 +256,17 @@
<?php endif; ?> <?php endif; ?>
</div> </div>
<div class="tfe-synopsis-column"> <?php if (!empty($data["context_note"])): ?>
<?php if (!empty($data["context_note"])): ?> <p class="tfe-context-note"><em>Note Contextuelle :</em><br><?= nl2br(htmlspecialchars($data["context_note"])) ?></p>
<p class="tfe-context-note"><em>Note Contextuelle :</em><br><?= nl2br(htmlspecialchars($data["context_note"])) ?></p> <?php endif; ?>
<?php endif; ?>
<?php if (!empty($data["synopsis"])): ?> <?php if (!empty($data["synopsis"])): ?>
<div class="tfe-synopsis-text"> <div class="tfe-synopsis-text">
<?= nl2br(htmlspecialchars($data["synopsis"])) ?> <?= nl2br(htmlspecialchars($data["synopsis"])) ?>
</div>
<?php else: ?>
<div class="tfe-synopsis-text tfe-synopsis-empty"></div>
<?php endif; ?>
</div> </div>
<?php else: ?>
<div class="tfe-synopsis-text tfe-synopsis-empty"></div>
<?php endif; ?>
</div><!-- /tfe-left-column --> </div><!-- /tfe-left-column -->
@@ -469,8 +465,6 @@
</div><!-- /tfe-right-column --> </div><!-- /tfe-right-column -->
</div>
</article> </article>
</main> </main>