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:
@@ -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>
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
Reference in New Issue
Block a user