Refactor about.php

- Hardcode source code URL and credits in about template, remove from DB/admin interface; only contacts remains editable
- Merge apropos editables into one À propos section, remove charte, add editable source code URL
This commit is contained in:
Pontoporeia
2026-05-07 18:44:30 +02:00
parent 24d68dda59
commit e0c748d8e7
15 changed files with 259 additions and 250 deletions

View File

@@ -1,7 +1,7 @@
<?php
/**
* Save handler for apropos contents (contacts, credits).
* Structure: groups[] with label/role, each having entries[] of {text, url, email}.
* Save handler for apropos contacts.
* Structure: groups[] with role, each having entries[] of {text, url, email}.
*/
require_once __DIR__ . "/../../../bootstrap.php";
require_once __DIR__ . '/../../../src/AdminAuth.php';
@@ -13,7 +13,7 @@ if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) ||
die("Erreur de sécurité : token invalide.");
}
$allowedKeys = ['contacts', 'credits'];
$allowedKeys = ['contacts'];
$aproposKey = $_POST['apropos_key'] ?? '';
if (!in_array($aproposKey, $allowedKeys)) {
die("Clé invalide.");
@@ -28,38 +28,22 @@ try {
$cleaned = [];
foreach ($groups as $group) {
if ($aproposKey === 'credits') {
$label = trim($group['label'] ?? '');
if ($label === '') continue;
$entries = [];
foreach ($group['entries'] ?? [] as $entry) {
$text = trim($entry['text'] ?? '');
if ($text === '') continue;
$e = ['text' => $text];
$url = trim($entry['url'] ?? '');
if ($url !== '') $e['url'] = $url;
$entries[] = $e;
}
if (empty($entries)) continue;
$cleaned[] = ['label' => $label, 'entries' => $entries];
} else { // contacts
$role = trim($group['role'] ?? '');
if ($role === '') continue;
$entries = [];
foreach ($group['entries'] ?? [] as $entry) {
$text = trim($entry['text'] ?? '');
if ($text === '') continue;
$e = [
'text' => $text,
'email' => trim($entry['email'] ?? ''),
];
$url = trim($entry['url'] ?? '');
if ($url !== '') $e['url'] = $url;
$entries[] = $e;
}
if (empty($entries)) continue;
$cleaned[] = ['role' => $role, 'entries' => $entries];
$role = trim($group['role'] ?? '');
if ($role === '') continue;
$entries = [];
foreach ($group['entries'] ?? [] as $entry) {
$text = trim($entry['text'] ?? '');
if ($text === '') continue;
$e = [
'text' => $text,
'email' => trim($entry['email'] ?? ''),
];
$url = trim($entry['url'] ?? '');
if ($url !== '') $e['url'] = $url;
$entries[] = $e;
}
if (empty($entries)) continue;
$cleaned[] = ['role' => $role, 'entries' => $entries];
}
if (empty($cleaned)) {

View File

@@ -13,7 +13,7 @@ if (!isset($_POST['csrf_token'], $_SESSION['csrf_token'])
exit;
}
$allowedSlugs = ['about', 'licenses', 'charte'];
$allowedSlugs = ['about', 'licenses'];
$slug = $_POST['slug'] ?? '';
$content = $_POST['content'] ?? '';

View File

@@ -9,8 +9,8 @@ if (empty($_SESSION["csrf_token"])) {
$_SESSION["csrf_token"] = bin2hex(random_bytes(32));
}
$allowedPageSlugs = ["about", "licenses", "charte"];
$allowedApropos = ["contacts", "credits"];
$allowedPageSlugs = ["about", "licenses"];
$allowedApropos = ["contacts"];
$pageSlug = $_GET["slug"] ?? "";
$aproposKey = $_GET["apropos"] ?? "";
@@ -40,7 +40,13 @@ try {
die("Page introuvable.");
}
$editTitle = $page["title"];
$editType = "page";
if ($pageSlug === 'about') {
$editType = 'about_page';
$aboutContacts = $db->getAproposContent('contacts');
$aboutContacts = is_array($aboutContacts) ? $aboutContacts : [];
} else {
$editType = "page";
}
} elseif ($formHelpKey) {
$editType = "form_help";
$formHelpContent = $db->getFormHelpBlock($formHelpKey);
@@ -50,7 +56,6 @@ try {
$value = $db->getAproposContent($aproposKey);
$editTitle = match($aproposKey) {
'contacts' => 'Contacts',
'credits' => 'Crédits',
};
}
} catch (Exception $e) {
@@ -58,8 +63,15 @@ try {
}
$pageTitle = "Éditer : " . $editTitle;
$extraJs = ["/assets/js/overtype.min.js"];
$extraJsInline = <<<'JS'
$initialContent = '';
$extraJs = [];
$extraJsInline = '';
if ($editType === 'page' || $editType === 'about_page') {
$initialContent = $page["content"] ?? "";
$extraJs = ["/assets/js/overtype.min.js"];
$extraJsInline = <<<'JS'
var OT = window.OverType.default || window.OverType;
var hidden = document.getElementById('content');
var editor = new OT(document.getElementById('editor'), {
@@ -69,12 +81,19 @@ var editor = new OT(document.getElementById('editor'), {
onChange: function(value) { hidden.value = value; }
});
JS;
$initialContent = '';
if ($editType === 'page') {
$initialContent = $page["content"] ?? "";
} elseif ($editType === 'form_help') {
$initialContent = $formHelpContent;
$extraJs = ["/assets/js/overtype.min.js"];
$extraJsInline = <<<'JS'
var OT = window.OverType.default || window.OverType;
var hidden = document.getElementById('content');
var editor = new OT(document.getElementById('editor'), {
value: hidden.value,
minHeight: '400px',
spellcheck: false,
onChange: function(value) { hidden.value = value; }
});
JS;
}
$isAdmin = true;

View File

@@ -10,9 +10,12 @@ if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
$allowedPageSlugs = ['about', 'licenses'];
try {
$db = new Database();
$pages = $db->getAllPages();
$allPages = $db->getAllPages();
$pages = array_values(array_filter($allPages, fn($p) => in_array($p['slug'], $allowedPageSlugs, true)));
$aproposKeys = $db->getAllAproposContents();
$formHelpBlocks = $db->getAllFormHelpBlocks();
} catch (Exception $e) {

View File

@@ -89,6 +89,21 @@
opacity: 0.75;
}
.apropos-toc-source {
padding-top: var(--space-xs);
}
.apropos-toc-source a {
font-size: var(--step--2);
color: var(--accent-primary);
text-decoration: none;
transition: opacity 0.15s;
}
.apropos-toc-source a:hover {
opacity: 0.75;
}
/* ------------------------------------------------------------------ */
/* Right — main content area */
/* ------------------------------------------------------------------ */

View File

@@ -21,15 +21,12 @@ class AboutController
if (empty(trim($rawContent)) || trim($rawContent) === 'Contenu à venir') {
$rawContent = $this->defaultContent;
}
$contacts = $db->getAproposContent('contacts');
$credits = $db->getAproposContent('credits');
$contacts = is_array($contacts) && !empty($contacts) ? $contacts : null;
$credits = is_array($credits) && !empty($credits) ? $credits : null;
$contacts = $db->getAproposContent('contacts');
$contacts = is_array($contacts) && !empty($contacts) ? $contacts : null;
} catch (Exception $e) {
error_log('Error loading about page: ' . $e->getMessage());
$rawContent = $this->defaultContent;
$contacts = null;
$credits = null;
}
$pd = new Parsedown();
@@ -39,7 +36,6 @@ class AboutController
'currentNav' => 'apropos',
'aboutHtml' => $pd->text($rawContent),
'contacts' => $contacts,
'credits' => $credits,
'pageTitle' => 'À Propos XAMXAM',
'metaDescription' => "À propos de XAMXAM, le répertoire des mémoires de fin d'études de l'erg École de Recherches Graphiques de Bruxelles.",
'extraCss' => ['/assets/css/apropos.css'],

View File

@@ -2239,31 +2239,21 @@ class Database
return null;
}
$value = $row['value'];
if ($key === 'erg_url') {
return $value;
}
$decoded = json_decode($value, true);
$decoded = json_decode($row['value'], true);
return is_array($decoded) ? $decoded : null;
}
/**
* Save an apropos content value by key.
* @param string $key
* @param mixed $value array for contacts/credits, string for erg_url
* Save an apropos content value by key (contacts JSON).
*/
public function saveAproposContent(string $key, $value): void
public function saveAproposContent(string $key, array $value): void
{
$stmt = $this->pdo->prepare('SELECT id FROM apropos_contents WHERE key = ?');
$stmt->execute([$key]);
if (!$stmt->fetch()) {
throw new Exception("Apropos key not found: $key");
}
$storedValue = is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : (string)$value;
$storedValue = json_encode($value, JSON_UNESCAPED_UNICODE);
$stmt = $this->pdo->prepare(
'UPDATE apropos_contents SET value = ?, updated_at = CURRENT_TIMESTAMP WHERE key = ?'
'INSERT INTO apropos_contents (key, value, updated_at) VALUES (?, ?, CURRENT_TIMESTAMP)
ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = CURRENT_TIMESTAMP'
);
$stmt->execute([$storedValue, $key]);
$stmt->execute([$key, $storedValue]);
}
/**

View File

@@ -11,3 +11,4 @@
{"timestamp":"2026-05-05T16:57:57+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0","resource":"thesis","action":"publish","status":"success","context":{"count":15,"ids":[53,52,51,50,49,48,47,46,45,44,43,42,41,40,39]}}
{"timestamp":"2026-05-05T16:58:02+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0","resource":"thesis","action":"publish","status":"success","context":{"count":25,"ids":[178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154]}}
{"timestamp":"2026-05-07T16:15:27+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0","resource":"system","action":"files_export","status":"success","context":{"file_count":0,"byte_size":248}}
{"timestamp":"2026-05-07T16:56:50+00:00","ip":"127.0.0.1","user_agent":"Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0","resource":"apropos","action":"edit","status":"success","context":{"key":"credits"}}

View File

@@ -408,8 +408,8 @@ SELECT * FROM smtp_settings WHERE id = 1;
CREATE TABLE IF NOT EXISTS apropos_contents (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key TEXT NOT NULL UNIQUE, -- 'contacts', 'credits', 'erg_url'
value TEXT, -- JSON array or plain string
key TEXT NOT NULL UNIQUE, -- 'contacts'
value TEXT, -- JSON array
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
@@ -433,23 +433,6 @@ INSERT OR IGNORE INTO apropos_contents (key, value) VALUES
{"text": "Brigitte Ledune", "url": "", "email": "brigitte.ledune@erg.be"}
]
}
]'),
('credits', '[
{
"label": "Design & développement",
"entries": [
{"text": "Olivia Marly", "url": ""},
{"text": "Théophile Gerveau-Mercie", "url": ""},
{"text": "Théo Hennequin", "url": ""}
]
},
{
"label": "Typographies",
"entries": [
{"text": "Ductus (Amélie Dumont)", "url": ""},
{"text": "BBB DM Sans", "url": ""}
]
}
]');
-- ============================================================================

View File

@@ -0,0 +1,115 @@
<?php
/**
* Reusable partial for apropos contacts groups form.
* Expected variables:
* $aproposKey string 'contacts'
* $groups array Existing groups data
*/
?>
<form action="/admin/actions/apropos.php" method="post" class="admin-form" id="apropos-form-<?= $aproposKey ?>">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
<input type="hidden" name="apropos_key" value="<?= htmlspecialchars($aproposKey) ?>">
<?php foreach ($groups as $gi => $group): ?>
<fieldset class="apropos-group">
<legend>Contact <?= $gi + 1 ?></legend>
<label for="group_f_<?= $aproposKey ?>_<?= $gi ?>_role">Rôle :</label>
<input type="text" id="group_f_<?= $aproposKey ?>_<?= $gi ?>_role"
name="groups[<?= $gi ?>][role]"
value="<?= htmlspecialchars($group['role'] ?? '') ?>">
<?php $entries = is_array($group['entries'] ?? null) ? $group['entries'] : []; ?>
<?php foreach ($entries as $ei => $entry): ?>
<div class="apropos-entry">
<label for="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_text">Nom :</label>
<input type="text" id="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_text"
name="groups[<?= $gi ?>][entries][<?= $ei ?>][text]"
value="<?= htmlspecialchars($entry['text'] ?? '') ?>">
<label for="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_email">Email :</label>
<input type="email" id="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_email"
name="groups[<?= $gi ?>][entries][<?= $ei ?>][email]"
value="<?= htmlspecialchars($entry['email'] ?? '') ?>">
<label for="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_url">Lien (optionnel) :</label>
<input type="url" id="entry_f_<?= $aproposKey ?>_<?= $gi ?>_<?= $ei ?>_url"
name="groups[<?= $gi ?>][entries][<?= $ei ?>][url]"
value="<?= htmlspecialchars($entry['url'] ?? '') ?>">
</div>
<?php endforeach; ?>
<button type="button" class="btn btn--primary btn--sm add-entry-btn-f"
data-group="<?= $gi ?>"
data-key="<?= $aproposKey ?>">+ Ajouter une entrée</button>
</fieldset>
<?php endforeach; ?>
<button type="button" class="btn btn--primary add-group-btn-f"
data-key="<?= $aproposKey ?>">+ Ajouter un contact</button>
<div class="admin-form-footer">
<button type="submit" class="btn btn--primary">Enregistrer</button>
<a href="/admin/contenus.php" class="btn btn--secondary admin-cancel-link">Annuler</a>
</div>
<template id="entry-template-f-<?= $aproposKey ?>">
<div class="apropos-entry">
<label>Entrée :</label>
<input type="text" name="groups[{{gi}}][entries][{{ei}}][text]">
<label>Email :</label>
<input type="email" name="groups[{{gi}}][entries][{{ei}}][email]">
<label>Lien (optionnel) :</label>
<input type="url" name="groups[{{gi}}][entries][{{ei}}][url]">
</div>
</template>
<template id="group-template-f-<?= $aproposKey ?>">
<fieldset class="apropos-group">
<legend>Contact {{gi}}</legend>
<label>Rôle :</label>
<input type="text" name="groups[{{gi}}][role]">
<button type="button" class="btn btn--primary btn--sm add-entry-btn-f"
data-group="{{gi}}"
data-key="<?= $aproposKey ?>">+ Ajouter une entrée</button>
</fieldset>
</template>
</form>
<script>
(function() {
var key = '<?= $aproposKey ?>';
var form = document.getElementById('apropos-form-' + key);
var groupCount = <?= count($groups) ?>;
var entryTpl = document.getElementById('entry-template-f-' + key).innerHTML;
var groupTpl = document.getElementById('group-template-f-' + key).innerHTML;
form.querySelectorAll('.add-entry-btn-f').forEach(function(btn) {
btn.addEventListener('click', function() {
var gi = parseInt(this.dataset.group);
var fieldset = this.closest('fieldset');
var entryCount = fieldset.querySelectorAll('.apropos-entry').length;
var html = entryTpl.replaceAll('{{gi}}', gi).replaceAll('{{ei}}', entryCount);
this.insertAdjacentHTML('beforebegin', html);
});
});
form.querySelector('.add-group-btn-f').addEventListener('click', function() {
groupCount++;
var html = groupTpl.replaceAll('{{gi}}', groupCount);
this.insertAdjacentHTML('beforebegin', html);
var newGroup = this.previousElementSibling;
if (newGroup && newGroup.classList.contains('apropos-group')) {
var btn = newGroup.querySelector('.add-entry-btn-f');
if (btn) {
btn.dataset.group = groupCount;
btn.addEventListener('click', function() {
var gi = parseInt(this.dataset.group);
var fieldset = this.closest('fieldset');
var entryCount = fieldset.querySelectorAll('.apropos-entry').length;
var html = entryTpl.replaceAll('{{gi}}', gi).replaceAll('{{ei}}', entryCount);
this.insertAdjacentHTML('beforebegin', html);
});
}
}
});
})();
</script>

View File

@@ -1,7 +1,34 @@
<main id="main-content">
<h1>Éditer : <?= htmlspecialchars($editTitle) ?></h1>
<?php if ($editType === 'page'): ?>
<?php if ($editType === 'about_page'): ?>
<!-- ── Markdown content ──────────────────────────────────────────────── -->
<h2>Contenu de la page</h2>
<form action="/admin/actions/page.php" method="post" class="admin-form">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION["csrf_token"]) ?>">
<input type="hidden" name="slug" value="about">
<label for="editor">Contenu (Markdown) :</label>
<input type="hidden" id="content" name="content"
value="<?= htmlspecialchars($initialContent) ?>">
<div id="editor"></div>
<div class="admin-form-footer">
<button type="submit" class="btn btn--primary">Enregistrer</button>
<a href="/admin/contenus.php" class="btn btn--secondary admin-cancel-link">Annuler</a>
</div>
</form>
<!-- ── Contacts ──────────────────────────────────────────────────────── -->
<h2 style="margin-top:3rem;">Contacts</h2>
<?php
$aproposKey = 'contacts';
$groups = $aboutContacts ?? [];
include APP_ROOT . '/templates/admin/apropos-groups-form.php';
?>
<?php elseif ($editType === 'page' && $pageSlug !== 'about'): ?>
<form action="/admin/actions/page.php" method="post" class="admin-form">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION["csrf_token"]) ?>">
<input type="hidden" name="slug" value="<?= htmlspecialchars($pageSlug) ?>">
@@ -38,125 +65,6 @@
<?php
$groups = is_array($value) ? $value : [];
?>
<form action="/admin/actions/apropos.php" method="post" class="admin-form" id="apropos-form">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION["csrf_token"]) ?>">
<input type="hidden" name="apropos_key" value="<?= htmlspecialchars($aproposKey) ?>">
<?php foreach ($groups as $gi => $group): ?>
<fieldset class="apropos-group">
<legend><?= htmlspecialchars($aproposKey === 'contacts' ? 'Contact' : 'Crédit') ?> <?= $gi + 1 ?></legend>
<?php if ($aproposKey === 'contacts'): ?>
<label for="group_<?= $gi ?>_role">Rôle :</label>
<input type="text" id="group_<?= $gi ?>_role"
name="groups[<?= $gi ?>][role]"
value="<?= htmlspecialchars($group['role'] ?? '') ?>">
<?php else: ?>
<label for="group_<?= $gi ?>_label">Label :</label>
<input type="text" id="group_<?= $gi ?>_label"
name="groups[<?= $gi ?>][label]"
value="<?= htmlspecialchars($group['label'] ?? '') ?>">
<?php endif; ?>
<?php $entries = is_array($group['entries'] ?? null) ? $group['entries'] : []; ?>
<?php foreach ($entries as $ei => $entry): ?>
<div class="apropos-entry">
<label for="entry_<?= $gi ?>_<?= $ei ?>_text"><?= $aproposKey === 'contacts' ? 'Nom' : 'Texte' ?> :</label>
<input type="text" id="entry_<?= $gi ?>_<?= $ei ?>_text"
name="groups[<?= $gi ?>][entries][<?= $ei ?>][text]"
value="<?= htmlspecialchars($entry['text'] ?? '') ?>">
<?php if ($aproposKey === 'contacts'): ?>
<label for="entry_<?= $gi ?>_<?= $ei ?>_email">Email :</label>
<input type="email" id="entry_<?= $gi ?>_<?= $ei ?>_email"
name="groups[<?= $gi ?>][entries][<?= $ei ?>][email]"
value="<?= htmlspecialchars($entry['email'] ?? '') ?>">
<?php endif; ?>
<label for="entry_<?= $gi ?>_<?= $ei ?>_url">Lien (optionnel) :</label>
<input type="url" id="entry_<?= $gi ?>_<?= $ei ?>_url"
name="groups[<?= $gi ?>][entries][<?= $ei ?>][url]"
value="<?= htmlspecialchars($entry['url'] ?? '') ?>">
</div>
<?php endforeach; ?>
<button type="button" class="btn btn--primary btn--sm add-entry-btn" data-group="<?= $gi ?>">+ Ajouter une entrée</button>
</fieldset>
<?php endforeach; ?>
<button type="button" class="btn btn--primary" id="add-group-btn">+ Ajouter un <?= $aproposKey === 'contacts' ? 'contact' : 'groupe de crédit' ?></button>
<div class="admin-form-footer">
<button type="submit" class="btn btn--primary">Enregistrer</button>
<a href="/admin/contenus.php" class="btn btn--secondary admin-cancel-link">Annuler</a>
</div>
<template id="entry-template-<?= $aproposKey ?>">
<div class="apropos-entry">
<label>Entrée :</label>
<input type="text" name="groups[{{gi}}][entries][{{ei}}][text]">
<?php if ($aproposKey === 'contacts'): ?>
<label>Email :</label>
<input type="email" name="groups[{{gi}}][entries][{{ei}}][email]">
<?php endif; ?>
<label>Lien (optionnel) :</label>
<input type="url" name="groups[{{gi}}][entries][{{ei}}][url]">
</div>
</template>
<template id="group-template-<?= $aproposKey ?>">
<fieldset class="apropos-group">
<legend><?= htmlspecialchars($aproposKey === 'contacts' ? 'Contact' : 'Crédit') ?> {{gi}}</legend>
<?php if ($aproposKey === 'contacts'): ?>
<label>Rôle :</label>
<input type="text" name="groups[{{gi}}][role]">
<?php else: ?>
<label>Label :</label>
<input type="text" name="groups[{{gi}}][label]">
<?php endif; ?>
<button type="button" class="btn btn--primary btn--sm add-entry-btn" data-group="{{gi}}">+ Ajouter une entrée</button>
</fieldset>
</template>
</form>
<script>
(function() {
const aproposKey = '<?= $aproposKey ?>';
let groupCount = <?= count($groups) ?>;
const entryTpl = document.getElementById('entry-template-' + aproposKey).innerHTML;
const groupTpl = document.getElementById('group-template-' + aproposKey).innerHTML;
// Add entry to a group
document.querySelectorAll('.add-entry-btn').forEach(btn => {
btn.addEventListener('click', function() {
const gi = parseInt(this.dataset.group);
const fieldset = this.closest('fieldset');
const entryCount = fieldset.querySelectorAll('.apropos-entry').length;
const html = entryTpl.replaceAll('{{gi}}', gi).replaceAll('{{ei}}', entryCount);
this.insertAdjacentHTML('beforebegin', html);
});
});
// Add new group
document.getElementById('add-group-btn').addEventListener('click', function() {
groupCount++;
const html = groupTpl.replaceAll('{{gi}}', groupCount);
this.insertAdjacentHTML('beforebegin', html);
// Re-bind add-entry buttons for the new group
const newGroup = this.previousElementSibling;
if (newGroup && newGroup.classList.contains('apropos-group')) {
const btn = newGroup.querySelector('.add-entry-btn');
if (btn) {
btn.dataset.group = groupCount;
btn.addEventListener('click', function() {
const gi = parseInt(this.dataset.group);
const fieldset = this.closest('fieldset');
const entryCount = fieldset.querySelectorAll('.apropos-entry').length;
const html = entryTpl.replaceAll('{{gi}}', gi).replaceAll('{{ei}}', entryCount);
this.insertAdjacentHTML('beforebegin', html);
});
}
}
});
})();
</script>
<?php include APP_ROOT . '/templates/admin/apropos-groups-form.php'; ?>
<?php endif; ?>
</main>

View File

@@ -37,38 +37,6 @@
</tbody>
</table>
<h2 style="margin-top:2rem;">À propos</h2>
<table>
<thead>
<tr>
<th scope="col">Clé</th>
<th scope="col">Type</th>
<th scope="col">Mis à jour</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
<?php foreach ($aproposKeys as $a): ?>
<?php
$typeLabel = match($a['key']) {
'contacts' => 'Contacts',
'credits' => 'Crédits',
};
?>
<tr>
<td><code><?= htmlspecialchars($a['key']) ?></code></td>
<td><?= htmlspecialchars($typeLabel) ?></td>
<td><?= htmlspecialchars($a['updated_at'] ?? '—') ?></td>
<td>
<a href="/admin/contenus-edit.php?apropos=<?= urlencode($a['key']) ?>"
class="btn btn--primary btn--sm">Éditer</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<!-- ═══════════════════════════════════════════════════════════════════
Blocs d'aide du formulaire étudiant·e
═══════════════════════════════════════════════════════════════════ -->

View File

@@ -33,15 +33,18 @@ function renderEntries(array $entries): string {
<?php if (!empty($contacts)): ?>
<li><a href="#apropos-contacts">Contacts</a></li>
<?php endif; ?>
<?php if (!empty($credits)): ?>
<li><a href="#apropos-credits">Crédits</a></li>
<?php endif; ?>
</ul>
<div class="apropos-toc-erg">
<a href="https://erg.be" target="_blank" rel="noopener">
Site de l'erg ↗
</a>
</div>
<div class="apropos-toc-source">
<a href="https://git.erg.school/PostERG/xamxam" target="_blank" rel="noopener">
Code source ↗
</a>
</div>
</nav>
<!-- MIDDLE: main prose + sections -->
@@ -77,20 +80,27 @@ function renderEntries(array $entries): string {
</section>
<?php endif; ?>
<?php if (!empty($credits)): ?>
<!-- Credits section -->
<!-- Credits section (hardcoded) -->
<section class="apropos-section" id="apropos-credits">
<h2 class="apropos-section-title">Crédits</h2>
<dl class="apropos-credits-list">
<?php foreach ($credits as $group): ?>
<div class="apropos-credit-row">
<dt><?= htmlspecialchars($group['label']) ?></dt>
<dd><?= renderEntries($group['entries'] ?? []) ?></dd>
<dt>Design & développement</dt>
<dd>
<span class="apropos-entry">Olivia Marly</span>,
<span class="apropos-entry">Théophile Gerveau-Mercie</span> &
<span class="apropos-entry">Théo Hennequin</span>
</dd>
</div>
<div class="apropos-credit-row">
<dt>Typographies</dt>
<dd>
<span class="apropos-entry">Ductus (Amélie Dumont)</span> &
<span class="apropos-entry">BBB DM Sans</span>
</dd>
</div>
<?php endforeach; ?>
</dl>
</section>
<?php endif; ?>
</div>