tfe page: author above title, interne/externe jury split, rounded images, strip contact protocol

This commit is contained in:
Pontoporeia
2026-04-07 14:29:29 +02:00
parent 547d581e26
commit 3a1cd5b43e
4 changed files with 91 additions and 47 deletions

View File

@@ -1,6 +1,14 @@
# TODO
## Done
- [x] Redesign TFE detail page
- [x] Author moved above title (smaller body font)
- [x] Remove "← Retour" back link
- [x] Split jury promoteurs into interne/externe using `getThesisJury()`
- [x] Jury fields order: promoteur interne → externe → président → lecteurs
- [x] Contact URL strips `http(s)://` prefix for display
- [x] Right-column images get `border-radius: 8px`
- [x] Remove orphan `.tfe-back-link` CSS rule
- [x] Improve À propos page layout
- [x] Replace two-column (prose + aside) with sticky-TOC-nav + main-content layout
- [x] Sticky left nav with section anchors (À propos, Contacts, Crédits + erg link)

View File

@@ -32,12 +32,14 @@
gap: 1.5rem;
}
/* Back link — top of left column */
.tfe-back-link {
font-size: .88rem;
color: var(--text-tertiary);
text-decoration: underline;
text-underline-offset: 2px;
/* Author (p) — above title, smaller */
.tfe-author {
font-family: var(--font-body);
font-size: 1rem;
font-weight: 400;
color: var(--text-primary);
margin: 0;
line-height: 1.4;
}
/* Title (h1) — primary heading, very large */
@@ -51,17 +53,6 @@
letter-spacing: -0.01em;
}
/* Author (p) — large but secondary */
.tfe-author {
font-family: var(--font-display);
font-size: 1.9rem;
font-weight: 400;
color: var(--text-primary);
margin: 0;
line-height: 1.15;
letter-spacing: -0.01em;
}
/* Metadata description list — target <dl> directly inside article > header */
article dl {
display: flex;
@@ -125,12 +116,14 @@ article dl dd a {
aside figure {
overflow: hidden;
margin: 0;
border-radius: 8px;
}
aside figure img {
width: 100%;
height: auto;
display: block;
border-radius: 8px;
}
aside figure embed,
@@ -188,10 +181,6 @@ aside figcaption {
.tfe-title {
font-size: 1.7rem;
}
.tfe-author {
font-size: 1.5rem;
}
}
@media (max-width: 600px) {
@@ -202,8 +191,4 @@ aside figcaption {
.tfe-title {
font-size: 1.4rem;
}
.tfe-author {
font-size: 1.25rem;
}
}

View File

@@ -16,9 +16,9 @@ extract($ctrl->handle());
<!-- LEFT: info — article header -->
<header class="tfe-left">
<a href="index.php" class="tfe-back-link">← Retour</a>
<!-- Author above title -->
<p class="tfe-author"><?= htmlspecialchars($data['authors'] ?? 'Auteur inconnu') ?></p>
<!-- Title is the primary heading; author is metadata -->
<h1 class="tfe-title">
<?= htmlspecialchars($data['title']) ?>
<?php if (!empty($data['subtitle'])): ?>
@@ -26,8 +26,6 @@ extract($ctrl->handle());
<?php endif; ?>
</h1>
<p class="tfe-author"><?= htmlspecialchars($data['authors'] ?? 'Auteur inconnu') ?></p>
<dl>
<?php if (!empty($data['orientation'])): ?>
<div>
@@ -78,24 +76,31 @@ extract($ctrl->handle());
</div>
<?php endif; ?>
<?php if (!empty($data['jury_president'])): ?>
<?php if (!empty($promoteursInternes)): ?>
<div>
<dt>Promoteur·ice interne :</dt>
<dd><?= htmlspecialchars(implode(', ', $promoteursInternes)) ?></dd>
</div>
<?php endif; ?>
<?php if (!empty($promoteursExternes)): ?>
<div>
<dt>Promoteur·ice externe :</dt>
<dd><?= htmlspecialchars(implode(', ', $promoteursExternes)) ?></dd>
</div>
<?php endif; ?>
<?php if (!empty($juryPresidents)): ?>
<div>
<dt>Président·e du jury :</dt>
<dd><?= htmlspecialchars($data['jury_president']) ?></dd>
<dd><?= htmlspecialchars(implode(', ', $juryPresidents)) ?></dd>
</div>
<?php endif; ?>
<?php if (!empty($data['jury_promoteurs'])): ?>
<div>
<dt>Promoteur·ice :</dt>
<dd><?= htmlspecialchars($data['jury_promoteurs']) ?></dd>
</div>
<?php endif; ?>
<?php if (!empty($data['jury_lecteurs'])): ?>
<?php if (!empty($juryLecteurs)): ?>
<div>
<dt>Lecteur·ices :</dt>
<dd><?= htmlspecialchars($data['jury_lecteurs']) ?></dd>
<dd><?= htmlspecialchars(implode(', ', $juryLecteurs)) ?></dd>
</div>
<?php endif; ?>
@@ -121,11 +126,15 @@ extract($ctrl->handle());
<?php endif; ?>
<?php if (!empty($data['baiu_link'])): ?>
<?php
$_contactHref = htmlspecialchars($data['baiu_link']);
$_contactLabel = preg_replace('#^https?://#i', '', rtrim($data['baiu_link'], '/'));
?>
<div>
<dt>Contact :</dt>
<dd>
<a href="<?= htmlspecialchars($data['baiu_link']) ?>" target="_blank" rel="noopener">
<?= htmlspecialchars($data['baiu_link']) ?>
<a href="<?= $_contactHref ?>" target="_blank" rel="noopener">
<?= htmlspecialchars($_contactLabel) ?>
<span class="sr-only">(ouvre dans un nouvel onglet)</span>
</a>
</dd>

View File

@@ -78,6 +78,10 @@ class TfeController
// Caption (WebVTT) files — N-th VTT is paired with the N-th <video>
$captionFiles = $this->collectCaptionPaths($data['files'] ?? []);
// Jury members with interne/externe split
$jury = $this->db->getThesisJury($thesisId);
$juryByRole = $this->splitJuryByRole($jury);
// Page meta
$metaDescription = $this->buildMetaDescription($data['synopsis'] ?? '');
$ogTags = $this->buildOgTags($data, $thesisId, $metaDescription);
@@ -92,6 +96,10 @@ class TfeController
'accessTypeId' => $accessTypeId,
'isInterdit' => $isInterdit,
'captionFiles' => $captionFiles,
'juryPresidents' => $juryByRole['presidents'],
'promoteursInternes' => $juryByRole['internes'],
'promoteursExternes' => $juryByRole['externes'],
'juryLecteurs' => $juryByRole['lecteurs'],
// Page meta
'pageTitle' => $pageTitle,
@@ -169,6 +177,40 @@ class TfeController
];
}
/**
* Split jury members by role and internal/external flag.
*
* @param array<int, array<string, mixed>> $jury
* @return array{presidents: list<string>, internes: list<string>, externes: list<string>, lecteurs: list<string>}
*/
private function splitJuryByRole(array $jury): array
{
$result = ['presidents' => [], 'internes' => [], 'externes' => [], 'lecteurs' => []];
foreach ($jury as $member) {
$name = $member['name'] ?? '';
if ($name === '') continue;
switch ($member['role']) {
case 'president':
$result['presidents'][] = $name;
break;
case 'promoteur':
if ((int)$member['is_external'] === 1) {
$result['externes'][] = $name;
} else {
$result['internes'][] = $name;
}
break;
case 'lecteur':
$result['lecteurs'][] = $name;
break;
}
}
return $result;
}
/**
* Return an ordered list of VTT caption file paths from the files array.
* The N-th entry corresponds to the N-th <video> element in document order.