import "./ListOrGridView.css"; import { useEffect, useRef, useState } from "preact/hooks"; import FNote from "../../../entities/fnote"; import attribute_renderer from "../../../services/attribute_renderer"; import content_renderer from "../../../services/content_renderer"; import { t } from "../../../services/i18n"; import link from "../../../services/link"; import tree from "../../../services/tree"; import { useImperativeSearchHighlighlighting, useNoteLabel, useNoteLabelBoolean } from "../../react/hooks"; import Icon from "../../react/Icon"; import NoteLink from "../../react/NoteLink"; import { ViewModeProps } from "../interface"; import { Pager, usePagination } from "../Pagination"; import { filterChildNotes, useFilteredNoteIds } from "./utils"; export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) { const expandDepth = useExpansionDepth(note); const noteIds = useFilteredNoteIds(note, unfilteredNoteIds); const { pageNotes, ...pagination } = usePagination(note, noteIds); const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived"); return (
{ noteIds.length > 0 &&
}
); } export function GridView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) { const noteIds = useFilteredNoteIds(note, unfilteredNoteIds); const { pageNotes, ...pagination } = usePagination(note, noteIds); return (
); } function ListNoteCard({ note, parentNote, highlightedTokens, currentLevel, expandDepth, includeArchived }: { note: FNote, parentNote: FNote, currentLevel: number, expandDepth: number, highlightedTokens: string[] | null | undefined; includeArchived: boolean; }) { const [ isExpanded, setExpanded ] = useState(currentLevel <= expandDepth); const notePath = getNotePath(parentNote, note); // Reset expand state if switching to another note, or if user manually toggled expansion state. useEffect(() => setExpanded(currentLevel <= expandDepth), [ note, currentLevel, expandDepth ]); return (
setExpanded(!isExpanded)} />
{isExpanded && <> }
); } function GridNoteCard({ note, parentNote, highlightedTokens }: { note: FNote, parentNote: FNote, highlightedTokens: string[] | null | undefined }) { const titleRef = useRef(null); const [ noteTitle, setNoteTitle ] = useState(); const notePath = getNotePath(parentNote, note); const highlightSearch = useImperativeSearchHighlighlighting(highlightedTokens); useEffect(() => { tree.getNoteTitle(note.noteId, parentNote.noteId).then(setNoteTitle); }, [ note ]); useEffect(() => highlightSearch(titleRef.current), [ noteTitle, highlightedTokens ]); return (
link.goToLink(e)} >
{noteTitle}
); } function NoteAttributes({ note }: { note: FNote }) { const ref = useRef(null); useEffect(() => { attribute_renderer.renderNormalAttributes(note).then(({$renderedAttributes}) => { ref.current?.replaceChildren(...$renderedAttributes); }); }, [ note ]); return ; } function NoteContent({ note, trim, noChildrenList, highlightedTokens }: { note: FNote, trim?: boolean, noChildrenList?: boolean, highlightedTokens: string[] | null | undefined }) { const contentRef = useRef(null); const highlightSearch = useImperativeSearchHighlighlighting(highlightedTokens); useEffect(() => { content_renderer.getRenderedContent(note, { trim, noChildrenList }) .then(({ $renderedContent, type }) => { if (!contentRef.current) return; if ($renderedContent[0].innerHTML) { contentRef.current.replaceChildren(...$renderedContent); } else { contentRef.current.replaceChildren(); } contentRef.current.classList.add(`type-${type}`); highlightSearch(contentRef.current); }) .catch(e => { console.warn(`Caught error while rendering note '${note.noteId}' of type '${note.type}'`); console.error(e); contentRef.current?.replaceChildren(t("collections.rendering_error")); }); }, [ note, highlightedTokens ]); return
; } function NoteChildren({ note, parentNote, highlightedTokens, currentLevel, expandDepth, includeArchived }: { note: FNote, parentNote: FNote, currentLevel: number, expandDepth: number, highlightedTokens: string[] | null | undefined includeArchived: boolean; }) { const [ childNotes, setChildNotes ] = useState(); useEffect(() => { filterChildNotes(note, includeArchived).then(setChildNotes); }, [ note, includeArchived ]); return childNotes?.map(childNote => ); } function getNotePath(parentNote: FNote, childNote: FNote) { if (parentNote.type === "search") { // for search note parent, we want to display a non-search path return childNote.noteId; } return `${parentNote.noteId}/${childNote.noteId}`; } function useExpansionDepth(note: FNote) { const [ expandDepth ] = useNoteLabel(note, "expanded"); if (expandDepth === null || expandDepth === undefined) { // not defined return 0; } else if (expandDepth === "") { // defined without value return 1; } else if (expandDepth === "all") { return Number.MAX_SAFE_INTEGER; } return parseInt(expandDepth, 10); }