import { useEffect, useMemo, useRef, useState } from "preact/hooks"; import FNote from "../../../entities/fnote"; import Icon from "../../react/Icon"; import { ViewModeProps } from "../interface"; import { useNoteLabelBoolean, useImperativeSearchHighlighlighting } from "../../react/hooks"; import NoteLink from "../../react/NoteLink"; import "./ListOrGridView.css"; import content_renderer from "../../../services/content_renderer"; import { Pager, usePagination } from "../Pagination"; import tree from "../../../services/tree"; import link from "../../../services/link"; import { t } from "../../../services/i18n"; import attribute_renderer from "../../../services/attribute_renderer"; export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps) { const [ isExpanded ] = useNoteLabelBoolean(note, "expanded"); const noteIds = useFilteredNoteIds(note, unfilteredNoteIds); const { pageNotes, ...pagination } = usePagination(note, noteIds); 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, expand, highlightedTokens }: { note: FNote, parentNote: FNote, expand?: boolean, highlightedTokens: string[] | null | undefined }) { const [ isExpanded, setExpanded ] = useState(expand); const notePath = getNotePath(parentNote, note); 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, highlightedTokens }: { note: FNote, trim?: boolean, highlightedTokens }) { const contentRef = useRef(null); const highlightSearch = useImperativeSearchHighlighlighting(highlightedTokens); useEffect(() => { content_renderer.getRenderedContent(note, { trim }) .then(({ $renderedContent, type }) => { if (!contentRef.current) return; contentRef.current.replaceChildren(...$renderedContent); 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 }: { note: FNote, parentNote: FNote, highlightedTokens: string[] | null | undefined }) { const imageLinks = note.getRelations("imageLink"); const [ childNotes, setChildNotes ] = useState(); useEffect(() => { note.getChildNotes().then(childNotes => { const filteredChildNotes = childNotes.filter((childNote) => !imageLinks.find((rel) => rel.value === childNote.noteId)); setChildNotes(filteredChildNotes); }); }, [ note ]); return childNotes?.map(childNote => ) } /** * Filters the note IDs for the legacy view to filter out subnotes that are already included in the note content such as images, included notes. */ function useFilteredNoteIds(note: FNote, noteIds: string[]) { return useMemo(() => { const includedLinks = note ? note.getRelations().filter((rel) => rel.name === "imageLink" || rel.name === "includeNoteLink") : []; const includedNoteIds = new Set(includedLinks.map((rel) => rel.value)); return noteIds.filter((noteId) => !includedNoteIds.has(noteId) && noteId !== "_hidden"); }, noteIds); } 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; } else { return `${parentNote.noteId}/${childNote.noteId}` } }