mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 19:19:19 +02:00
tfe page: author above title, interne/externe jury split, rounded images, strip contact protocol
This commit is contained in:
8
TODO.md
8
TODO.md
@@ -1,6 +1,14 @@
|
|||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
## Done
|
## 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] Improve À propos page layout
|
||||||
- [x] Replace two-column (prose + aside) with sticky-TOC-nav + main-content 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)
|
- [x] Sticky left nav with section anchors (À propos, Contacts, Crédits + erg link)
|
||||||
|
|||||||
@@ -32,12 +32,14 @@
|
|||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Back link — top of left column */
|
/* Author (p) — above title, smaller */
|
||||||
.tfe-back-link {
|
.tfe-author {
|
||||||
font-size: .88rem;
|
font-family: var(--font-body);
|
||||||
color: var(--text-tertiary);
|
font-size: 1rem;
|
||||||
text-decoration: underline;
|
font-weight: 400;
|
||||||
text-underline-offset: 2px;
|
color: var(--text-primary);
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Title (h1) — primary heading, very large */
|
/* Title (h1) — primary heading, very large */
|
||||||
@@ -51,17 +53,6 @@
|
|||||||
letter-spacing: -0.01em;
|
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 */
|
/* Metadata description list — target <dl> directly inside article > header */
|
||||||
article dl {
|
article dl {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -125,12 +116,14 @@ article dl dd a {
|
|||||||
aside figure {
|
aside figure {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
aside figure img {
|
aside figure img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
display: block;
|
display: block;
|
||||||
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
aside figure embed,
|
aside figure embed,
|
||||||
@@ -188,10 +181,6 @@ aside figcaption {
|
|||||||
.tfe-title {
|
.tfe-title {
|
||||||
font-size: 1.7rem;
|
font-size: 1.7rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tfe-author {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
@@ -202,8 +191,4 @@ aside figcaption {
|
|||||||
.tfe-title {
|
.tfe-title {
|
||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tfe-author {
|
|
||||||
font-size: 1.25rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ extract($ctrl->handle());
|
|||||||
|
|
||||||
<!-- LEFT: info — article header -->
|
<!-- LEFT: info — article header -->
|
||||||
<header class="tfe-left">
|
<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">
|
<h1 class="tfe-title">
|
||||||
<?= htmlspecialchars($data['title']) ?>
|
<?= htmlspecialchars($data['title']) ?>
|
||||||
<?php if (!empty($data['subtitle'])): ?>
|
<?php if (!empty($data['subtitle'])): ?>
|
||||||
@@ -26,8 +26,6 @@ extract($ctrl->handle());
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p class="tfe-author"><?= htmlspecialchars($data['authors'] ?? 'Auteur inconnu') ?></p>
|
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
<?php if (!empty($data['orientation'])): ?>
|
<?php if (!empty($data['orientation'])): ?>
|
||||||
<div>
|
<div>
|
||||||
@@ -78,24 +76,31 @@ extract($ctrl->handle());
|
|||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?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>
|
<div>
|
||||||
<dt>Président·e du jury :</dt>
|
<dt>Président·e du jury :</dt>
|
||||||
<dd><?= htmlspecialchars($data['jury_president']) ?></dd>
|
<dd><?= htmlspecialchars(implode(', ', $juryPresidents)) ?></dd>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (!empty($data['jury_promoteurs'])): ?>
|
<?php if (!empty($juryLecteurs)): ?>
|
||||||
<div>
|
|
||||||
<dt>Promoteur·ice :</dt>
|
|
||||||
<dd><?= htmlspecialchars($data['jury_promoteurs']) ?></dd>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if (!empty($data['jury_lecteurs'])): ?>
|
|
||||||
<div>
|
<div>
|
||||||
<dt>Lecteur·ices :</dt>
|
<dt>Lecteur·ices :</dt>
|
||||||
<dd><?= htmlspecialchars($data['jury_lecteurs']) ?></dd>
|
<dd><?= htmlspecialchars(implode(', ', $juryLecteurs)) ?></dd>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
@@ -121,11 +126,15 @@ extract($ctrl->handle());
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (!empty($data['baiu_link'])): ?>
|
<?php if (!empty($data['baiu_link'])): ?>
|
||||||
|
<?php
|
||||||
|
$_contactHref = htmlspecialchars($data['baiu_link']);
|
||||||
|
$_contactLabel = preg_replace('#^https?://#i', '', rtrim($data['baiu_link'], '/'));
|
||||||
|
?>
|
||||||
<div>
|
<div>
|
||||||
<dt>Contact :</dt>
|
<dt>Contact :</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<a href="<?= htmlspecialchars($data['baiu_link']) ?>" target="_blank" rel="noopener">
|
<a href="<?= $_contactHref ?>" target="_blank" rel="noopener">
|
||||||
<?= htmlspecialchars($data['baiu_link']) ?>
|
<?= htmlspecialchars($_contactLabel) ?>
|
||||||
<span class="sr-only">(ouvre dans un nouvel onglet)</span>
|
<span class="sr-only">(ouvre dans un nouvel onglet)</span>
|
||||||
</a>
|
</a>
|
||||||
</dd>
|
</dd>
|
||||||
|
|||||||
@@ -78,6 +78,10 @@ class TfeController
|
|||||||
// Caption (WebVTT) files — N-th VTT is paired with the N-th <video>
|
// Caption (WebVTT) files — N-th VTT is paired with the N-th <video>
|
||||||
$captionFiles = $this->collectCaptionPaths($data['files'] ?? []);
|
$captionFiles = $this->collectCaptionPaths($data['files'] ?? []);
|
||||||
|
|
||||||
|
// Jury members with interne/externe split
|
||||||
|
$jury = $this->db->getThesisJury($thesisId);
|
||||||
|
$juryByRole = $this->splitJuryByRole($jury);
|
||||||
|
|
||||||
// Page meta
|
// Page meta
|
||||||
$metaDescription = $this->buildMetaDescription($data['synopsis'] ?? '');
|
$metaDescription = $this->buildMetaDescription($data['synopsis'] ?? '');
|
||||||
$ogTags = $this->buildOgTags($data, $thesisId, $metaDescription);
|
$ogTags = $this->buildOgTags($data, $thesisId, $metaDescription);
|
||||||
@@ -87,11 +91,15 @@ class TfeController
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
// Core data
|
// Core data
|
||||||
'thesisId' => $thesisId,
|
'thesisId' => $thesisId,
|
||||||
'data' => $data,
|
'data' => $data,
|
||||||
'accessTypeId' => $accessTypeId,
|
'accessTypeId' => $accessTypeId,
|
||||||
'isInterdit' => $isInterdit,
|
'isInterdit' => $isInterdit,
|
||||||
'captionFiles' => $captionFiles,
|
'captionFiles' => $captionFiles,
|
||||||
|
'juryPresidents' => $juryByRole['presidents'],
|
||||||
|
'promoteursInternes' => $juryByRole['internes'],
|
||||||
|
'promoteursExternes' => $juryByRole['externes'],
|
||||||
|
'juryLecteurs' => $juryByRole['lecteurs'],
|
||||||
|
|
||||||
// Page meta
|
// Page meta
|
||||||
'pageTitle' => $pageTitle,
|
'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.
|
* 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.
|
* The N-th entry corresponds to the N-th <video> element in document order.
|
||||||
|
|||||||
Reference in New Issue
Block a user