diff --git a/src/App.tsx b/src/App.tsx index 41a32af..31b6ea4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -16,6 +16,7 @@ function App() { const [username, setUsername] = useState(''); const [theme, setTheme] = useState<'light' | 'dark' | 'system'>('system'); const [effectiveTheme, setEffectiveTheme] = useState<'light' | 'dark'>('light'); + const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); useEffect(() => { const savedServer = localStorage.getItem('serverURL'); @@ -193,11 +194,13 @@ function App() { onSearchChange={setSearchText} showFavoritesOnly={showFavoritesOnly} onToggleFavorites={() => setShowFavoritesOnly(!showFavoritesOnly)} + hasUnsavedChanges={hasUnsavedChanges} /> ); diff --git a/src/components/NoteEditor.tsx b/src/components/NoteEditor.tsx index c61a1ed..e84c067 100644 --- a/src/components/NoteEditor.tsx +++ b/src/components/NoteEditor.tsx @@ -11,6 +11,7 @@ interface NoteEditorProps { note: Note | null; onUpdateNote: (note: Note) => void; fontSize: number; + onUnsavedChanges?: (hasChanges: boolean) => void; } const turndownService = new TurndownService({ @@ -18,7 +19,7 @@ const turndownService = new TurndownService({ codeBlockStyle: 'fenced', }); -export function NoteEditor({ note, onUpdateNote, fontSize }: NoteEditorProps) { +export function NoteEditor({ note, onUpdateNote, fontSize, onUnsavedChanges }: NoteEditorProps) { const [localTitle, setLocalTitle] = useState(''); const [localFavorite, setLocalFavorite] = useState(false); const [isSaving, setIsSaving] = useState(false); @@ -26,6 +27,11 @@ export function NoteEditor({ note, onUpdateNote, fontSize }: NoteEditorProps) { const [titleManuallyEdited, setTitleManuallyEdited] = useState(false); const previousNoteIdRef = useRef(null); + // Notify parent component when unsaved changes state changes + useEffect(() => { + onUnsavedChanges?.(hasUnsavedChanges); + }, [hasUnsavedChanges, onUnsavedChanges]); + const editor = useEditor({ extensions: [ StarterKit, diff --git a/src/components/NotesList.tsx b/src/components/NotesList.tsx index 23bbe17..a0680cb 100644 --- a/src/components/NotesList.tsx +++ b/src/components/NotesList.tsx @@ -16,6 +16,7 @@ interface NotesListProps { onSearchChange: (text: string) => void; showFavoritesOnly: boolean; onToggleFavorites: () => void; + hasUnsavedChanges: boolean; } export function NotesList({ @@ -33,6 +34,7 @@ export function NotesList({ onSearchChange, showFavoritesOnly, onToggleFavorites, + hasUnsavedChanges, }: NotesListProps) { const [isSyncing, setIsSyncing] = React.useState(false); const [deleteClickedId, setDeleteClickedId] = React.useState(null); @@ -144,10 +146,21 @@ export function NotesList({ notes.map((note) => (
onSelectNote(note.id)} - className={`p-3 border-b border-gray-200 dark:border-gray-700 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors group ${ - note.id === selectedNoteId ? 'bg-blue-50 dark:bg-gray-800 border-l-4 border-l-blue-500' : '' + onClick={() => { + // Prevent switching if current note has unsaved changes + if (hasUnsavedChanges && note.id !== selectedNoteId) { + return; + } + onSelectNote(note.id); + }} + className={`p-3 border-b border-gray-200 dark:border-gray-700 transition-colors group ${ + note.id === selectedNoteId + ? 'bg-blue-50 dark:bg-gray-800 border-l-4 border-l-blue-500' + : hasUnsavedChanges + ? 'cursor-not-allowed opacity-50' + : 'cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800' }`} + title={hasUnsavedChanges && note.id !== selectedNoteId ? 'Save current note before switching' : ''} >