| 
									
										
										
										
											2025-08-04 18:54:17 +03:00
										 |  |  | import ReactBasicWidget from "../react/ReactBasicWidget"; | 
					
						
							|  |  |  | import Modal from "../react/Modal"; | 
					
						
							|  |  |  | import Button from "../react/Button"; | 
					
						
							|  |  |  | import NoteAutocomplete from "../react/NoteAutocomplete"; | 
					
						
							|  |  |  | import { t } from "../../services/i18n"; | 
					
						
							|  |  |  | import { useEffect, useRef, useState } from "preact/hooks"; | 
					
						
							|  |  |  | import note_autocomplete, { Suggestion } from "../../services/note_autocomplete"; | 
					
						
							|  |  |  | import appContext from "../../components/app_context"; | 
					
						
							|  |  |  | import commandRegistry from "../../services/command_registry"; | 
					
						
							| 
									
										
										
										
											2025-08-06 18:38:52 +03:00
										 |  |  | import { refToJQuerySelector } from "../react/react_utils"; | 
					
						
							| 
									
										
										
										
											2025-08-10 11:38:12 +03:00
										 |  |  | import useTriliumEvent from "../react/hooks"; | 
					
						
							| 
									
										
										
										
											2025-08-04 18:54:17 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | const KEEP_LAST_SEARCH_FOR_X_SECONDS = 120; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type Mode = "last-search" | "recent-notes" | "commands"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-10 11:38:12 +03:00
										 |  |  | function JumpToNoteDialogComponent() { | 
					
						
							|  |  |  |     const [ mode, setMode ] = useState<Mode>("last-search"); | 
					
						
							|  |  |  |     const [ lastOpenedTs, setLastOpenedTs ] = useState<number>(0); | 
					
						
							| 
									
										
										
										
											2025-08-04 18:54:17 +03:00
										 |  |  |     const containerRef = useRef<HTMLDivElement>(null); | 
					
						
							|  |  |  |     const autocompleteRef = useRef<HTMLInputElement>(null); | 
					
						
							|  |  |  |     const [ isCommandMode, setIsCommandMode ] = useState(mode === "commands"); | 
					
						
							|  |  |  |     const [ text, setText ] = useState(isCommandMode ? "> " : ""); | 
					
						
							| 
									
										
										
										
											2025-08-10 11:38:12 +03:00
										 |  |  |     const [ shown, setShown ] = useState(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async function openDialog(commandMode: boolean) {         | 
					
						
							|  |  |  |         let newMode: Mode; | 
					
						
							|  |  |  |         if (commandMode) { | 
					
						
							|  |  |  |             newMode = "commands";             | 
					
						
							|  |  |  |         } else if (Date.now() - lastOpenedTs > KEEP_LAST_SEARCH_FOR_X_SECONDS * 1000) { | 
					
						
							|  |  |  |             // if you open the Jump To dialog soon after using it previously, it can often mean that you
 | 
					
						
							|  |  |  |             // actually want to search for the same thing (e.g., you opened the wrong note at first try)
 | 
					
						
							|  |  |  |             // so we'll keep the content.
 | 
					
						
							|  |  |  |             // if it's outside of this time limit, then we assume it's a completely new search and show recent notes instead.
 | 
					
						
							|  |  |  |             newMode = "recent-notes"; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             newMode = "last-search"; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (mode !== newMode) { | 
					
						
							|  |  |  |             setMode(newMode); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         setShown(true); | 
					
						
							|  |  |  |         setLastOpenedTs(Date.now()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     useTriliumEvent("jumpToNote", () => openDialog(false)); | 
					
						
							|  |  |  |     useTriliumEvent("commandPalette", () => openDialog(true)); | 
					
						
							| 
									
										
										
										
											2025-08-04 18:54:17 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     useEffect(() => { | 
					
						
							|  |  |  |         setIsCommandMode(text.startsWith(">")); | 
					
						
							|  |  |  |     }, [ text ]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-10 13:02:17 +03:00
										 |  |  |     async function onItemSelected(suggestion?: Suggestion | null) { | 
					
						
							|  |  |  |         if (!suggestion) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |          | 
					
						
							| 
									
										
										
										
											2025-08-10 12:22:11 +03:00
										 |  |  |         setShown(false); | 
					
						
							| 
									
										
										
										
											2025-08-04 18:54:17 +03:00
										 |  |  |         if (suggestion.notePath) { | 
					
						
							|  |  |  |             appContext.tabManager.getActiveContext()?.setNote(suggestion.notePath); | 
					
						
							|  |  |  |         } else if (suggestion.commandId) { | 
					
						
							|  |  |  |             await commandRegistry.executeCommand(suggestion.commandId); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function onShown() { | 
					
						
							| 
									
										
										
										
											2025-08-06 18:38:52 +03:00
										 |  |  |         const $autoComplete = refToJQuerySelector(autocompleteRef); | 
					
						
							| 
									
										
										
										
											2025-08-04 18:54:17 +03:00
										 |  |  |         switch (mode) { | 
					
						
							|  |  |  |             case "last-search": | 
					
						
							| 
									
										
										
										
											2025-08-04 19:27:47 +03:00
										 |  |  |                 // Fall-through if there is no text, in order to display the recent notes.
 | 
					
						
							|  |  |  |                 if (text) { | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2025-08-04 18:54:17 +03:00
										 |  |  |             case "recent-notes": | 
					
						
							|  |  |  |                 note_autocomplete.showRecentNotes($autoComplete); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case "commands": | 
					
						
							|  |  |  |                 note_autocomplete.showAllCommands($autoComplete); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $autoComplete | 
					
						
							|  |  |  |             .trigger("focus") | 
					
						
							|  |  |  |             .trigger("select"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ( | 
					
						
							|  |  |  |         <Modal | 
					
						
							|  |  |  |             className="jump-to-note-dialog" | 
					
						
							|  |  |  |             size="lg" | 
					
						
							|  |  |  |             title={<NoteAutocomplete | 
					
						
							|  |  |  |                 placeholder={t("jump_to_note.search_placeholder")} | 
					
						
							|  |  |  |                 inputRef={autocompleteRef} | 
					
						
							|  |  |  |                 container={containerRef} | 
					
						
							|  |  |  |                 text={text} | 
					
						
							|  |  |  |                 opts={{ | 
					
						
							|  |  |  |                     allowCreatingNotes: true, | 
					
						
							|  |  |  |                     hideGoToSelectedNoteButton: true, | 
					
						
							|  |  |  |                     allowJumpToSearchNotes: true, | 
					
						
							|  |  |  |                     isCommandPalette: true | 
					
						
							|  |  |  |                 }} | 
					
						
							|  |  |  |                 onTextChange={setText} | 
					
						
							|  |  |  |                 onChange={onItemSelected} | 
					
						
							|  |  |  |                 />} | 
					
						
							|  |  |  |             onShown={onShown} | 
					
						
							| 
									
										
										
										
											2025-08-10 11:38:12 +03:00
										 |  |  |             onHidden={() => setShown(false)} | 
					
						
							| 
									
										
										
										
											2025-08-04 18:54:17 +03:00
										 |  |  |             footer={!isCommandMode && <Button className="show-in-full-text-button" text={t("jump_to_note.search_button")} keyboardShortcut="Ctrl+Enter" />} | 
					
						
							| 
									
										
										
										
											2025-08-10 11:38:12 +03:00
										 |  |  |             show={shown} | 
					
						
							| 
									
										
										
										
											2025-08-04 18:54:17 +03:00
										 |  |  |         > | 
					
						
							|  |  |  |             <div className="algolia-autocomplete-container jump-to-note-results" ref={containerRef}></div> | 
					
						
							|  |  |  |         </Modal> | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default class JumpToNoteDialog extends ReactBasicWidget { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     get component() { | 
					
						
							| 
									
										
										
										
											2025-08-10 11:38:12 +03:00
										 |  |  |         return <JumpToNoteDialogComponent />; | 
					
						
							| 
									
										
										
										
											2025-08-04 18:54:17 +03:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |