From e12fb751caa07539c1c7cefb920eb0cceecc334a Mon Sep 17 00:00:00 2001 From: streaper2 Date: Thu, 5 Mar 2026 08:09:28 +0100 Subject: [PATCH] correction du nixpack pour supprimer les fichiers sources --- .next/dev/cache/turbopack/23c46498/CURRENT | Bin 4 -> 4 bytes .next/dev/cache/turbopack/23c46498/LOG | 12 ++++++ nixpacks.toml | 19 +++++++--- src/components/RichTextEditor.tsx | 41 +++++++++++++-------- src/components/layout/EditorShell.tsx | 14 ++++++- 5 files changed, 65 insertions(+), 21 deletions(-) diff --git a/.next/dev/cache/turbopack/23c46498/CURRENT b/.next/dev/cache/turbopack/23c46498/CURRENT index 4a1cf43ec3ad3726d9f625343114aefab3f6aab1..dedfcdf37d7fdf7bf2ad298aec391f0cd473bb33 100644 GIT binary patch literal 4 LcmZQzFg^(({ useEffect(() => { if (!contentRef.current || initialContent === undefined) return; - // Ignore exact loopbacks from our own saves - if (initialContent === syncRef.current) return; + // 1. Si le contenu entrant est identique à ce qu'on a déjà, on ne touche à rien + if (initialContent === contentRef.current.innerHTML) return; - // Safety: never overwrite real content with an empty string from a stale/placeholder source - const hasRealContent = latestContentRef.current && latestContentRef.current.trim().length > 0; - if (!initialContent && hasRealContent) return; + // 2. LOGIQUE CRUCIALE : On ne met à jour le DOM que si : + // - L'éditeur est vide (premier chargement) + // - OU le document a changé (si vous gérez des IDs de documents) + // - OU si l'utilisateur n'est PAS en train de focus l'éditeur + const isUserEditing = document.activeElement === contentRef.current; - // We reached here, so initialContent is genuinely NEW data we didn't know about. - // E.g. clicked another chapter, or data was modified in another tab/device. - contentRef.current.innerHTML = initialContent; - syncRef.current = initialContent; - latestContentRef.current = initialContent; + if (!isUserEditing || (contentRef.current.innerHTML === "" && initialContent !== "")) { + contentRef.current.innerHTML = initialContent; + syncRef.current = initialContent; + latestContentRef.current = initialContent; + } }, [initialContent]); // Flush pending save on unmount @@ -187,9 +189,11 @@ const RichTextEditor = forwardRef(({ return () => { if (saveTimeoutRef.current) { clearTimeout(saveTimeoutRef.current); - if (latestContentRef.current !== syncRef.current && onSave) { - onSave(latestContentRef.current); - } + } + // Always save if there are unsaved changes, regardless of timer + if (latestContentRef.current !== syncRef.current && onSave) { + syncRef.current = latestContentRef.current; + onSave(latestContentRef.current); } }; }, [onSave]); @@ -217,8 +221,15 @@ const RichTextEditor = forwardRef(({ saveTimeoutRef.current = setTimeout(async () => { setSaveStatus('saving'); const htmlToSave = latestContentRef.current; - await onSave(htmlToSave); - syncRef.current = htmlToSave; // Record that we've synced this exact string to the server + // Update syncRef BEFORE calling onSave, because onSave triggers setProjects + // which causes a re-render. The useEffect must see the updated syncRef + // to avoid re-writing innerHTML unnecessarily. + syncRef.current = htmlToSave; + try { + await onSave(htmlToSave); + } catch (err) { + console.error('Auto-save failed:', err); + } setSaveStatus('saved'); }, 2000); // 2 seconds } diff --git a/src/components/layout/EditorShell.tsx b/src/components/layout/EditorShell.tsx index 74e2877..dff8c2d 100644 --- a/src/components/layout/EditorShell.tsx +++ b/src/components/layout/EditorShell.tsx @@ -4,7 +4,7 @@ import React, { useState, useEffect } from 'react'; import { BookProject, UserProfile, ViewMode, ChatMessage } from '@/lib/types'; import AIPanel from '@/components/AIPanel'; -import { Book, FileText, Globe, GitGraph, Lightbulb, Settings, Menu, ChevronRight, ChevronLeft, Share2, HelpCircle, LogOut, LayoutDashboard, User, Plus, Trash2 } from 'lucide-react'; +import { Book, FileText, Globe, GitGraph, Lightbulb, Settings, Menu, ChevronRight, ChevronLeft, Share2, HelpCircle, LogOut, LayoutDashboard, User, Plus, Trash2, Wand2 } from 'lucide-react'; import { useLanguage } from '@/providers/LanguageProvider'; import { LanguageSwitcher } from '@/components/LanguageSwitcher'; @@ -157,6 +157,18 @@ const EditorShell: React.FC = (props) => {
{isAiPanelOpen && }
+ + {/* Floating Mobile Button for AI Panel */} + {!isAiPanelOpen && ( + + )} ); };