@@ -133,24 +133,213 @@ export default function Desktop() {
133133 const keyShortcutService =
134134 new WindowTopBarKeyShortcutRegistrationService ( ) ;
135135
136+ // Enhanced menu handlers
136137 const menuHandlers = {
137- onNew : ( ) => { } ,
138- onOpen : ( ) => { } ,
139- onOpenLocal : ( ) => { } ,
140- onSave : ( ) => { } ,
141- onSaveAs : ( ) => { } ,
138+ onNew : ( ) => {
139+ // Create a new blank document
140+ const newNote = {
141+ id : Date . now ( ) . toString ( ) ,
142+ title : 'Untitled Note' ,
143+ content : '' ,
144+ createdAt : new Date ( ) . toISOString ( ) ,
145+ } ;
146+
147+ // Save to localStorage or trigger state update
148+ const existingNotes = JSON . parse (
149+ localStorage . getItem ( 'orbitos-notes' ) || '[]' ,
150+ ) ;
151+ existingNotes . unshift ( newNote ) ;
152+ localStorage . setItem ( 'orbitos-notes' , JSON . stringify ( existingNotes ) ) ;
153+
154+ // Reload the notes app to show new document
155+ window . dispatchEvent ( new CustomEvent ( 'notes-refresh' ) ) ;
156+ } ,
157+ onOpen : ( ) => {
158+ // Show document picker modal
159+ const event = new CustomEvent ( 'show-notes-picker' , {
160+ detail : { action : 'open' } ,
161+ } ) ;
162+ window . dispatchEvent ( event ) ;
163+ } ,
164+ onOpenLocal : ( ) => {
165+ // Create file input for local file opening
166+ const fileInput = document . createElement ( 'input' ) ;
167+ fileInput . type = 'file' ;
168+ fileInput . accept = '.txt,.md,.json,text/plain' ;
169+ fileInput . style . display = 'none' ;
170+
171+ fileInput . onchange = ( event ) => {
172+ const file = event . target . files [ 0 ] ;
173+ if ( ! file ) return ;
174+
175+ const reader = new FileReader ( ) ;
176+ reader . onload = ( e ) => {
177+ const content = e . target . result ;
178+ const newNote = {
179+ id : Date . now ( ) . toString ( ) ,
180+ title : file . name . replace ( / \. [ ^ / . ] + $ / , '' ) , // Remove extension
181+ content : content ,
182+ createdAt : new Date ( ) . toISOString ( ) ,
183+ isLocalFile : true ,
184+ } ;
185+
186+ // Save to notes collection
187+ const existingNotes = JSON . parse (
188+ localStorage . getItem ( 'orbitos-notes' ) || '[]' ,
189+ ) ;
190+ existingNotes . unshift ( newNote ) ;
191+ localStorage . setItem (
192+ 'orbitos-notes' ,
193+ JSON . stringify ( existingNotes ) ,
194+ ) ;
195+
196+ // Load this note
197+ window . dispatchEvent (
198+ new CustomEvent ( 'notes-load' , {
199+ detail : { note : newNote } ,
200+ } ) ,
201+ ) ;
202+ } ;
203+ reader . readAsText ( file ) ;
204+ } ;
205+
206+ document . body . appendChild ( fileInput ) ;
207+ fileInput . click ( ) ;
208+ document . body . removeChild ( fileInput ) ;
209+ } ,
210+ onSave : async ( ) => {
211+ const currentNote = JSON . parse (
212+ localStorage . getItem ( 'orbitos-current-note' ) || '{}' ,
213+ ) ;
214+ const textarea = document . querySelector ( '.notes-textarea' ) ;
215+ const content = textarea ? textarea . value : '' ;
216+
217+ try {
218+ const response = await fetch ( '/api/files' , {
219+ method : 'POST' ,
220+ headers : { 'Content-Type' : 'application/json' } ,
221+ body : JSON . stringify ( {
222+ id : currentNote . _id , // Use database ID
223+ title : currentNote . title ,
224+ content : content ,
225+ } ) ,
226+ } ) ;
227+
228+ if ( response . ok ) {
229+ const { file } = await response . json ( ) ;
230+ // Update current note with saved version from database
231+ localStorage . setItem (
232+ 'orbitos-current-note' ,
233+ JSON . stringify ( file ) ,
234+ ) ;
235+ window . dispatchEvent (
236+ new CustomEvent ( 'show-notification' , {
237+ detail : {
238+ message : 'Note saved successfully!' ,
239+ type : 'success' ,
240+ } ,
241+ } ) ,
242+ ) ;
243+ }
244+ } catch ( error ) {
245+ console . error ( 'Save failed:' , error ) ;
246+ }
247+ } ,
248+ onSaveAs : async ( ) => {
249+ const textarea = document . querySelector ( '.notes-textarea' ) ;
250+ const content = textarea ? textarea . value : '' ;
251+ const currentNote = JSON . parse (
252+ localStorage . getItem ( 'orbitos-current-note' ) || '{}' ,
253+ ) ;
254+
255+ const fileName = prompt (
256+ 'Save as:' ,
257+ currentNote . name || 'Untitled Note' ,
258+ ) ;
259+ if ( ! fileName ) return ;
260+
261+ try {
262+ const response = await fetch ( '/api/files' , {
263+ method : 'POST' ,
264+ headers : { 'Content-Type' : 'application/json' } ,
265+ body : JSON . stringify ( {
266+ name : fileName ,
267+ content : content ,
268+ } ) ,
269+ } ) ;
270+
271+ if ( response . ok ) {
272+ const { file : savedFile } = await response . json ( ) ;
273+ localStorage . setItem (
274+ 'orbitos-current-note' ,
275+ JSON . stringify ( savedFile ) ,
276+ ) ;
277+
278+ window . dispatchEvent (
279+ new CustomEvent ( 'notes-title-update' , {
280+ detail : { name : fileName } , // Update to use 'name'
281+ } ) ,
282+ ) ;
283+
284+ window . dispatchEvent (
285+ new CustomEvent ( 'show-notification' , {
286+ detail : {
287+ message : `File saved as "${ fileName } "` ,
288+ type : 'success' ,
289+ } ,
290+ } ) ,
291+ ) ;
292+ }
293+ } catch ( error ) {
294+ console . error ( 'Save As failed:' , error ) ;
295+ window . dispatchEvent (
296+ new CustomEvent ( 'show-notification' , {
297+ detail : { message : 'Failed to save file' , type : 'error' } ,
298+ } ) ,
299+ ) ;
300+ }
301+ } ,
142302 onPrint : ( ) => window . print ( ) ,
143303 onUndo : ( ) => document . execCommand ( 'undo' ) ,
144304 onRedo : ( ) => document . execCommand ( 'redo' ) ,
145305 onCut : ( ) => document . execCommand ( 'cut' ) ,
146306 onCopy : ( ) => document . execCommand ( 'copy' ) ,
147307 onPaste : ( ) => document . execCommand ( 'paste' ) ,
148- onFind : ( ) => { } ,
149- onReplace : ( ) => { } ,
308+ onFind : ( ) => {
309+ window . dispatchEvent (
310+ new CustomEvent ( 'toggle-find-replace' , {
311+ detail : { show : true , mode : 'find' } ,
312+ } ) ,
313+ ) ;
314+ } ,
315+ onReplace : ( ) => {
316+ window . dispatchEvent (
317+ new CustomEvent ( 'toggle-find-replace' , {
318+ detail : { show : true , mode : 'replace' } ,
319+ } ) ,
320+ ) ;
321+ } ,
150322 onFindInFiles : ( ) => { } ,
151- onFindNext : ( ) => { } ,
152- onFindPrevious : ( ) => { } ,
153- onSelectFindNext : ( ) => { } ,
323+ onFindNext : ( ) => {
324+ window . dispatchEvent ( new Event ( 'find-next' ) ) ;
325+ } ,
326+ onFindPrevious : ( ) => {
327+ window . dispatchEvent ( new Event ( 'find-previous' ) ) ;
328+ } ,
329+ onSelectFindNext : ( ) => {
330+ const textarea = document . querySelector ( '.notes-textarea' ) ;
331+ if ( textarea && textarea . selectionStart !== textarea . selectionEnd ) {
332+ const selectedText = textarea . value . substring (
333+ textarea . selectionStart ,
334+ textarea . selectionEnd ,
335+ ) ;
336+ window . dispatchEvent (
337+ new CustomEvent ( 'find-text' , {
338+ detail : { text : selectedText , forward : true } ,
339+ } ) ,
340+ ) ;
341+ }
342+ } ,
154343 onSelectFindPrevious : ( ) => { } ,
155344 onFindVolatileNext : ( ) => { } ,
156345 onFindVolatilePrevious : ( ) => { } ,
0 commit comments