add form help blocks: DB table, admin editor, live rendering in partage form

This commit is contained in:
Pontoporeia
2026-04-29 21:08:09 +02:00
parent 0437ec8d15
commit 670a38f30d
7 changed files with 136 additions and 29 deletions

View File

@@ -0,0 +1,39 @@
<?php
/**
* Save handler for static page content (Markdown).
*/
require_once __DIR__ . '/../../../bootstrap.php';
require_once __DIR__ . '/../../../src/AdminAuth.php';
AdminAuth::requireLogin();
if (!isset($_POST['csrf_token'], $_SESSION['csrf_token'])
|| !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
App::flash('error', 'Erreur de sécurité : token invalide.');
header('Location: /admin/contenus.php');
exit;
}
$allowedSlugs = ['about', 'licenses', 'charte'];
$slug = $_POST['slug'] ?? '';
$content = $_POST['content'] ?? '';
if (!in_array($slug, $allowedSlugs, true)) {
App::flash('error', 'Slug de page invalide.');
header('Location: /admin/contenus.php');
exit;
}
require_once APP_ROOT . '/src/Database.php';
$db = new Database();
try {
$db->savePage($slug, $content);
App::flash('success', 'Page « ' . htmlspecialchars($slug) . ' » mise à jour.');
} catch (Exception $e) {
error_log('page save error: ' . $e->getMessage());
App::flash('error', 'Erreur lors de la sauvegarde : ' . htmlspecialchars($e->getMessage()));
}
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
header('Location: /admin/contenus.php');
exit;

View File

@@ -1643,3 +1643,10 @@
/* ── Form group, student mode, thanks page → see form.css ───────────────── */
/* ── Utility ─────────────────────────────────────────────────────────────── */
.muted {
color: var(--text-secondary);
font-style: italic;
}

View File

@@ -786,3 +786,26 @@ a.recap-file-name:hover {
background: var(--accent-secondary);
transform: translateY(-1px);
}
/* ── Form help blocks ────────────────────────────────────────────────────── */
.form-help-block {
background: color-mix(in srgb, var(--accent-primary) 8%, transparent);
border-left: 3px solid var(--accent-primary);
border-radius: 0 6px 6px 0;
padding: var(--space-s) var(--space-m);
margin-bottom: var(--space-s);
font-size: var(--step--1);
color: var(--text-primary);
line-height: 1.6;
}
.form-help-block > *:first-child { margin-top: 0; }
.form-help-block > *:last-child { margin-bottom: 0; }
.form-help-block p { margin: 0 0 var(--space-xs); }
.form-help-block ul,
.form-help-block ol { margin: 0 0 var(--space-xs); padding-left: var(--space-m); }
.form-help-block li { margin-bottom: var(--space-3xs); }
.form-help-block a { color: var(--accent-primary); }

View File

