From cef00e62e187b7cf4411b40b0f6ea3d23fc6f41d Mon Sep 17 00:00:00 2001 From: Esenjin Date: Sat, 15 Feb 2025 14:55:27 +0100 Subject: [PATCH] =?UTF-8?q?ajout=20de=20la=20fonction=20s=C3=A9parateur=20?= =?UTF-8?q?=C3=A0=20l'=C3=A9diteur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/css/editor.css | 37 ++++++++- assets/js/story-edit.js | 172 ++++++++++++++++++---------------------- 2 files changed, 115 insertions(+), 94 deletions(-) diff --git a/assets/css/editor.css b/assets/css/editor.css index 9008443..73e47aa 100644 --- a/assets/css/editor.css +++ b/assets/css/editor.css @@ -16,7 +16,6 @@ color: var(--text-primary); min-height: 300px; font-family: inherit; - overflow-x: hidden; } /* Contenu de l'éditeur */ @@ -219,6 +218,36 @@ min-width: 200px; } +/* Style des icônes dans la barre d'outils */ +.ql-snow .ql-toolbar button svg { + width: 18px; + height: 18px; +} + +/* Style du séparateur dans l'éditeur */ +.chapter-divider { + border: none; + border-top: 2px solid var(--accent-primary); + margin: 2em 0; + opacity: 0.5; + transition: opacity var(--transition-fast); +} + +.chapter-divider:hover { + opacity: 0.8; +} + +/* États au survol des boutons */ +.ql-snow .ql-toolbar button:hover .ql-stroke, +.ql-snow .ql-toolbar button.ql-active .ql-stroke { + stroke: var(--accent-primary); +} + +.ql-snow .ql-toolbar button:hover .ql-fill, +.ql-snow .ql-toolbar button.ql-active .ql-fill { + fill: var(--accent-primary); +} + /* Responsive */ @media (max-width: 768px) { .ql-snow.ql-toolbar { @@ -249,4 +278,10 @@ width: 100%; margin: 4px 0; } + + .tooltip:before { + width: 200px; + white-space: normal; + text-align: center; + } } \ No newline at end of file diff --git a/assets/js/story-edit.js b/assets/js/story-edit.js index 079583d..d831cb9 100644 --- a/assets/js/story-edit.js +++ b/assets/js/story-edit.js @@ -2,24 +2,61 @@ document.addEventListener('DOMContentLoaded', function() { let currentChapterId = null; const storyId = document.querySelector('input[name="id"]')?.value; - // Initialisation de l'éditeur Quill avec toutes les options + // Création de l'icône SVG pour le séparateur + const icons = { + divider: ` + + + + ` + }; + + // 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 const quill = new Quill('#editor', { theme: 'snow', modules: { - toolbar: [ - [{ 'header': [1, 2, 3, false] }], - ['bold', 'italic', 'underline', 'strike'], - [{ 'color': [] }, { 'background': [] }], - [{ 'font': [] }], - [{ 'align': [] }], - ['blockquote', 'code-block'], - [{ 'list': 'ordered'}, { 'list': 'bullet' }], - [{ 'script': 'sub'}, { 'script': 'super' }], - [{ 'indent': '-1'}, { 'indent': '+1' }], - [{ 'direction': 'rtl' }], - ['link', 'image', 'video'], - ['clean'] - ], + toolbar: { + container: [ + [{ 'header': [1, 2, 3, false] }], + ['bold', 'italic', 'underline', 'strike'], + [{ 'color': [] }, { 'background': [] }], + [{ 'font': [] }], + [{ 'align': [] }], + ['blockquote', 'code-block'], + [{ 'list': 'ordered'}, { 'list': 'bullet' }], + [{ 'script': 'sub'}, { 'script': 'super' }], + [{ 'indent': '-1'}, { 'indent': '+1' }], + [{ 'direction': 'rtl' }], + ['link', 'image', 'video'], + ['divider'], + ['clean'] + ], + handlers: { + 'divider': function() { + const range = quill.getSelection(true); + quill.insertText(range.index, '\n', Quill.sources.USER); + quill.insertEmbed(range.index + 1, 'divider', true, Quill.sources.USER); + quill.setSelection(range.index + 2, Quill.sources.SILENT); + } + } + }, keyboard: { bindings: { tab: false, @@ -27,20 +64,7 @@ document.addEventListener('DOMContentLoaded', function() { } } }, - placeholder: 'Commencez à écrire votre chapitre ici...', - formats: [ - 'header', - 'bold', 'italic', 'underline', 'strike', - 'color', 'background', - 'font', - 'align', - 'blockquote', 'code-block', - 'list', 'bullet', - 'script', - 'indent', - 'direction', - 'link', 'image', 'video' - ] + placeholder: 'Commencez à écrire votre chapitre ici...' }); // Gestion des chapitres @@ -55,7 +79,7 @@ document.addEventListener('DOMContentLoaded', function() { if (chaptersList) { new Sortable(chaptersList, { animation: 150, - handle: '.chapter-number', // Utiliser le numéro comme poignée de drag + handle: '.chapter-number', ghostClass: 'sortable-ghost', onEnd: async function(evt) { const chapters = Array.from(chaptersList.children).map((item, index) => ({ @@ -79,7 +103,6 @@ document.addEventListener('DOMContentLoaded', function() { throw new Error('Erreur lors de la réorganisation'); } - // Mise à jour des numéros de chapitres chapters.forEach((chapter, index) => { const element = document.querySelector(`[data-id="${chapter.id}"] .chapter-number`); if (element) { @@ -116,7 +139,7 @@ document.addEventListener('DOMContentLoaded', function() { }); } -// Gestion des clics sur la liste des chapitres + // Gestion des clics sur la liste des chapitres if (chaptersList) { chaptersList.addEventListener('click', async (e) => { const target = e.target; @@ -139,10 +162,8 @@ document.addEventListener('DOMContentLoaded', function() { // Gestion du contenu if (chapter.html) { - // Si on a du HTML, on le charge directement quill.root.innerHTML = chapter.html; } else if (chapter.content) { - // Si on a du contenu au format Delta try { const content = typeof chapter.content === 'string' ? JSON.parse(chapter.content) @@ -153,50 +174,18 @@ document.addEventListener('DOMContentLoaded', function() { quill.setText(chapter.content || ''); } } else { - // Contenu vide par défaut quill.setContents([]); } modal.style.display = 'block'; } catch (error) { console.error('Erreur détaillée:', error); - showNotification('Erreur lors du chargement du chapitre. Veuillez réessayer.', 'error'); + showNotification('Erreur lors du chargement du chapitre', 'error'); } } }); } - // Système de notification - function showNotification(message, type = 'success') { - const notification = document.createElement('div'); - notification.className = `notification ${type}`; - notification.textContent = message; - - 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%)'; - setTimeout(() => notification.remove(), 300); - }, 3000); - } - - // Vérification des changements non sauvegardés - function hasUnsavedChanges() { - if (!currentChapterId) { - return chapterTitleInput.value !== '' || quill.getLength() > 1; - } - // Pour les chapitres existants, il faudrait comparer avec le contenu original - return true; // Par défaut, on suppose qu'il y a des changements - } - // Sauvegarde d'un chapitre if (saveChapterBtn) { saveChapterBtn.addEventListener('click', async () => { @@ -233,32 +222,29 @@ document.addEventListener('DOMContentLoaded', function() { }); } - // Ajouter le style des notifications - const style = document.createElement('style'); - style.textContent = ` - .notification { - position: fixed; - top: 20px; - right: 20px; - padding: 1rem 2rem; - border-radius: var(--radius-sm); - background: white; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - opacity: 0; - transform: translateY(-100%); - transition: opacity 0.3s ease, transform 0.3s ease; - z-index: 1000; + function hasUnsavedChanges() { + if (!currentChapterId) { + return chapterTitleInput.value !== '' || quill.getLength() > 1; } + return true; + } - .notification.success { - background-color: var(--success-color); - color: white; - } - - .notification.error { - background-color: var(--error-color); - color: white; - } - `; - document.head.appendChild(style); + function showNotification(message, type = 'success') { + const notification = document.createElement('div'); + notification.className = `notification ${type}`; + notification.textContent = message; + + document.body.appendChild(notification); + + setTimeout(() => { + notification.style.opacity = '1'; + notification.style.transform = 'translateY(0)'; + }, 10); + + setTimeout(() => { + notification.style.opacity = '0'; + notification.style.transform = 'translateY(-100%)'; + setTimeout(() => notification.remove(), 300); + }, 3000); + } }); \ No newline at end of file