diff --git a/apps/client/src/layouts/desktop_layout.tsx b/apps/client/src/layouts/desktop_layout.tsx index 35de1a868..79e8d2da4 100644 --- a/apps/client/src/layouts/desktop_layout.tsx +++ b/apps/client/src/layouts/desktop_layout.tsx @@ -11,7 +11,6 @@ import NoteListWidget from "../widgets/note_list.js"; import SqlResultWidget from "../widgets/sql_result.js"; import SqlTableSchemasWidget from "../widgets/sql_table_schemas.js"; import NoteIconWidget from "../widgets/note_icon.jsx"; -import SearchResultWidget from "../widgets/search_result.js"; import ScrollingContainer from "../widgets/containers/scrolling_container.js"; import RootContainer from "../widgets/containers/root_container.js"; import WatchedFileUpdateStatusWidget from "../widgets/watched_file_update_status.js"; @@ -42,6 +41,7 @@ import { applyModals } from "./layout_commons.js"; import Ribbon from "../widgets/ribbon/Ribbon.jsx"; import FloatingButtons from "../widgets/FloatingButtons.jsx"; import { DESKTOP_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx"; +import SearchResult from "../widgets/search_result.jsx"; export default class DesktopLayout { @@ -139,7 +139,7 @@ export default class DesktopLayout { .child(new SqlTableSchemasWidget()) .child(new NoteDetailWidget()) .child(new NoteListWidget(false)) - .child(new SearchResultWidget()) + .child() .child(new SqlResultWidget()) .child() ) diff --git a/apps/client/src/widgets/react/Alert.tsx b/apps/client/src/widgets/react/Alert.tsx index 8b8afb68b..e57960157 100644 --- a/apps/client/src/widgets/react/Alert.tsx +++ b/apps/client/src/widgets/react/Alert.tsx @@ -4,11 +4,12 @@ interface AlertProps { type: "info" | "danger" | "warning"; title?: string; children: ComponentChildren; + className?: string; } -export default function Alert({ title, type, children }: AlertProps) { +export default function Alert({ title, type, children, className }: AlertProps) { return ( -
+
{title &&

{title}

} {children} diff --git a/apps/client/src/widgets/search_result.css b/apps/client/src/widgets/search_result.css new file mode 100644 index 000000000..5142bd776 --- /dev/null +++ b/apps/client/src/widgets/search_result.css @@ -0,0 +1,16 @@ +.search-result-widget { + flex-grow: 100000; + flex-shrink: 100000; + min-height: 0; + overflow: auto; + contain: none !important; +} + +.search-result-widget .note-list { + padding: 10px; +} + +.search-no-results, .search-not-executed-yet { + margin: 20px; + padding: 20px !important; +} \ No newline at end of file diff --git a/apps/client/src/widgets/search_result.ts b/apps/client/src/widgets/search_result.ts deleted file mode 100644 index 6fa69ae13..000000000 --- a/apps/client/src/widgets/search_result.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { t } from "../services/i18n.js"; -import NoteContextAwareWidget from "./note_context_aware_widget.js"; -import NoteListRenderer from "../services/note_list_renderer.js"; -import type FNote from "../entities/fnote.js"; -import type { EventData } from "../components/app_context.js"; - -const TPL = /*html*/` -
- - -
- ${t("search_result.no_notes_found")} -
- -
- ${t("search_result.search_not_executed")} -
- -
-
-
`; - -export default class SearchResultWidget extends NoteContextAwareWidget { - - private $content!: JQuery; - private $noResults!: JQuery; - private $notExecutedYet!: JQuery; - - isEnabled() { - return super.isEnabled() && this.note?.type === "search"; - } - - doRender() { - this.$widget = $(TPL); - this.contentSized(); - this.$content = this.$widget.find(".search-result-widget-content"); - this.$noResults = this.$widget.find(".search-no-results"); - this.$notExecutedYet = this.$widget.find(".search-not-executed-yet"); - } - - async refreshWithNote(note: FNote) { - const noResults = note.getChildNoteIds().length === 0 && !!note.searchResultsLoaded; - - this.$content.empty(); - this.$noResults.toggle(noResults); - this.$notExecutedYet.toggle(!note.searchResultsLoaded); - - if (noResults || !note.searchResultsLoaded) { - return; - } - - const noteListRenderer = new NoteListRenderer({ - $parent: this.$content, - parentNote: note, - showNotePath: true - }); - await noteListRenderer.renderList(); - } - - searchRefreshedEvent({ ntxId }: EventData<"searchRefreshed">) { - if (!this.isNoteContext(ntxId)) { - return; - } - - this.refresh(); - } - - notesReloadedEvent({ noteIds }: EventData<"notesReloaded">) { - if (this.noteId && noteIds.includes(this.noteId)) { - this.refresh(); - } - } -} diff --git a/apps/client/src/widgets/search_result.tsx b/apps/client/src/widgets/search_result.tsx new file mode 100644 index 000000000..3392fbc69 --- /dev/null +++ b/apps/client/src/widgets/search_result.tsx @@ -0,0 +1,63 @@ +import { useEffect, useRef, useState } from "preact/hooks"; +import { t } from "../services/i18n"; +import Alert from "./react/Alert"; +import { useNoteContext, useNoteProperty, useTriliumEvent } from "./react/hooks"; +import "./search_result.css"; +import NoteListRenderer from "../services/note_list_renderer"; + +enum SearchResultState { + NO_RESULTS, + NOT_EXECUTED, + GOT_RESULTS +} + +export default function SearchResult() { + const { note, ntxId } = useNoteContext(); + const [ state, setState ] = useState(); + const searchContainerRef = useRef(null); + + function refresh() { + searchContainerRef.current?.replaceChildren(); + + if (!note?.searchResultsLoaded) { + setState(SearchResultState.NOT_EXECUTED); + } else if (note.getChildNoteIds().length === 0) { + setState(SearchResultState.NO_RESULTS); + } else if (searchContainerRef.current) { + setState(SearchResultState.GOT_RESULTS); + + const noteListRenderer = new NoteListRenderer({ + $parent: $(searchContainerRef.current), + parentNote: note, + showNotePath: true + }); + noteListRenderer.renderList(); + } + } + + useEffect(() => refresh(), [ note ]); + useTriliumEvent("searchRefreshed", ({ ntxId: eventNtxId }) => { + if (eventNtxId === ntxId) { + refresh(); + } + }); + useTriliumEvent("notesReloaded", ({ noteIds }) => { + if (note?.noteId && noteIds.includes(note.noteId)) { + refresh(); + } + }); + + return ( +
+ {state === SearchResultState.NOT_EXECUTED && ( + {t("search_result.search_not_executed")} + )} + + {state === SearchResultState.NO_RESULTS && ( + {t("search_result.no_notes_found")} + )} + +
+
+ ); +} \ No newline at end of file