mirror of
https://github.com/zadam/trilium.git
synced 2025-10-21 07:38:53 +02:00
chore(react/collections): content highlighting in list
This commit is contained in:
parent
68dff71512
commit
1cee01a22a
@ -2,7 +2,7 @@ import { useEffect, useMemo, useRef, useState } from "preact/hooks";
|
|||||||
import FNote from "../../../entities/fnote";
|
import FNote from "../../../entities/fnote";
|
||||||
import Icon from "../../react/Icon";
|
import Icon from "../../react/Icon";
|
||||||
import { ViewModeProps } from "../interface";
|
import { ViewModeProps } from "../interface";
|
||||||
import { useNoteLabelBoolean, useNoteProperty } from "../../react/hooks";
|
import { useNoteLabelBoolean, useImperativeSearchHighlighlighting } from "../../react/hooks";
|
||||||
import NoteLink from "../../react/NoteLink";
|
import NoteLink from "../../react/NoteLink";
|
||||||
import "./ListOrGridView.css";
|
import "./ListOrGridView.css";
|
||||||
import content_renderer from "../../../services/content_renderer";
|
import content_renderer from "../../../services/content_renderer";
|
||||||
@ -75,8 +75,8 @@ function ListNoteCard({ note, parentNote, expand, highlightedTokens }: { note: F
|
|||||||
<NoteAttributes note={note} />
|
<NoteAttributes note={note} />
|
||||||
|
|
||||||
{isExpanded && <>
|
{isExpanded && <>
|
||||||
<NoteContent note={note} />
|
<NoteContent note={note} highlightedTokens={highlightedTokens} />
|
||||||
<NoteChildren note={note} parentNote={parentNote} />
|
<NoteChildren note={note} parentNote={parentNote} highlightedTokens={highlightedTokens} />
|
||||||
</>}
|
</>}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
@ -104,7 +104,7 @@ function GridNoteCard({ note, parentNote, highlightedTokens }: { note: FNote, pa
|
|||||||
<span ref={titleRef} className="note-book-title">{noteTitle}</span>
|
<span ref={titleRef} className="note-book-title">{noteTitle}</span>
|
||||||
<NoteAttributes note={note} />
|
<NoteAttributes note={note} />
|
||||||
</h5>
|
</h5>
|
||||||
<NoteContent note={note} trim />
|
<NoteContent note={note} trim highlightedTokens={highlightedTokens} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -120,26 +120,29 @@ function NoteAttributes({ note }: { note: FNote }) {
|
|||||||
return <span className="note-list-attributes" ref={ref} />
|
return <span className="note-list-attributes" ref={ref} />
|
||||||
}
|
}
|
||||||
|
|
||||||
function NoteContent({ note, trim }: { note: FNote, trim?: boolean }) {
|
function NoteContent({ note, trim, highlightedTokens }: { note: FNote, trim?: boolean, highlightedTokens }) {
|
||||||
const contentRef = useRef<HTMLDivElement>(null);
|
const contentRef = useRef<HTMLDivElement>(null);
|
||||||
|
const highlightSearch = useImperativeSearchHighlighlighting(highlightedTokens);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
content_renderer.getRenderedContent(note, { trim })
|
content_renderer.getRenderedContent(note, { trim })
|
||||||
.then(({ $renderedContent, type }) => {
|
.then(({ $renderedContent, type }) => {
|
||||||
contentRef.current?.replaceChildren(...$renderedContent);
|
if (!contentRef.current) return;
|
||||||
contentRef.current?.classList.add(`type-${type}`);
|
contentRef.current.replaceChildren(...$renderedContent);
|
||||||
|
contentRef.current.classList.add(`type-${type}`);
|
||||||
|
highlightSearch(contentRef.current);
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
console.warn(`Caught error while rendering note '${note.noteId}' of type '${note.type}'`);
|
console.warn(`Caught error while rendering note '${note.noteId}' of type '${note.type}'`);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
contentRef.current?.replaceChildren(t("collections.rendering_error"));
|
contentRef.current?.replaceChildren(t("collections.rendering_error"));
|
||||||
})
|
})
|
||||||
}, [ note ]);
|
}, [ note, highlightedTokens ]);
|
||||||
|
|
||||||
return <div ref={contentRef} className="note-book-content" />;
|
return <div ref={contentRef} className="note-book-content" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function NoteChildren({ note, parentNote }: { note: FNote, parentNote: FNote }) {
|
function NoteChildren({ note, parentNote, highlightedTokens }: { note: FNote, parentNote: FNote, highlightedTokens: string[] | null | undefined }) {
|
||||||
const imageLinks = note.getRelations("imageLink");
|
const imageLinks = note.getRelations("imageLink");
|
||||||
const [ childNotes, setChildNotes ] = useState<FNote[]>();
|
const [ childNotes, setChildNotes ] = useState<FNote[]>();
|
||||||
|
|
||||||
@ -150,7 +153,7 @@ function NoteChildren({ note, parentNote }: { note: FNote, parentNote: FNote })
|
|||||||
});
|
});
|
||||||
}, [ note ]);
|
}, [ note ]);
|
||||||
|
|
||||||
return childNotes?.map(childNote => <ListNoteCard note={childNote} parentNote={parentNote} highlightedTokens={null} />)
|
return childNotes?.map(childNote => <ListNoteCard note={childNote} parentNote={parentNote} highlightedTokens={highlightedTokens} />)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { useEffect, useRef, useState } from "preact/hooks";
|
import { useEffect, useRef, useState } from "preact/hooks";
|
||||||
import link from "../../services/link";
|
import link from "../../services/link";
|
||||||
import RawHtml from "./RawHtml";
|
import { useImperativeSearchHighlighlighting } from "./hooks";
|
||||||
import { useSearchHighlighlighting } from "./hooks";
|
|
||||||
|
|
||||||
interface NoteLinkOpts {
|
interface NoteLinkOpts {
|
||||||
className?: string;
|
className?: string;
|
||||||
@ -16,15 +15,21 @@ interface NoteLinkOpts {
|
|||||||
|
|
||||||
export default function NoteLink({ className, notePath, showNotePath, showNoteIcon, style, noPreview, noTnLink, highlightedTokens }: NoteLinkOpts) {
|
export default function NoteLink({ className, notePath, showNotePath, showNoteIcon, style, noPreview, noTnLink, highlightedTokens }: NoteLinkOpts) {
|
||||||
const stringifiedNotePath = Array.isArray(notePath) ? notePath.join("/") : notePath;
|
const stringifiedNotePath = Array.isArray(notePath) ? notePath.join("/") : notePath;
|
||||||
|
const ref = useRef<HTMLSpanElement>(null);
|
||||||
const [ jqueryEl, setJqueryEl ] = useState<JQuery<HTMLElement>>();
|
const [ jqueryEl, setJqueryEl ] = useState<JQuery<HTMLElement>>();
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const highlightSearch = useImperativeSearchHighlighlighting(highlightedTokens);
|
||||||
useSearchHighlighlighting(containerRef, highlightedTokens);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
link.createLink(stringifiedNotePath, { showNotePath, showNoteIcon })
|
link.createLink(stringifiedNotePath, { showNotePath, showNoteIcon })
|
||||||
.then(setJqueryEl);
|
.then(setJqueryEl);
|
||||||
}, [ stringifiedNotePath, showNotePath ]);
|
}, [ stringifiedNotePath, showNotePath ]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ref.current || !jqueryEl) return;
|
||||||
|
ref.current.replaceChildren(jqueryEl[0]);
|
||||||
|
highlightSearch(ref.current);
|
||||||
|
}, [ jqueryEl ]);
|
||||||
|
|
||||||
if (style) {
|
if (style) {
|
||||||
jqueryEl?.css(style);
|
jqueryEl?.css(style);
|
||||||
}
|
}
|
||||||
@ -42,6 +47,6 @@ export default function NoteLink({ className, notePath, showNotePath, showNoteIc
|
|||||||
$linkEl?.addClass(className);
|
$linkEl?.addClass(className);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <RawHtml containerRef={containerRef} html={jqueryEl} />
|
return <span ref={ref} />
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -550,7 +550,7 @@ export function useSyncedRef<T>(externalRef?: RefObject<T>, initialValue: T | nu
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useSearchHighlighlighting(ref: RefObject<HTMLElement>, highlightedTokens: string[] | null | undefined) {
|
export function useImperativeSearchHighlighlighting(highlightedTokens: string[] | null | undefined) {
|
||||||
const mark = useRef<Mark>();
|
const mark = useRef<Mark>();
|
||||||
const highlightRegex = useMemo(() => {
|
const highlightRegex = useMemo(() => {
|
||||||
if (!highlightedTokens?.length) return null;
|
if (!highlightedTokens?.length) return null;
|
||||||
@ -558,18 +558,17 @@ export function useSearchHighlighlighting(ref: RefObject<HTMLElement>, highlight
|
|||||||
return new RegExp(regex, "gi")
|
return new RegExp(regex, "gi")
|
||||||
}, [ highlightedTokens ]);
|
}, [ highlightedTokens ]);
|
||||||
|
|
||||||
useEffect(() => {
|
return (el: HTMLElement) => {
|
||||||
if (!ref.current || !highlightRegex) return;
|
if (!el || !highlightRegex) return;
|
||||||
|
|
||||||
if (!mark.current) {
|
if (!mark.current) {
|
||||||
mark.current = new Mark(ref.current);
|
mark.current = new Mark(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mark.current.unmark();
|
||||||
mark.current.markRegExp(highlightRegex, {
|
mark.current.markRegExp(highlightRegex, {
|
||||||
element: "span",
|
element: "span",
|
||||||
className: "ck-find-result"
|
className: "ck-find-result"
|
||||||
});
|
});
|
||||||
|
};
|
||||||
return () => mark.current?.unmark();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user