6895a3bf65
Remplace le formulaire unique par un wizard 5 étapes (création) et
6 étapes (édition) avec auto-sauvegarde en brouillon, détection de
tags depuis le texte (TagSuggester), aperçu SEO, diff avant validation
et plan Markdown dynamique dans l'éditeur.
Détail des changements :
- ArticleManager : +6 méthodes (updatePartialMeta, saveDraftOverlay,
getDraftOverlay, hasDraftOverlay, discardDraftOverlay, commitDraftOverlay)
- .htaccess : routes /new/{uuid}/{1-5} et /edit/{uuid}/{1-6}
- index.php : cases create et edit réécrits en switch($step),
nouveau case autosave_draft et edit_discard_draft
- assets/js/wizard.js : autosave debounce, auto-resize textarea,
scroll curseur, plan TOC dynamique, toggle pills tags
- templates/wizard/ : nav.php + step1..6.php
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
108 lines
4.8 KiB
PHP
108 lines
4.8 KiB
PHP
<?php
|
|
// Attendu : $mode, $step, $totalSteps, $uuid, $flatTagValues, $flatArticleTags, $draftContent
|
|
ob_start();
|
|
$_backUrl = $mode === 'create' ? '/new/' . rawurlencode($uuid) . '/3' : '/edit/' . rawurlencode($uuid) . '/3';
|
|
$_formAction = $mode === 'create' ? '/new/' . rawurlencode($uuid) . '/4' : '/edit/' . rawurlencode($uuid) . '/4';
|
|
$_tagVal = implode(', ', $flatArticleTags);
|
|
|
|
$_suggester = new TagSuggester();
|
|
$_candidates = $draftContent !== ''
|
|
? $_suggester->suggest($draftContent, $flatTagValues, $flatArticleTags)
|
|
: [];
|
|
|
|
$_knownInText = array_keys(array_filter($_candidates, fn ($_c) => $_c['known']));
|
|
$_detectedInText = array_keys(array_filter($_candidates, fn ($_c) => !$_c['known']));
|
|
?>
|
|
<form method="POST" action="<?= htmlspecialchars($_formAction) ?>">
|
|
|
|
<div class="d-flex align-items-center justify-content-between gap-3 mb-4 flex-wrap">
|
|
<h1 class="h4 mb-0">Tags</h1>
|
|
<div class="d-flex gap-2">
|
|
<a href="<?= htmlspecialchars($_backUrl) ?>" class="btn btn-outline-secondary btn-sm">← Retour</a>
|
|
<button type="submit" class="btn btn-primary">Suivant →</button>
|
|
</div>
|
|
</div>
|
|
|
|
<?php include __DIR__ . '/nav.php'; ?>
|
|
|
|
<div class="card mb-4">
|
|
<div class="card-body">
|
|
|
|
<datalist id="wz-tags-list">
|
|
<?php foreach ($flatTagValues as $_v): ?>
|
|
<option value="<?= htmlspecialchars($_v) ?>">
|
|
<?php endforeach; ?>
|
|
</datalist>
|
|
|
|
<div class="mb-3">
|
|
<input type="text" class="form-control"
|
|
id="wz-tags-flat"
|
|
name="tags_flat"
|
|
value="<?= htmlspecialchars($_tagVal) ?>"
|
|
placeholder="valeur1, valeur2…"
|
|
list="wz-tags-list"
|
|
autocomplete="off">
|
|
<div class="form-text">Séparer par des virgules.</div>
|
|
</div>
|
|
|
|
<!-- Valeurs existantes ──────────────────────────────────────────────── -->
|
|
<?php if (!empty($flatTagValues)): ?>
|
|
<div class="mb-3">
|
|
<p class="small text-muted mb-2">Valeurs déjà utilisées :</p>
|
|
<div class="d-flex flex-wrap gap-1 wz-tag-pills" data-target="wz-tags-flat">
|
|
<?php foreach ($flatTagValues as $_v):
|
|
$_isActive = in_array($_v, $flatArticleTags, true);
|
|
$_inText = in_array($_v, $_knownInText, true);
|
|
?>
|
|
<button type="button"
|
|
class="btn btn-sm <?= $_isActive ? 'btn-secondary' : 'btn-outline-secondary' ?> wz-tag-pill py-0"
|
|
data-value="<?= htmlspecialchars($_v) ?>"
|
|
style="font-size:.75rem"
|
|
title="<?= $_inText ? 'Présent dans le texte' : '' ?>">
|
|
<?= htmlspecialchars($_v) ?><?= $_inText ? ' <span class="ms-1" style="opacity:.6;font-size:.65rem">●</span>' : '' ?>
|
|
</button>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Détectés dans le texte ──────────────────────────────────────────── -->
|
|
<?php if (!empty($_detectedInText)): ?>
|
|
<div>
|
|
<p class="small text-muted mb-2">Détectés dans le texte (abréviations, noms propres, mots composés) :</p>
|
|
<div class="d-flex flex-wrap gap-1 wz-tag-pills" data-target="wz-tags-flat">
|
|
<?php foreach ($_detectedInText as $_v):
|
|
$_isActive = in_array($_v, $flatArticleTags, true);
|
|
$_meta = $_candidates[$_v];
|
|
$_badge = match($_meta['group'] ?? '') {
|
|
'abbrev' => 'ABR',
|
|
'camel' => 'CC',
|
|
'proper' => 'NP',
|
|
default => '',
|
|
};
|
|
?>
|
|
<button type="button"
|
|
class="btn btn-sm <?= $_isActive ? 'btn-info' : 'btn-outline-info' ?> wz-tag-pill py-0"
|
|
data-value="<?= htmlspecialchars($_v) ?>"
|
|
style="font-size:.75rem"
|
|
title="<?= htmlspecialchars($_meta['count'] . 'x dans le texte — ' . ($_badge ?: 'détecté')) ?>">
|
|
<?= htmlspecialchars($_v) ?>
|
|
<?php if ($_badge): ?>
|
|
<span class="ms-1 text-muted" style="font-size:.6rem"><?= $_badge ?></span>
|
|
<?php endif; ?>
|
|
</button>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</form>
|
|
<script src="/assets/js/wizard.js"></script>
|
|
<?php
|
|
$content = ob_get_clean();
|
|
$title = 'Tags — Étape 4/' . $totalSteps;
|
|
include BASE_PATH . '/templates/layout.php';
|