feat(NotesPage, MarkdownEditor): enhance note creation and editing experience

- Added state management for new notes in NotesPageClient to track if a note is newly created.
- Updated MarkdownEditor to support initial editing state and handle editing changes, improving user interaction during note creation and editing.
This commit is contained in:
Julien Froidefond
2025-11-17 08:27:34 +01:00
parent f0b9f75817
commit 6cad6a333d
2 changed files with 35 additions and 3 deletions

View File

@@ -20,6 +20,7 @@ interface NotesPageClientProps {
function NotesPageContent({ initialNotes }: { initialNotes: Note[] }) { function NotesPageContent({ initialNotes }: { initialNotes: Note[] }) {
const [notes, setNotes] = useState<Note[]>(initialNotes); const [notes, setNotes] = useState<Note[]>(initialNotes);
const [selectedNote, setSelectedNote] = useState<Note | null>(null); const [selectedNote, setSelectedNote] = useState<Note | null>(null);
const [isNewNote, setIsNewNote] = useState(false);
const { tags: availableTags } = useTasksContext(); const { tags: availableTags } = useTasksContext();
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
@@ -46,6 +47,7 @@ function NotesPageContent({ initialNotes }: { initialNotes: Note[] }) {
} }
setSelectedNote(note); setSelectedNote(note);
setIsNewNote(false);
setHasUnsavedChanges(false); setHasUnsavedChanges(false);
}, },
[hasUnsavedChanges, selectedNote] [hasUnsavedChanges, selectedNote]
@@ -60,6 +62,7 @@ function NotesPageContent({ initialNotes }: { initialNotes: Note[] }) {
setNotes((prev) => [newNote, ...prev]); setNotes((prev) => [newNote, ...prev]);
setSelectedNote(newNote); setSelectedNote(newNote);
setIsNewNote(true);
setHasUnsavedChanges(false); setHasUnsavedChanges(false);
} catch (err) { } catch (err) {
setError('Erreur lors de la création de la note'); setError('Erreur lors de la création de la note');
@@ -128,6 +131,7 @@ function NotesPageContent({ initialNotes }: { initialNotes: Note[] }) {
); );
setHasUnsavedChanges(false); setHasUnsavedChanges(false);
setIsNewNote(false);
} catch (err) { } catch (err) {
setError('Erreur lors de la sauvegarde'); setError('Erreur lors de la sauvegarde');
console.error('Error saving note:', err); console.error('Error saving note:', err);
@@ -279,6 +283,12 @@ function NotesPageContent({ initialNotes }: { initialNotes: Note[] }) {
onToggleSidebar={() => onToggleSidebar={() =>
setSidebarCollapsed(!sidebarCollapsed) setSidebarCollapsed(!sidebarCollapsed)
} }
initialIsEditing={isNewNote}
onEditingChange={(isEditing) => {
if (!isEditing) {
setIsNewNote(false);
}
}}
className="h-full" className="h-full"
/> />
</div> </div>

View File

@@ -288,6 +288,8 @@ interface MarkdownEditorProps {
onTaskChange?: (task: Task | null) => void; onTaskChange?: (task: Task | null) => void;
onCreateNote?: () => void; onCreateNote?: () => void;
onToggleSidebar?: () => void; onToggleSidebar?: () => void;
initialIsEditing?: boolean;
onEditingChange?: (isEditing: boolean) => void;
} }
export function MarkdownEditor({ export function MarkdownEditor({
@@ -305,9 +307,11 @@ export function MarkdownEditor({
onTaskChange, onTaskChange,
onCreateNote, onCreateNote,
onToggleSidebar, onToggleSidebar,
initialIsEditing = false,
onEditingChange,
}: MarkdownEditorProps) { }: MarkdownEditorProps) {
const [showPreview, setShowPreview] = useState(true); // Aperçu par défaut const [showPreview, setShowPreview] = useState(true); // Aperçu par défaut
const [isEditing, setIsEditing] = useState(false); // Mode édition const [isEditing, setIsEditing] = useState(initialIsEditing); // Mode édition
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
const autoSaveTimeoutRef = useRef<NodeJS.Timeout | null>(null); const autoSaveTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const lastSavedValueRef = useRef(value); const lastSavedValueRef = useRef(value);
@@ -454,6 +458,7 @@ export function MarkdownEditor({
case 'e': case 'e':
event.preventDefault(); event.preventDefault();
setIsEditing(!isEditing); setIsEditing(!isEditing);
onEditingChange?.(!isEditing);
break; break;
case 'b': case 'b':
event.preventDefault(); event.preventDefault();
@@ -598,6 +603,17 @@ export function MarkdownEditor({
} }
}, [value, history, historyIndex, addToHistory]); }, [value, history, historyIndex, addToHistory]);
// Réinitialiser le mode édition quand initialIsEditing devient true (nouvelle note)
useEffect(() => {
if (initialIsEditing) {
setIsEditing(true);
// Focus sur le textarea après un court délai pour s'assurer qu'il est monté
setTimeout(() => {
textareaRef.current?.focus();
}, 100);
}
}, [initialIsEditing]);
return ( return (
<div <div
className={`flex flex-col h-full bg-[var(--card)]/40 backdrop-blur-md border border-[var(--border)]/60 rounded-lg overflow-hidden relative before:absolute before:inset-0 before:bg-gradient-to-br before:from-[color-mix(in_srgb,var(--primary)_8%,transparent)] before:via-[color-mix(in_srgb,var(--primary)_4%,transparent)] before:to-transparent before:opacity-80 before:pointer-events-none ${className}`} className={`flex flex-col h-full bg-[var(--card)]/40 backdrop-blur-md border border-[var(--border)]/60 rounded-lg overflow-hidden relative before:absolute before:inset-0 before:bg-gradient-to-br before:from-[color-mix(in_srgb,var(--primary)_8%,transparent)] before:via-[color-mix(in_srgb,var(--primary)_4%,transparent)] before:to-transparent before:opacity-80 before:pointer-events-none ${className}`}
@@ -691,7 +707,10 @@ export function MarkdownEditor({
Aperçu Aperçu
</span> </span>
<button <button
onClick={() => setIsEditing(true)} onClick={() => {
setIsEditing(true);
onEditingChange?.(true);
}}
className="flex items-center gap-1 px-2 py-1 text-xs rounded bg-[var(--primary)]/80 hover:bg-[var(--primary)]/90 backdrop-blur-sm text-[var(--primary-foreground)] transition-all duration-200" className="flex items-center gap-1 px-2 py-1 text-xs rounded bg-[var(--primary)]/80 hover:bg-[var(--primary)]/90 backdrop-blur-sm text-[var(--primary-foreground)] transition-all duration-200"
> >
<Edit3 className="w-3 h-3" /> <Edit3 className="w-3 h-3" />
@@ -741,7 +760,10 @@ export function MarkdownEditor({
</span> </span>
)} )}
<button <button
onClick={() => setIsEditing(false)} onClick={() => {
setIsEditing(false);
onEditingChange?.(false);
}}
className="flex items-center gap-1 px-2 py-1 text-xs rounded bg-[var(--card)]/60 hover:bg-[var(--card)]/80 backdrop-blur-sm text-[var(--foreground)] border border-[var(--border)]/40 hover:border-[var(--border)]/60 transition-all duration-200" className="flex items-center gap-1 px-2 py-1 text-xs rounded bg-[var(--card)]/60 hover:bg-[var(--card)]/80 backdrop-blur-sm text-[var(--foreground)] border border-[var(--border)]/40 hover:border-[var(--border)]/60 transition-all duration-200"
> >
<X className="w-3 h-3" /> <X className="w-3 h-3" />