feat: add file display to forms and recap pages

- Live file preview on all file inputs (file-field partial, edit template):
  thumbnails for images, emoji icons for PDF/video/zip/vtt, filename + size
- New file-preview.js wired via $extraJs in add.php / edit.php and direct
  <script> in partage/index.php; $extraJs support added to head.php
- admin/recapitulatif.php: replace plain table with rich file list — image
  thumbnails linked to media.php, type badges, human-readable size, date
- partage/recapitulatif.php: full rewrite — shows thesis metadata + files
  list with same rich display (no media links for student privacy)
- form.css: new sections for .file-preview-list (live preview) and
  .recap-file-list / .recap-dl / .partage-recap (recap pages)
This commit is contained in:
Pontoporeia
2026-04-27 20:41:43 +02:00
parent aca7e7eef8
commit 32a7509598
11 changed files with 450 additions and 107 deletions

View File

@@ -112,7 +112,8 @@
</label>
</div>
<?php endif; ?>
<input type="file" id="couverture" name="couverture" accept="image/jpeg,image/png">
<input type="file" id="couverture" name="couverture" accept="image/jpeg,image/png" data-preview="fp-couverture">
<div id="fp-couverture" class="file-preview-list" aria-live="polite"></div>
<small><?= empty($currentCover) ? 'JPG, PNG. Max 10 MB.' : 'Laisser vide pour conserver la couverture actuelle. JPG, PNG. Max 10 MB.' ?></small>
</div>
</div>
@@ -149,7 +150,9 @@
<label for="files">Ajouter des fichiers du TFE :</label>
<div class="admin-file-input">
<input type="file" id="files" name="files[]" multiple
accept=".pdf,.jpg,.jpeg,.png,.mp4,.zip,.vtt">
accept=".pdf,.jpg,.jpeg,.png,.mp4,.zip,.vtt"
data-preview="fp-files">
<div id="fp-files" class="file-preview-list" aria-live="polite"></div>
<small>PDF, JPG, PNG, MP4, ZIP. Max 50 MB par fichier. Pour les vidéos, un fichier .vtt de sous-titres peut être joint.</small>
</div>
</div>
@@ -167,7 +170,8 @@
</label>
</div>
<?php endif; ?>
<input type="file" name="banner" accept="image/jpeg,image/png,image/webp">
<input type="file" name="banner" id="banner" accept="image/jpeg,image/png,image/webp" data-preview="fp-banner">
<div id="fp-banner" class="file-preview-list" aria-live="polite"></div>
<small><?= empty($thesis['banner_path']) ? 'JPG, PNG ou WEBP. Format paysage recommandé (4:1). Max 5 MB.' : 'Laisser vide pour conserver la bannière actuelle. JPG, PNG ou WEBP. Format paysage recommandé (4:1). Max 5 MB.' ?></small>
</div>
</div>

View File

@@ -84,19 +84,41 @@
<?php if (!empty($files)): ?>
<section>
<h2>Fichiers</h2>
<table>
<thead><tr><th scope="col">Type</th><th scope="col">Fichier</th><th scope="col">Taille</th><th scope="col">Date</th></tr></thead>
<tbody>
<?php foreach ($files as $f): ?>
<tr>
<td><?= htmlspecialchars($f['file_type']) ?></td>
<td><?= htmlspecialchars($f['file_name']) ?></td>
<td><?= formatFileSize($f['file_size']) ?></td>
<td><?= date('d/m/Y H:i', strtotime($f['uploaded_at'])) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<ul class="recap-file-list">
<?php foreach ($files as $f): ?>
<?php
$mime = $f['mime_type'] ?? '';
$isImage = str_starts_with($mime, 'image/');
$mediaUrl = '/media.php?path=' . urlencode($f['file_path']);
$fileName = htmlspecialchars($f['file_name'] ?? basename($f['file_path']));
$fileType = htmlspecialchars($f['file_type']);
?>
<li class="recap-file-item">
<?php if ($isImage): ?>
<a href="<?= $mediaUrl ?>" target="_blank" rel="noopener" class="recap-file-thumb-link">
<img src="<?= $mediaUrl ?>" alt="<?= $fileName ?>" class="recap-file-thumb" loading="lazy">
</a>
<?php else: ?>
<span class="recap-file-icon">
<?php
if ($mime === 'application/pdf') echo '📄';
elseif (str_starts_with($mime, 'video/')) echo '🎬';
elseif (str_starts_with($mime, 'audio/')) echo '🎵';
elseif (in_array($mime, ['application/zip','application/x-zip-compressed'])) echo '🗜️';
elseif (str_ends_with($f['file_name'] ?? '', '.vtt')) echo '💬';
else echo '📎';
?>
</span>
<?php endif; ?>
<div class="recap-file-meta">
<a href="<?= $mediaUrl ?>" target="_blank" rel="noopener" class="recap-file-name"><?= $fileName ?></a>
<span class="recap-file-type-badge"><?= $fileType ?></span>
<span class="recap-file-size"><?= formatFileSize($f['file_size']) ?></span>
<span class="recap-file-date"><?= date('d/m/Y H:i', strtotime($f['uploaded_at'])) ?></span>
</div>
</li>
<?php endforeach; ?>
</ul>
</section>
<?php endif; ?>

View File

@@ -69,6 +69,9 @@
<?php foreach ($extraCss ?? [] as $css): ?>
<link rel="stylesheet" href="<?= App::assetV($css) ?>">
<?php endforeach; ?>
<?php foreach ($extraJs ?? [] as $js): ?>
<script src="<?= App::assetV($js) ?>" defer></script>
<?php endforeach; ?>
<?php if (php_sapi_name() === 'cli-server'): ?>
<script>
(function poll(){

View File

@@ -15,6 +15,7 @@ $accept = $accept ?? '';
$hint = $hint ?? null;
$multiple = $multiple ?? false;
$id = $id ?? $name;
$previewId = 'fp-' . htmlspecialchars($id);
?>
<div>
<label for="<?= htmlspecialchars($id) ?>"><?= htmlspecialchars($label) ?></label>
@@ -23,11 +24,13 @@ $id = $id ?? $name;
id="<?= htmlspecialchars($id) ?>"
name="<?= htmlspecialchars($name) ?><?= $multiple ? '[]' : '' ?>"
<?= $accept ? 'accept="' . htmlspecialchars($accept) . '"' : '' ?>
<?= $multiple ? 'multiple' : '' ?>>
<?= $multiple ? 'multiple' : '' ?>
data-preview="<?= $previewId ?>">
<div id="<?= $previewId ?>" class="file-preview-list" aria-live="polite"></div>
<?php if ($hint): ?>
<small><?= htmlspecialchars($hint) ?></small>
<?php endif; ?>
</div>
</div>
<?php
unset($accept, $hint, $multiple, $id);
unset($accept, $hint, $multiple, $id, $previewId);