@@ -210,6 +210,10 @@ function renderShareLinkForm(string $slug, array $link): void
$shareOldFn = fn(string $key, string $default = '') => old($formData, $key, $default);
// No autofocus in the share form — identity function.
$shareWithAutofocusFn = fn(string $field, array $attrs = []) => $attrs;
// Load all form help blocks in one query.
$helpBlocks = Database::getInstance()->getAllFormHelpBlocks();
$helpFn = fn(string $key) => $helpBlocks[$key]['content'] ?? '';
?>
<!DOCTYPE html>
<html lang="fr">
@@ -243,9 +247,7 @@ function renderShareLinkForm(string $slug, array $link): void
<div class="flash-success" role="alert"><?= htmlspecialchars($flashSuccess) ?></div>
<?php endif; ?>
<!-- TODO: Add an introductory block here explaining the purpose of this form
to students: what xamxam is, what happens after submission, who can see
their work, and the general timeline before publication. -->
<?php $helpContent = $helpFn('partage_intro'); include APP_ROOT . '/templates/partials/form/form-help-block.php'; ?>
<p class="required-note"><span class="asterisk">*</span> Champs obligatoires</p>
<form action="/partage/<?= urlencode($slug) ?>/submit" method="post" enctype="multipart/form-data" class="admin-form">
@@ -253,13 +255,15 @@ function renderShareLinkForm(string $slug, array $link): void
<!-- ═══════════════════ Informations du TFE ═══════════════════ -->
<?php
// TODO: Add a student-facing explanation block for each fieldset below,
// describing what information is expected and why it is collected.
$oldFn = $shareOldFn;
$withAutofocusFn = $shareWithAutofocusFn;
// TODO: Add a contextual note for the synopsis field explaining the
// expected length, tone, and whether it will be publicly visible.
$synopsisExtra = '';
// Inject fieldset intro note and synopsis-specific note via the partial's hook.
ob_start();
$helpContent = $helpFn('fieldset_synopsis');
include APP_ROOT . '/templates/partials/form/form-help-block.php';
$synopsisExtra = ob_get_clean();
$helpContent = $helpFn('fieldset_tfe_info');
include APP_ROOT . '/templates/partials/form/form-help-block.php';
include APP_ROOT . '/templates/partials/form/fieldset-tfe-info.php';
?>
@@ -279,9 +283,8 @@ function renderShareLinkForm(string $slug, array $link): void
];
}
}
// TODO: Add a note explaining the jury composition to students:
// who counts as external, what role each member plays, and
// whether this information will be publicly visible.
$helpContent = $helpFn('fieldset_jury');
include APP_ROOT . '/templates/partials/form/form-help-block.php';
require APP_ROOT . '/templates/partials/form/jury-fieldset.php';
?>
@@ -289,17 +292,15 @@ function renderShareLinkForm(string $slug, array $link): void
<?php
$oldFn = $shareOldFn;
$withAutofocusFn = $shareWithAutofocusFn;
// TODO: Add a note for the academic context fieldset clarifying what
// orientation/AP/finality values correspond to, and where students
// can look them up if unsure.
$helpContent = $helpFn('fieldset_academic');
include APP_ROOT . '/templates/partials/form/form-help-block.php';
include APP_ROOT . '/templates/partials/form/fieldset-academic.php';
?>
<!-- ═══════════════════ Fichiers ═══════════════════ -->
<?php
// TODO: Add a note before the files fieldset explaining accepted formats,
// max sizes, what a cover image should look like, and that files
// will only be accessible according to the chosen access level.
$helpContent = $helpFn('fieldset_files');
include APP_ROOT . '/templates/partials/form/form-help-block.php';
include APP_ROOT . '/templates/partials/form/fieldset-files.php';
?>
@@ -309,10 +310,8 @@ function renderShareLinkForm(string $slug, array $link): void
$withAutofocusFn = $shareWithAutofocusFn;
$showDescription = false;
$defaultAccessTypeId = 2;
// TODO: Add an explanation of each access level (Libre / Interne / Interdit)
// close to the "Visibilité / Accès" select so students understand
// the implications before choosing. Cross-reference the licence
// fieldset below.
$helpContent = $helpFn('fieldset_access');
include APP_ROOT . '/templates/partials/form/form-help-block.php';
include APP_ROOT . '/templates/partials/form/fieldset-metadata.php';
?>
@@ -322,8 +321,7 @@ function renderShareLinkForm(string $slug, array $link): void
<!-- ═══════════════════ E-mail de confirmation ═══════════ -->
<fieldset>
<legend>E-mail de confirmation</legend>
<!-- TODO: Add a sentence explaining that the confirmation email is only
used to send the submission recap and will not be shared publicly. -->
<?php $helpContent = $helpFn('fieldset_email'); include APP_ROOT . '/templates/partials/form/form-help-block.php'; ?>
<?php
$name = 'confirmation_email';
$label = 'Adresse e-mail * :';