'use client' import { useNoteEditorContext } from './note-editor-context' import { NoteEditorToolbar } from './note-editor-toolbar' import { NoteTitleBlock } from './note-title-block' import { NoteContentArea } from './note-content-area' import { EditorImages } from '@/components/editor-images' import { ComparisonModal } from '@/components/comparison-modal' import { FusionModal } from '@/components/fusion-modal' import { ReminderDialog } from '@/components/reminder-dialog' import { ContextualAIChat } from '@/components/contextual-ai-chat' import { NoteDocumentInfoPanel } from '@/components/note-document-info-panel' import { format } from 'date-fns' import { ChevronRight } from 'lucide-react' import { toast } from 'sonner' import { Note } from '@/lib/types' import { GhostTags } from '@/components/ghost-tags' import { LabelBadge } from '@/components/label-badge' interface NoteEditorFullPageProps { onClose: () => void } export function NoteEditorFullPage({ onClose }: NoteEditorFullPageProps) { const { state, actions, note, readOnly, notebooks, fileInputRef, globalLabels } = useNoteEditorContext() const notebookName = notebooks.find(nb => nb.id === note.notebookId)?.name || null const getLabelType = (name: string): 'ai' | 'user' => { const found = globalLabels.find(l => l.name.toLowerCase() === name.toLowerCase()) return (found as any)?.type === 'ai' ? 'ai' : 'user' } return ( <> {/* ── outer container ── */}
{/* ── main scrollable column ── */}
{/* TOOLBAR */} {/* BODY — max-w-4xl, responsive px, py-16 */}
{/* Breadcrumb + Title block */}
{/* Breadcrumb: Notebook › Date */}
{notebookName && {notebookName}} {notebookName && } {format(new Date(note.contentUpdatedAt), 'MMM d, yyyy')}
{/* Title */} {(state.labels.length > 0 || (state.filteredSuggestions.length > 0)) && (
{state.labels.map((label) => ( actions.handleRemoveLabel(label)} /> ))} {!readOnly && ( )}
)}
{/* Hero image — show first note image if present */} {state.allImages.length > 0 && (
{state.title}
)} {/* Content area — max-w-3xl for wider reading column */}
{/* ── Side panel: AI Chat ── */} {state.aiOpen && (
actions.setAiOpen(false)} noteTitle={state.title} noteContent={state.content} noteImages={state.allImages} noteId={note.id} onApplyToNote={(nc: string) => { actions.setPreviousContentForCopilot(state.content) actions.setContent(nc) if (state.isMarkdown) actions.setShowMarkdownPreview(true) }} onUndoLastAction={state.previousContentForCopilot !== null ? () => { actions.setContent(state.previousContentForCopilot!); actions.setPreviousContentForCopilot(null) } : undefined} lastActionApplied={state.previousContentForCopilot !== null} notebooks={notebooks} notebookId={note.notebookId ?? undefined} notebookName={notebookName ?? undefined} diagramInsertFormat={state.isMarkdown ? 'markdown' : 'html'} onGenerateTitle={async () => { const plain = state.content.replace(/<[^>]+>/g, ' ').trim() const wordCount = plain.split(/\s+/).filter(Boolean).length if (wordCount < 10) { toast.error('Ajoutez au moins 10 mots avant de générer un titre.') return } actions.setIsProcessingAI(true) try { const res = await fetch('/api/ai/title-suggestions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content: plain }), }) if (res.ok) { const data = await res.json() const s = data.suggestions?.[0]?.title ?? '' if (s) { actions.setTitle(s) toast.success('Titre généré !') } else { toast.error('Impossible de générer un titre.') } } else { toast.error('Erreur lors de la génération du titre.') } } catch { toast.error('Erreur réseau.') } finally { actions.setIsProcessingAI(false) } }} />
)} {/* ── Side panel: Document Info ── */} {state.infoOpen && (
actions.setInfoOpen(false)} onNoteRestored={(r: Note) => { actions.setContent(r.content || ''); actions.setTitle(r.title || ''); actions.setIsDirty(false) }} />
)}
) }