'use client' import { useState, useRef } from 'react' import { useNoteEditorContext } from './note-editor-context' import { LabelManager } from '@/components/label-manager' import { LabelBadge } from '@/components/label-badge' import { GhostTags } from '@/components/ghost-tags' import { EditorImages } from '@/components/editor-images' import { TitleSuggestions } from '@/components/title-suggestions' import { NoteTypeSelector } from '@/components/note-type-selector' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { X, Plus, Palette, Image as ImageIcon, Bell, Eye, Link as LinkIcon, Sparkles, Maximize2, Copy, ArrowLeft, ChevronRight, PanelRight, Check, Loader2, Save, MoreHorizontal, Trash2, LogOut, Wand2, Share2 } from 'lucide-react' import { NoteShareDialog } from './note-share-dialog' import { deleteNote, leaveSharedNote } from '@/app/actions/notes' import { useRefresh } from '@/lib/use-refresh' import { useLanguage } from '@/lib/i18n' import { NOTE_COLORS, NoteColor, Note } from '@/lib/types' import { cn } from '@/lib/utils' import { toast } from 'sonner' import { format } from 'date-fns' interface NoteEditorToolbarProps { mode: 'fullPage' | 'dialog' onClose: () => void } export function NoteEditorToolbar({ mode, onClose }: NoteEditorToolbarProps) { const { state, actions, note, readOnly, fullPage, notebooks, fileInputRef } = useNoteEditorContext() const { t } = useLanguage() const { refreshNotes } = useRefresh() const [isConverting, setIsConverting] = useState(false) const [shareOpen, setShareOpen] = useState(false) const notebookName = notebooks.find(nb => nb.id === note.notebookId)?.name || null // Snapshot for undo — stored in a ref so the toast callback isn't a stale closure const undoSnapshotRef = useRef<{ content: string; noteType: string } | null>(null) const handleConvertToRichtext = async () => { if (isConverting || !state.content.trim()) return setIsConverting(true) // Capture snapshot BEFORE converting const snapshot = { content: state.content, noteType: state.noteType } undoSnapshotRef.current = snapshot try { let html: string if (state.noteType === 'markdown') { // Proper markdown → HTML via marked (no AI needed) const { marked } = await import('marked') html = await marked(state.content, { async: false }) as string } else { // Plain text → wrap paragraphs in

tags html = state.content .split(/\n{2,}/) .map(para => `

${para.trim().replace(/\n/g, '
')}

`) .join('') } actions.setContent(html) actions.setNoteType('richtext') toast.success(t('notes.convertedToRichText') || 'Converted to rich text', { duration: 8000, action: { label: t('notes.undo') || '↩ Undo', onClick: () => { const snap = undoSnapshotRef.current if (!snap) return actions.setContent(snap.content) actions.setNoteType(snap.noteType as any) undoSnapshotRef.current = null toast.info(t('ai.undoApplied') || 'Conversion undone') }, }, }) } catch { toast.error(t('notes.transformFailed') || 'Conversion failed') } finally { setIsConverting(false) } } if (mode === 'fullPage') { return (
{/* Left: back */} {/* Right: status + type + AI + Info */}
{/* Save status */} {state.isSaving ? <>Saving… : state.isDirty ? <>Modified : <>Saved} {/* Note type */} { actions.setNoteType(newType); actions.setIsDirty(true) }} compact /> {/* Preview toggle — icon only */} {(state.noteType === 'text' || state.noteType === 'markdown') && !readOnly && ( )} {/* Convert to Rich Text — icon only */} {(state.noteType === 'text' || state.noteType === 'markdown') && !readOnly && ( )} {/* AI — icon only */} {/* Save — icon only */} {!readOnly && ( )} {/* Share button */} {!readOnly && ( )} {/* Three-dot options menu */} {!readOnly && ( { try { await deleteNote(note.id) refreshNotes(note.notebookId) toast.success('Note supprimée.') onClose() } catch { toast.error('Impossible de supprimer.') } }} className="text-red-600 dark:text-red-400 focus:text-red-600" > Supprimer la note )} {/* Share Dialog portal */} {shareOpen && ( setShareOpen(false)} /> )} {/* Info panel toggle — rightmost, icon only */}
) } // Dialog toolbar return (
{!readOnly && ( <> {/* Reminder */} {/* Add Image */} {/* Add Link */} { actions.setNoteType(newType); if (newType !== 'markdown') actions.setShowMarkdownPreview(false) }} /> {state.noteType === 'markdown' && ( )} {/* AI Copilot */} {state.noteType !== 'checklist' && ( )} {/* Size Selector */}
{(['small', 'medium', 'large'] as const).map((s) => ( ))}
{/* Color Picker */}
{Object.entries(NOTE_COLORS).map(([colorName, classes]) => (
{/* Label Manager */} )} {readOnly && (
{t('notes.sharedReadOnly')}
)}
{readOnly ? ( <> ) : ( <> )}
) }