mirror of
https://github.com/zadam/trilium.git
synced 2025-11-11 15:55:52 +01:00
feat(react/widgets): port search result
This commit is contained in:
@@ -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(<SearchResult />)
|
||||
.child(new SqlResultWidget())
|
||||
.child(<ScrollPadding />)
|
||||
)
|
||||
|
||||
@@ -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 (
|
||||
<div className={`alert alert-${type}`}>
|
||||
<div className={`alert alert-${type} ${className ?? ""}`}>
|
||||
{title && <h4>{title}</h4>}
|
||||
|
||||
{children}
|
||||
|
||||
16
apps/client/src/widgets/search_result.css
Normal file
16
apps/client/src/widgets/search_result.css
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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*/`
|
||||
<div class="search-result-widget">
|
||||
<style>
|
||||
.search-result-widget {
|
||||
flex-grow: 100000;
|
||||
flex-shrink: 100000;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.search-result-widget .note-list {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.search-no-results, .search-not-executed-yet {
|
||||
margin: 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="search-no-results alert alert-info">
|
||||
${t("search_result.no_notes_found")}
|
||||
</div>
|
||||
|
||||
<div class="search-not-executed-yet alert alert-info">
|
||||
${t("search_result.search_not_executed")}
|
||||
</div>
|
||||
|
||||
<div class="search-result-widget-content">
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
export default class SearchResultWidget extends NoteContextAwareWidget {
|
||||
|
||||
private $content!: JQuery<HTMLElement>;
|
||||
private $noResults!: JQuery<HTMLElement>;
|
||||
private $notExecutedYet!: JQuery<HTMLElement>;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
63
apps/client/src/widgets/search_result.tsx
Normal file
63
apps/client/src/widgets/search_result.tsx
Normal file
@@ -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<SearchResultState>();
|
||||
const searchContainerRef = useRef<HTMLDivElement>(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 (
|
||||
<div className="search-result-widget">
|
||||
{state === SearchResultState.NOT_EXECUTED && (
|
||||
<Alert type="info" className="search-not-executed-yet">{t("search_result.search_not_executed")}</Alert>
|
||||
)}
|
||||
|
||||
{state === SearchResultState.NO_RESULTS && (
|
||||
<Alert type="info" className="search-no-results">{t("search_result.no_notes_found")}</Alert>
|
||||
)}
|
||||
|
||||
<div ref={searchContainerRef} className="search-results" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user