import { allViewTypes, ViewModeProps, ViewTypeOptions } from "./interface"; import { useNoteContext, useNoteLabel, useTriliumEvent } from "../react/hooks"; import FNote from "../../entities/fnote"; import "./NoteList.css"; import { ListView, GridView } from "./legacy/ListOrGridView"; import { useEffect, useRef, useState } from "preact/hooks"; interface NoteListProps { note?: FNote | null; displayOnlyCollections?: boolean; highlightedTokens?: string[] | null; } export default function NoteList({ note: providedNote, highlightedTokens }: NoteListProps) { const widgetRef = useRef(null); const { note: contextNote } = useNoteContext(); const note = providedNote ?? contextNote; const viewType = useNoteViewType(note); const noteIds = useNoteIds(note, viewType); const isFullHeight = (viewType !== "list" && viewType !== "grid"); const [ isIntersecting, setIsIntersecting ] = useState(false); const shouldRender = (isFullHeight || isIntersecting); const isEnabled = (note && !!viewType && shouldRender); useEffect(() => { const observer = new IntersectionObserver( (entries) => { if (!isIntersecting) { setIsIntersecting(entries[0].isIntersecting); } observer.disconnect(); }, { rootMargin: "50px", threshold: 0.1 } ); // there seems to be a race condition on Firefox which triggers the observer only before the widget is visible // (intersection is false). https://github.com/zadam/trilium/issues/4165 setTimeout(() => widgetRef.current && observer.observe(widgetRef.current), 10); return () => observer.disconnect(); }, []); return (
{isEnabled && (
{getComponentByViewType(note, noteIds, viewType, highlightedTokens)}
)}
); } function getComponentByViewType(note: FNote, noteIds: string[], viewType: ViewTypeOptions, highlightedTokens: string[] | null | undefined) { const props: ViewModeProps = { note, noteIds, highlightedTokens }; switch (viewType) { case "list": return ; case "grid": return ; } } function useNoteViewType(note?: FNote | null): ViewTypeOptions | undefined { const [ viewType ] = useNoteLabel(note, "viewType"); if (!note) { return undefined; } else if (!(allViewTypes as readonly string[]).includes(viewType || "")) { // when not explicitly set, decide based on the note type return note.type === "search" ? "list" : "grid"; } else { return viewType as ViewTypeOptions; } } function useNoteIds(note: FNote | null | undefined, viewType: ViewTypeOptions | undefined) { const [ noteIds, setNoteIds ] = useState([]); async function refreshNoteIds() { if (!note) { setNoteIds([]); } else if (viewType === "list" || viewType === "grid") { console.log("Refreshed note IDs"); setNoteIds(note.getChildNoteIds()); } else { console.log("Refreshed note IDs"); setNoteIds(await note.getSubtreeNoteIds()); } } // Refresh on note switch. useEffect(() => { refreshNoteIds() }, [ note ]); // Refresh on alterations to the note subtree. useTriliumEvent("entitiesReloaded", ({ loadResults }) => { if (note && loadResults.getBranchRows().some(branch => branch.parentNoteId === note.noteId || noteIds.includes(branch.parentNoteId ?? ""))) { refreshNoteIds(); } }) return noteIds; }