ajout de la fonction séparateur à l'éditeur
This commit is contained in:
parent
072e0a7fb1
commit
cef00e62e1
@ -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;
|
||||
}
|
||||
}
|
@ -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: `
|
||||
<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
|
||||
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);
|
||||
}
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user