@@ -19,7 +19,7 @@ import { StarterKit } from "@tiptap/starter-kit";
1919import { type Editor , EditorContent , useEditor } from " @tiptap/vue-3" ;
2020import { useDebounceFn } from " @vueuse/core" ;
2121import { type NoteContent } from " shared" ;
22- import { onMounted , watch } from " vue" ;
22+ import { onMounted , onUnmounted , watch } from " vue" ;
2323
2424import " ./editor.css" ;
2525import { ArrowKeysFix } from " ./extensions/arrows-fix" ;
@@ -32,6 +32,7 @@ import SearchUI from "./extensions/search/SearchUI.vue";
3232
3333import { useSDK } from " @/plugins/sdk" ;
3434import { useNotesStore } from " @/stores/notes" ;
35+ import { emitter } from " @/utils/eventBus" ;
3536import { compressImage } from " @/utils/images" ;
3637
3738const sdk = useSDK ();
@@ -42,6 +43,44 @@ const SessionMention = createSessionMention(sdk);
4243const MAX_IMAGE_SIZE_MB = 30 ;
4344const ALLOWED_IMAGE_TYPES = [" image/jpeg" , " image/png" , " image/gif" ];
4445
46+ const cursorPositions = new Map <string , { from: number ; to: number }>();
47+
48+ const saveCursorPosition = () => {
49+ if (! editor .value || ! notesStore .currentNotePath ) return ;
50+
51+ const { from, to } = editor .value .state .selection ;
52+ cursorPositions .set (notesStore .currentNotePath , { from , to });
53+ };
54+
55+ const restoreCursorPosition = (notePath : string ) => {
56+ if (! editor .value ) return ;
57+
58+ const savedPosition = cursorPositions .get (notePath );
59+ if (savedPosition ) {
60+ const docLength = editor .value .state .doc .content .size ;
61+ const from = Math .min (savedPosition .from , docLength );
62+ const to = Math .min (savedPosition .to , docLength );
63+
64+ editor .value .commands .setTextSelection ({ from , to });
65+ }
66+
67+ editor .value .view .focus ();
68+ };
69+
70+ const restoreFocus = () => {
71+ if (! editor .value || ! notesStore .currentNotePath ) return ;
72+
73+ editor .value .view .focus ();
74+
75+ const savedPosition = cursorPositions .get (notesStore .currentNotePath );
76+ if (savedPosition ) {
77+ const docLength = editor .value .state .doc .content .size ;
78+ const from = Math .min (savedPosition .from , docLength );
79+ const to = Math .min (savedPosition .to , docLength );
80+ editor .value .commands .setTextSelection ({ from , to });
81+ }
82+ };
83+
4584const saveNote = async (editor : Editor ) => {
4685 if (! notesStore .currentNote ) return ;
4786
@@ -189,16 +228,29 @@ const editor = useEditor({
189228 debouncedSave (editor as Editor );
190229 }
191230 },
231+ onBlur : () => {
232+ saveCursorPosition ();
233+ },
192234});
193235
236+ let previousNotePath: string | undefined ;
237+
194238watch (
195239 () => notesStore .currentNote ,
196- (newNote ) => {
240+ (newNote , oldNote ) => {
241+ // Save cursor position of the previous note before switching
242+ if (previousNotePath && editor .value ) {
243+ const { from, to } = editor .value .state .selection ;
244+ cursorPositions .set (previousNotePath , { from , to });
245+ }
246+
197247 if (editor .value && newNote ) {
198248 const content = newNote .content ;
199249 editor .value .commands .setContent (content );
200- editor . value . commands . focus ( " end " );
250+ restoreCursorPosition ( newNote . path );
201251 }
252+
253+ previousNotePath = newNote ?.path ;
202254 },
203255 { immediate: true },
204256);
@@ -207,8 +259,15 @@ onMounted(() => {
207259 if (editor .value && notesStore .currentNote ) {
208260 const content = notesStore .currentNote .content ;
209261 editor .value .commands .setContent (content );
210- editor . value . commands . focus ( " end " );
262+ restoreCursorPosition ( notesStore . currentNote . path );
211263 }
264+
265+ emitter .on (" restoreFocus" , restoreFocus );
266+ });
267+
268+ onUnmounted (() => {
269+ saveCursorPosition ();
270+ emitter .off (" restoreFocus" , restoreFocus );
212271});
213272 </script >
214273
0 commit comments