From 1fa578e3124059cdec8339b3f009df1844dd2c23 Mon Sep 17 00:00:00 2001 From: Esenjin <esenjin@sangigi-fuchsia.fr> Date: Sun, 23 Feb 2025 19:20:23 +0100 Subject: [PATCH] ajout d'un mode "brouillon" pour les chapitres ils ne sont visibles que par les admins --- admin/api/save-chapter.php | 28 +- admin/story-edit.php | 4 + assets/css/components.css | 56 ++++ assets/js/story-edit.js | 512 ++++++++++++++++++------------------- chapitre.php | 24 +- index.php | 25 +- roman.php | 9 +- version.txt | 2 +- 8 files changed, 381 insertions(+), 279 deletions(-) diff --git a/admin/api/save-chapter.php b/admin/api/save-chapter.php index 293b585..cb7a6e6 100644 --- a/admin/api/save-chapter.php +++ b/admin/api/save-chapter.php @@ -5,16 +5,20 @@ require_once '../../includes/stories.php'; if (!Auth::check()) { http_response_code(401); - exit('Non autorisé'); + exit(json_encode(['success' => false, 'error' => 'Non autorisé'])); } $input = json_decode(file_get_contents('php://input'), true); $storyId = $input['storyId'] ?? null; $chapterId = $input['chapterId'] ?? null; $title = $input['title'] ?? ''; -$content = $input['content']; +$content = $input['content'] ?? ''; +$draft = $input['draft'] ?? false; try { + // Ajout de logs pour déboguer + error_log('Données reçues: ' . print_r($input, true)); + $story = Stories::get($storyId); if (!$story) { throw new Exception('Roman non trouvé'); @@ -22,28 +26,42 @@ try { if ($chapterId) { // Mise à jour d'un chapitre existant + $chapterUpdated = false; foreach ($story['chapters'] as &$chapter) { - if ($chapter['id'] == $chapterId) { + if ($chapter['id'] === $chapterId) { $chapter['title'] = $title; $chapter['content'] = $content; + $chapter['draft'] = $draft; $chapter['updated'] = date('Y-m-d'); + $chapterUpdated = true; break; } } + if (!$chapterUpdated) { + throw new Exception('Chapitre non trouvé'); + } } else { // Nouveau chapitre $story['chapters'][] = [ 'id' => uniqid(), 'title' => $title, 'content' => $content, + 'draft' => $draft, 'created' => date('Y-m-d'), 'updated' => date('Y-m-d') ]; } - Stories::save($story); + if (!Stories::save($story)) { + throw new Exception('Erreur lors de la sauvegarde du roman'); + } + echo json_encode(['success' => true]); } catch (Exception $e) { + error_log('Erreur dans save-chapter.php: ' . $e->getMessage()); http_response_code(500); - echo json_encode(['error' => $e->getMessage()]); + echo json_encode([ + 'success' => false, + 'error' => $e->getMessage() + ]); } \ No newline at end of file diff --git a/admin/story-edit.php b/admin/story-edit.php index 625b292..c0ae206 100644 --- a/admin/story-edit.php +++ b/admin/story-edit.php @@ -149,6 +149,10 @@ function generateSlug($title) { <div class="modal-header"> <h2>Éditer un chapitre</h2> <input type="text" id="chapterTitle" placeholder="Titre du chapitre"> + <label class="draft-toggle"> + <input type="checkbox" id="chapterDraft"> + <span class="toggle-label">Mode brouillon</span> + </label> </div> <div class="editor-container"> diff --git a/assets/css/components.css b/assets/css/components.css index 68b6b92..3e7a24e 100644 --- a/assets/css/components.css +++ b/assets/css/components.css @@ -328,6 +328,62 @@ margin-top: var(--spacing-sm); } +/* Styles pour le mode brouillon */ +.draft-toggle { + display: flex; + align-items: center; + gap: var(--spacing-sm); + margin-top: var(--spacing-sm); +} + +.draft-toggle input[type="checkbox"] { + appearance: none; + width: 40px; + height: 20px; + background: var(--bg-secondary); + border-radius: 10px; + position: relative; + cursor: pointer; + transition: var(--transition-fast); +} + +.draft-toggle input[type="checkbox"]::before { + content: ''; + position: absolute; + width: 16px; + height: 16px; + border-radius: 50%; + background: var(--text-primary); + left: 2px; + top: 2px; + transition: var(--transition-fast); +} + +.draft-toggle input[type="checkbox"]:checked { + background: var(--accent-primary); +} + +.draft-toggle input[type="checkbox"]:checked::before { + transform: translateX(20px); +} + +.chapter-item.draft { + opacity: 0.7; + border-style: dashed; +} + +.chapter-item.draft::after { + content: 'Brouillon'; + position: absolute; + top: 0.5rem; + right: 0.5rem; + background: var(--accent-primary); + color: var(--text-tertiary); + padding: 0.2rem 0.5rem; + border-radius: var(--radius-sm); + font-size: 0.8rem; +} + /* Media queries */ @media (max-width: 768px) { .story-cover { diff --git a/assets/js/story-edit.js b/assets/js/story-edit.js index 7318416..4565be6 100644 --- a/assets/js/story-edit.js +++ b/assets/js/story-edit.js @@ -1,9 +1,29 @@ document.addEventListener('DOMContentLoaded', function() { + // Récupération des paramètres et variables globales const urlParams = new URLSearchParams(window.location.search); const storyId = document.querySelector('input[name="id"]')?.value || urlParams.get('id'); let currentChapterId = null; + let hasUnsavedChanges = false; - // Fonction de notification + // Références DOM pour l'éditeur + const modal = document.getElementById('chapterEditor'); + const coverModal = document.getElementById('chapterCoverEditor'); + const addChapterBtn = document.getElementById('addChapter'); + const saveChapterBtn = document.getElementById('saveChapter'); + const cancelEditBtn = document.getElementById('cancelEdit'); + const chapterTitleInput = document.getElementById('chapterTitle'); + const chaptersList = document.getElementById('chaptersList'); + const chapterDraftToggle = document.getElementById('chapterDraft'); + + // Éléments pour la modale de couverture + const coverPreview = document.querySelector('.current-cover-preview'); + const chapterCoverInput = document.getElementById('chapterCover'); + const saveCoverBtn = document.getElementById('saveCover'); + const cancelCoverBtn = document.getElementById('cancelCoverEdit'); + const deleteCoverBtn = document.getElementById('deleteCover'); + let currentChapterCover = null; + + // Notification système function showNotification(message, type = 'success') { const notification = document.createElement('div'); notification.className = `notification ${type}`; @@ -11,13 +31,11 @@ document.addEventListener('DOMContentLoaded', function() { document.body.appendChild(notification); - // Animation d'entrée setTimeout(() => { notification.style.opacity = '1'; notification.style.transform = 'translateY(0)'; }, 10); - // Auto-suppression après 3 secondes setTimeout(() => { notification.style.opacity = '0'; notification.style.transform = 'translateY(-100%)'; @@ -25,33 +43,7 @@ document.addEventListener('DOMContentLoaded', function() { }, 3000); } - // Création de l'icône SVG pour le séparateur - const icons = { - divider: ` - <svg viewBox="0 0 18 18"> - <line class="ql-stroke" x1="3" x2="15" y1="9" y2="9"></line> - </svg> - ` - }; - - // Ajout de l'icône à Quill - const Block = Quill.import('blots/block'); - const icons_list = Quill.import('ui/icons'); - icons_list['divider'] = icons.divider; - - // Définition du format pour le séparateur - class DividerBlot extends Block { - static create() { - const node = super.create(); - node.className = 'chapter-divider'; - return node; - } - } - DividerBlot.blotName = 'divider'; - DividerBlot.tagName = 'hr'; - Quill.register(DividerBlot); - - // Configuration et initialisation de Quill + // Configuration de l'éditeur Quill const quill = new Quill('#editor', { theme: 'snow', modules: { @@ -115,39 +107,241 @@ document.addEventListener('DOMContentLoaded', function() { }; } } - }, - keyboard: { - bindings: { - tab: false, - 'indent backwards': false - } } }, placeholder: 'Commencez à écrire votre chapitre ici...' }); - // Gestion des chapitres - const modal = document.getElementById('chapterEditor'); - const addChapterBtn = document.getElementById('addChapter'); - const saveChapterBtn = document.getElementById('saveChapter'); - const cancelEditBtn = document.getElementById('cancelEdit'); - const chapterTitleInput = document.getElementById('chapterTitle'); - const chaptersList = document.getElementById('chaptersList'); + // Détection des changements non sauvegardés + function detectUnsavedChanges() { + quill.on('text-change', () => { + hasUnsavedChanges = true; + }); + + if (chapterTitleInput) { + chapterTitleInput.addEventListener('input', () => { + hasUnsavedChanges = true; + }); + } + } - // Éléments de la modale de couverture - const coverModal = document.getElementById('chapterCoverEditor'); - const coverPreview = document.querySelector('.current-cover-preview'); - const chapterCoverInput = document.getElementById('chapterCover'); - const saveCoverBtn = document.getElementById('saveCover'); - const cancelCoverBtn = document.getElementById('cancelCoverEdit'); - const deleteCoverBtn = document.getElementById('deleteCover'); - let currentChapterCover = null; + // Configuration de Sortable pour la réorganisation des chapitres + if (chaptersList) { + new Sortable(chaptersList, { + animation: 150, + handle: '.chapter-number', + ghostClass: 'sortable-ghost', + onEnd: async function(evt) { + const chapters = Array.from(chaptersList.children).map((item, index) => ({ + id: item.dataset.id, + position: index + })); - // Gestionnaire pour le bouton de couverture + try { + const response = await fetch('api/reorder-chapters.php', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + storyId: storyId, + chapters: chapters + }) + }); + + if (!response.ok) { + throw new Error('Erreur lors de la réorganisation'); + } + + chapters.forEach((chapter, index) => { + const element = document.querySelector(`[data-id="${chapter.id}"] .chapter-number`); + if (element) { + element.textContent = index + 1; + } + }); + + } catch (error) { + console.error('Erreur:', error); + showNotification('Erreur lors de la réorganisation des chapitres', 'error'); + } + } + }); + } + + // Gestion de la sauvegarde du chapitre + if (saveChapterBtn) { + saveChapterBtn.addEventListener('click', async () => { + const title = chapterTitleInput.value.trim(); + if (!title) { + showNotification('Le titre est requis', 'error'); + return; + } + + try { + const response = await fetch('api/save-chapter.php', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + storyId: storyId, + chapterId: currentChapterId, + title: title, + content: quill.root.innerHTML, + draft: chapterDraftToggle?.checked || false + }) + }); + + if (response.ok) { + const result = await response.json(); + if (result.success) { + hasUnsavedChanges = false; + showNotification('Chapitre sauvegardé avec succès'); + setTimeout(() => location.reload(), 500); + } else { + throw new Error(result.error || 'Erreur lors de la sauvegarde'); + } + } else { + throw new Error('Erreur réseau'); + } + } catch (error) { + console.error('Erreur:', error); + showNotification('Erreur lors de la sauvegarde du chapitre', 'error'); + } + }); + } + + // Gestionnaires d'événements pour l'édition des chapitres + if (addChapterBtn) { + addChapterBtn.addEventListener('click', () => { + currentChapterId = null; + chapterTitleInput.value = ''; + quill.setContents([]); + if (chapterDraftToggle) { + chapterDraftToggle.checked = false; + } + hasUnsavedChanges = false; + modal.style.display = 'block'; + }); + } + + if (cancelEditBtn) { + cancelEditBtn.addEventListener('click', () => { + if (hasUnsavedChanges) { + confirmDialog.show({ + title: 'Modifications non sauvegardées', + message: 'Des modifications non sauvegardées seront perdues. Voulez-vous vraiment fermer ?', + confirmText: 'Fermer sans sauvegarder', + onConfirm: () => { + modal.style.display = 'none'; + hasUnsavedChanges = false; + } + }); + } else { + modal.style.display = 'none'; + } + }); + } + + // Gestion des clics sur la liste des chapitres if (chaptersList) { chaptersList.addEventListener('click', async (e) => { - if (e.target.matches('.edit-cover')) { - const chapterItem = e.target.closest('.chapter-item'); + const target = e.target; + + if (target.matches('.edit-chapter')) { + const chapterItem = target.closest('.chapter-item'); + currentChapterId = chapterItem.dataset.id; + + try { + const response = await fetch(`api/get-chapter.php?storyId=${storyId}&chapterId=${currentChapterId}`); + + if (!response.ok) { + throw new Error('Erreur réseau'); + } + + const chapter = await response.json(); + + // Mise à jour du titre + chapterTitleInput.value = chapter.title || ''; + + // Gestion du contenu + if (chapter.html) { + quill.root.innerHTML = chapter.html; + } else if (chapter.content) { + try { + const content = typeof chapter.content === 'string' + ? JSON.parse(chapter.content) + : chapter.content; + quill.setContents(content); + } catch (contentError) { + console.error('Erreur de parsing du contenu:', contentError); + quill.setText(chapter.content || ''); + } + } else { + quill.setContents([]); + } + + // Mise à jour du mode brouillon + if (chapterDraftToggle) { + chapterDraftToggle.checked = chapter.draft || false; + } + + modal.style.display = 'block'; + hasUnsavedChanges = false; + } catch (error) { + console.error('Erreur détaillée:', error); + showNotification('Erreur lors du chargement du chapitre', 'error'); + } + } + + // Gestion de la suppression + if (target.matches('.delete-chapter')) { + const chapterItem = target.closest('.chapter-item'); + const chapterId = chapterItem.dataset.id; + const chapterTitle = chapterItem.querySelector('.chapter-title').textContent; + + confirmDialog.show({ + title: 'Suppression du chapitre', + message: `Voulez-vous vraiment supprimer le chapitre "${chapterTitle}" ? Cette action est irréversible.`, + confirmText: 'Supprimer', + confirmClass: 'danger', + onConfirm: async () => { + try { + const response = await fetch('api/delete-chapter.php', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + storyId: storyId, + chapterId: chapterId + }) + }); + + if (!response.ok) throw new Error('Erreur réseau'); + + const result = await response.json(); + if (result.success) { + chapterItem.style.opacity = '0'; + chapterItem.style.transform = 'translateX(-100%)'; + setTimeout(() => { + chapterItem.remove(); + showNotification('Chapitre supprimé avec succès'); + }, 300); + } else { + throw new Error(result.error || 'Erreur lors de la suppression'); + } + } catch (error) { + console.error('Erreur:', error); + showNotification(error.message, 'error'); + } + } + }); + } + + // Gestion de la couverture + if (target.matches('.edit-cover')) { + const chapterItem = target.closest('.chapter-item'); const chapterId = chapterItem.dataset.id; const chapterTitle = chapterItem.querySelector('.chapter-title').textContent; @@ -179,7 +373,7 @@ document.addEventListener('DOMContentLoaded', function() { }); } - // Prévisualisation de l'image + // Prévisualisation de l'image de couverture if (chapterCoverInput) { chapterCoverInput.addEventListener('change', (e) => { const file = e.target.files[0]; @@ -231,6 +425,7 @@ document.addEventListener('DOMContentLoaded', function() { showNotification('Couverture mise à jour avec succès'); coverModal.style.display = 'none'; chapterCoverInput.value = ''; + setTimeout(() => location.reload(), 500); } else { throw new Error(result.error || 'Erreur lors de la mise à jour'); } @@ -270,6 +465,7 @@ document.addEventListener('DOMContentLoaded', function() { showNotification('Couverture supprimée avec succès'); coverPreview.innerHTML = ''; coverModal.style.display = 'none'; + setTimeout(() => location.reload(), 500); } else { throw new Error(result.error || 'Erreur lors de la suppression'); } @@ -282,208 +478,6 @@ document.addEventListener('DOMContentLoaded', function() { }); } - // Configuration de Sortable pour la réorganisation des chapitres - if (chaptersList) { - new Sortable(chaptersList, { - animation: 150, - handle: '.chapter-number', - ghostClass: 'sortable-ghost', - onEnd: async function(evt) { - const chapters = Array.from(chaptersList.children).map((item, index) => ({ - id: item.dataset.id, - position: index - })); - - try { - const response = await fetch('api/reorder-chapters.php', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - storyId: storyId, - chapters: chapters - }) - }); - - if (!response.ok) { - throw new Error('Erreur lors de la réorganisation'); - } - - chapters.forEach((chapter, index) => { - const element = document.querySelector(`[data-id="${chapter.id}"] .chapter-number`); - if (element) { - element.textContent = index + 1; - } - }); - - } catch (error) { - console.error('Erreur:', error); - showNotification('Erreur lors de la réorganisation des chapitres', 'error'); - } - } - }); - } - - // Gestionnaires d'événements pour l'édition des chapitres - if (addChapterBtn) { - addChapterBtn.addEventListener('click', () => { - currentChapterId = null; - chapterTitleInput.value = ''; - quill.setContents([]); - modal.style.display = 'block'; - }); - } - - if (cancelEditBtn) { - cancelEditBtn.addEventListener('click', () => { - if (hasUnsavedChanges()) { - confirmDialog.show({ - title: 'Modifications non sauvegardées', - message: 'Des modifications non sauvegardées seront perdues. Voulez-vous vraiment fermer ?', - confirmText: 'Fermer sans sauvegarder', - onConfirm: () => { - modal.style.display = 'none'; - } - }); - } else { - modal.style.display = 'none'; - } - }); - } - - // Gestion des clics sur la liste des chapitres - if (chaptersList) { - chaptersList.addEventListener('click', async (e) => { - const target = e.target; - - if (target.matches('.edit-chapter')) { - const chapterItem = target.closest('.chapter-item'); - currentChapterId = chapterItem.dataset.id; - - try { - const response = await fetch(`api/get-chapter.php?storyId=${storyId}&chapterId=${currentChapterId}`); - - if (!response.ok) { - throw new Error('Erreur réseau'); - } - - const chapter = await response.json(); - - // Mise à jour du titre - chapterTitleInput.value = chapter.title || ''; - - // Gestion du contenu - if (chapter.html) { - quill.root.innerHTML = chapter.html; - } else if (chapter.content) { - try { - const content = typeof chapter.content === 'string' - ? JSON.parse(chapter.content) - : chapter.content; - quill.setContents(content); - } catch (contentError) { - console.error('Erreur de parsing du contenu:', contentError); - quill.setText(chapter.content || ''); - } - } else { - quill.setContents([]); - } - - modal.style.display = 'block'; - } catch (error) { - console.error('Erreur détaillée:', error); - showNotification('Erreur lors du chargement du chapitre', 'error'); - } - } - - // Gestion de la suppression - if (target.matches('.delete-chapter')) { - const chapterItem = target.closest('.chapter-item'); - const chapterId = chapterItem.dataset.id; - const chapterTitle = chapterItem.querySelector('.chapter-title').textContent; - - confirmDialog.show({ - title: 'Suppression du chapitre', - message: `Voulez-vous vraiment supprimer le chapitre "${chapterTitle}" ? Cette action est irréversible.`, - confirmText: 'Supprimer', - confirmClass: 'danger', - onConfirm: async () => { - try { - const response = await fetch('api/delete-chapter.php', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - storyId: storyId, - chapterId: chapterId - }) - }); - - if (!response.ok) throw new Error('Erreur réseau'); - - const result = await response.json(); - if (result.success) { - chapterItem.style.opacity = '0'; - chapterItem.style.transform = 'translateX(-100%)'; - setTimeout(() => { - chapterItem.remove(); - showNotification('Chapitre supprimé avec succès'); - }, 300); - } else { - throw new Error(result.error || 'Erreur lors de la suppression'); - } - } catch (error) { - console.error('Erreur:', error); - showNotification(error.message, 'error'); - } - } - }); - } - }); - } - - // Sauvegarde d'un chapitre - if (saveChapterBtn) { - saveChapterBtn.addEventListener('click', async () => { - const title = chapterTitleInput.value.trim(); - if (!title) { - showNotification('Le titre est requis', 'error'); - return; - } - - try { - const response = await fetch('api/save-chapter.php', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - storyId: storyId, - chapterId: currentChapterId, - title: title, - content: quill.root.innerHTML - }) - }); - - if (response.ok) { - showNotification('Chapitre sauvegardé avec succès'); - setTimeout(() => location.reload(), 500); - } else { - throw new Error('Erreur lors de la sauvegarde'); - } - } catch (error) { - console.error('Erreur:', error); - showNotification('Erreur lors de la sauvegarde du chapitre', 'error'); - } - }); - } - - function hasUnsavedChanges() { - if (!currentChapterId) { - return chapterTitleInput.value !== '' || quill.getLength() > 1; - } - return true; - } + // Initialisation + detectUnsavedChanges(); }); \ No newline at end of file diff --git a/chapitre.php b/chapitre.php index bc22cb9..c646b2c 100644 --- a/chapitre.php +++ b/chapitre.php @@ -1,5 +1,6 @@ <?php require_once 'includes/config.php'; +require_once 'includes/auth.php'; require_once 'includes/stories.php'; // Récupération des paramètres @@ -22,6 +23,9 @@ if (!$story) { $currentChapter = null; $currentIndex = -1; foreach ($story['chapters'] as $index => $chapter) { + if (($chapter['draft'] ?? false) && !Auth::check()) { + continue; + } if ($chapter['id'] === $chapterId) { $currentChapter = $chapter; $currentIndex = $index; @@ -35,8 +39,14 @@ if (!$currentChapter) { } // Récupération des chapitres précédent et suivant -$prevChapter = $currentIndex > 0 ? $story['chapters'][$currentIndex - 1] : null; -$nextChapter = $currentIndex < count($story['chapters']) - 1 ? $story['chapters'][$currentIndex + 1] : null; +$visibleChapters = array_filter($story['chapters'], function($ch) { + return !($ch['draft'] ?? false) || Auth::check(); +}); +$visibleChapters = array_values($visibleChapters); + +$currentVisibleIndex = array_search($currentChapter, $visibleChapters); +$prevChapter = $currentVisibleIndex > 0 ? $visibleChapters[$currentVisibleIndex - 1] : null; +$nextChapter = $currentVisibleIndex < count($visibleChapters) - 1 ? $visibleChapters[$currentVisibleIndex + 1] : null; $config = Config::load(); ?> @@ -91,10 +101,16 @@ $config = Config::load(); <aside class="chapters-menu"> <h2>Chapitres</h2> <ul class="chapters-list"> - <?php foreach ($story['chapters'] as $chapter): ?> + <?php + $visibleChapters = array_filter($story['chapters'], function($chapter) { + return !($chapter['draft'] ?? false) || Auth::check(); + }); + + foreach ($visibleChapters as $chapter): + ?> <li> <a href="?story=<?= urlencode($storyId) ?>&chapter=<?= urlencode($chapter['id']) ?>" - class="<?= $chapter['id'] === $chapterId ? 'current-chapter' : '' ?>"> + class="<?= $chapter['id'] === $chapterId ? 'current-chapter' : '' ?>"> <?= htmlspecialchars($chapter['title']) ?> </a> </li> diff --git a/index.php b/index.php index 6fc832b..40c51f7 100644 --- a/index.php +++ b/index.php @@ -1,5 +1,6 @@ <?php require_once 'includes/config.php'; +require_once 'includes/auth.php'; require_once 'includes/stories.php'; $config = Config::load(); @@ -77,16 +78,22 @@ function formatDate($date) { class="novel-cover" loading="lazy"> - <div class="novel-info"> - <h2><?= htmlspecialchars($story['title']) ?></h2> - <p> - <?= count($story['chapters'] ?? []) ?> - chapitre<?= count($story['chapters'] ?? []) > 1 ? 's' : '' ?> - </p> - <div class="novel-date"> - Mis à jour le <?= formatDate($story['updated']) ?> + <div class="novel-info"> + <h2><?= htmlspecialchars($story['title']) ?></h2> + <?php + $visibleChapters = array_filter($story['chapters'] ?? [], function($chapter) { + return !($chapter['draft'] ?? false) || Auth::check(); + }); + $chapterCount = count($visibleChapters); + ?> + <p> + <?= $chapterCount ?> + chapitre<?= $chapterCount > 1 ? 's' : '' ?> + </p> + <div class="novel-date"> + Mis à jour le <?= formatDate($story['updated']) ?> + </div> </div> - </div> </a> <?php endforeach; ?> </div> diff --git a/roman.php b/roman.php index 0ae1171..05969d3 100644 --- a/roman.php +++ b/roman.php @@ -1,5 +1,6 @@ <?php require_once 'includes/config.php'; +require_once 'includes/auth.php'; require_once 'includes/stories.php'; // Récupération de l'ID du roman depuis l'URL @@ -53,7 +54,13 @@ $config = Config::load(); <h2>Chapitres</h2> <?php if (!empty($story['chapters'])): ?> <ul class="chapters-list"> - <?php foreach ($story['chapters'] as $index => $chapter): ?> + <?php + $visibleChapters = array_filter($story['chapters'], function($chapter) { + return !($chapter['draft'] ?? false) || Auth::check(); + }); + + foreach ($visibleChapters as $chapter): + ?> <li> <a href="chapitre.php?story=<?= urlencode($story['id']) ?>&chapter=<?= urlencode($chapter['id']) ?>"> <?= htmlspecialchars($chapter['title']) ?> diff --git a/version.txt b/version.txt index a5ba932..867e524 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.1.7 \ No newline at end of file +1.2.0 \ No newline at end of file