From cf33cea1c97a472ba6789325e13ac8999dd2faa4 Mon Sep 17 00:00:00 2001 From: alihamuh Date: Fri, 27 Jan 2023 09:16:51 +0500 Subject: [PATCH] web: added (highlighting search query in note) for search feature. --- apps/web/src/components/editor/tiptap.tsx | 18 +++ apps/web/src/navigation/routes.js | 134 +++++++++++------- apps/web/src/stores/note-store.js | 9 ++ apps/web/src/views/search.js | 6 +- .../src/toolbar/popups/search-replace.tsx | 1 + 5 files changed, 111 insertions(+), 57 deletions(-) diff --git a/apps/web/src/components/editor/tiptap.tsx b/apps/web/src/components/editor/tiptap.tsx index 12531b203..2e01ffc24 100644 --- a/apps/web/src/components/editor/tiptap.tsx +++ b/apps/web/src/components/editor/tiptap.tsx @@ -52,6 +52,7 @@ import { showBuyDialog } from "../../common/dialog-controller"; import { useStore as useSettingsStore } from "../../stores/setting-store"; import { debounceWithId } from "../../utils/debounce"; import { store as editorstore } from "../../stores/editor-store"; +import { useStore as useNoteStore } from "../../stores/note-store"; type TipTapProps = { editorContainer: HTMLElement; @@ -121,6 +122,7 @@ function TipTap(props: TipTapProps) { const doubleSpacedLines = useSettingsStore( (store) => store.doubleSpacedLines ); + const search = useNoteStore((store) => store.search); const { toolbarConfig } = useToolbarConfig(); const { isSearching, toggleSearch } = useSearch(); @@ -170,6 +172,8 @@ function TipTap(props: TipTapProps) { } }); if (onLoad) onLoad(); + + if (search && !isSearching) toggleSearch(); }, onUpdate: ({ editor, transaction }) => { onContentChange?.(); @@ -251,6 +255,20 @@ function TipTap(props: TipTapProps) { () => { const isEditorSearching = editor?.storage.searchreplace?.isSearching; if (isSearching && !isEditorSearching) toggleSearch(); + if (search && !isSearching) toggleSearch(); + + if (search && isSearching && isEditorSearching) { + setTimeout(() => { + ( + document.getElementById("search-replace-input") as HTMLInputElement + ).value = search["query"]; + editor.commands.search(search["query"], { + enableRegex: true, + matchCase: false, + matchWholeWord: false + }); + }, 500); + } }, // eslint-disable-next-line react-hooks/exhaustive-deps [toggleSearch, editor?.storage.searchreplace?.isSearching] diff --git a/apps/web/src/navigation/routes.js b/apps/web/src/navigation/routes.js index f6c4f2422..c1c2d4519 100644 --- a/apps/web/src/navigation/routes.js +++ b/apps/web/src/navigation/routes.js @@ -33,32 +33,39 @@ import { showToast } from "../utils/toast"; import Reminders from "../views/reminders"; const routes = { - "/notes": () => ({ - key: "home", - type: "notes", - title: "Notes", - component: , - buttons: { - search: { - title: "Search notes" + "/notes": () => { + notestore.clearSearch(); + return { + key: "home", + type: "notes", + title: "Notes", + component: , + buttons: { + search: { + title: "Search notes" + } } - } - }), - "/notebooks": () => ({ - key: "notebooks", - type: "notebooks", - title: "Notebooks", - component: , - buttons: { - search: { - title: "Search notebooks" + }; + }, + "/notebooks": () => { + notestore.clearSearch(); + return { + key: "notebooks", + type: "notebooks", + title: "Notebooks", + component: , + buttons: { + search: { + title: "Search notebooks" + } } - } - }), + }; + }, "/notebooks/:notebookId": ({ notebookId }) => { const notebook = db.notebooks.notebook(notebookId); if (!notebook) return false; nbstore.setSelectedNotebook(notebookId); + notestore.clearSearch(); return { key: "topics", type: "topics", @@ -82,6 +89,7 @@ const routes = { type: "topic", value: { id: notebookId, topic: topicId } }); + notestore.clearSearch(); return { key: "notes", type: "notes", @@ -106,6 +114,7 @@ const routes = { }, "/favorites": () => { notestore.setContext({ type: "favorite" }); + notestore.clearSearch(); return { key: "notes", title: "Favorites", @@ -119,6 +128,7 @@ const routes = { }; }, "/reminders": () => { + notestore.clearSearch(); return { key: "reminders", title: "Reminders", @@ -131,34 +141,41 @@ const routes = { } }; }, - "/trash": () => ({ - key: "trash", - type: "trash", - title: "Trash", - component: , - buttons: { - search: { - title: "Search trash" + "/trash": () => { + notestore.clearSearch(); + return { + key: "trash", + type: "trash", + title: "Trash", + component: , + buttons: { + search: { + title: "Search trash" + } } - } - }), - "/tags": () => ({ - key: "tags", - title: "Tags", - type: "tags", - component: , - buttons: { - search: { - title: "Search tags" + }; + }, + "/tags": () => { + notestore.clearSearch(); + return { + key: "tags", + title: "Tags", + type: "tags", + component: , + buttons: { + search: { + title: "Search tags" + } } - } - }), + }; + }, "/tags/:tagId": ({ tagId }) => { const tag = db.tags.tag(tagId); if (!tag) return false; const { id } = tag; notestore.setContext({ type: "tag", value: id }); const title = db.tags.alias(id); + notestore.clearSearch(); return { key: "notes", type: "notes", @@ -181,6 +198,7 @@ const routes = { const { id } = color; const title = db.colors.alias(id); notestore.setContext({ type: "color", value: id }); + notestore.clearSearch(); return { key: "notes", type: "notes", @@ -193,13 +211,17 @@ const routes = { } }; }, - "/settings": () => ({ - key: "settings", - title: "Settings", - component: - }), + "/settings": () => { + notestore.clearSearch(); + return { + key: "settings", + title: "Settings", + component: + }; + }, "/monographs": () => { notestore.setContext({ type: "monographs" }); + notestore.clearSearch(); return { key: "notes", title: "Monographs", @@ -212,17 +234,19 @@ const routes = { } }; }, - "/search/:type": ({ type }) => ({ - type: "search", - title: "Search", - component: , - buttons: { - back: { - title: `Go back to ${type}`, - action: () => window.history.back() + "/search/:type": ({ type }) => { + return { + type: "search", + title: "Search", + component: , + buttons: { + back: { + title: `Go back to ${type}`, + action: () => window.history.back() + } } - } - }) + }; + } }; export default routes; diff --git a/apps/web/src/stores/note-store.js b/apps/web/src/stores/note-store.js index 303e2da14..bf313112a 100644 --- a/apps/web/src/stores/note-store.js +++ b/apps/web/src/stores/note-store.js @@ -35,6 +35,7 @@ class NoteStore extends BaseStore { selectedNote = 0; nonce = 0; viewMode = Config.get("notes:viewMode", "detailed"); + search = undefined; setViewMode = (viewMode) => { this.set((state) => (state.viewMode = viewMode)); @@ -170,6 +171,14 @@ class NoteStore extends BaseStore { } }; + setSearch = (query) => { + this.set((state) => (state.search = { query })); + }; + + clearSearch = () => { + this.set((state) => (state.search = undefined)); + }; + /** * @private */ diff --git a/apps/web/src/views/search.js b/apps/web/src/views/search.js index b54fee3c9..719185f33 100644 --- a/apps/web/src/views/search.js +++ b/apps/web/src/views/search.js @@ -62,12 +62,14 @@ function Search({ type }) { const [results, setResults] = useState([]); const context = useNoteStore((store) => store.context); const nonce = useNoteStore((store) => store.nonce); + const setSearch = useNoteStore((store) => store.setSearch); const cachedQuery = useRef(); const onSearch = useCallback( async (query) => { if (!query) return; cachedQuery.current = query; + setSearch(query); const [lookupType, items] = await typeToItems(type, context); setResults([]); @@ -81,7 +83,7 @@ function Search({ type }) { setResults(results); setSearchState({ isSearching: false, totalItems: 0 }); }, - [context, type] + [context, type, setSearch] ); const title = useMemo(() => { @@ -161,7 +163,7 @@ function Search({ type }) { ) : ( ( diff --git a/packages/editor/src/toolbar/popups/search-replace.tsx b/packages/editor/src/toolbar/popups/search-replace.tsx index f6e76362b..979511b15 100644 --- a/packages/editor/src/toolbar/popups/search-replace.tsx +++ b/packages/editor/src/toolbar/popups/search-replace.tsx @@ -101,6 +101,7 @@ export function SearchReplacePopup(props: SearchReplacePopupProps) { }} >