import { useEffect, useMemo, useRef, useState } from "preact/hooks"; import FNote from "../../../entities/fnote"; import Icon from "../../react/Icon"; import { ViewModeProps } from "../interface"; import { useNoteLabelBoolean, useNoteProperty } 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"; export function ListView({ note, noteIds: unfilteredNoteIds }: ViewModeProps) { const [ isExpanded ] = useNoteLabelBoolean(note, "expanded"); const noteIds = useFilteredNoteIds(note, unfilteredNoteIds); const { pageNotes, ...pagination } = usePagination(note, noteIds); return (
); } export function GridView({ note, noteIds: unfilteredNoteIds }: ViewModeProps) { const noteIds = useFilteredNoteIds(note, unfilteredNoteIds); const { pageNotes, ...pagination } = usePagination(note, noteIds); return (
); } function ListNoteCard({ note, parentNote, expand }: { note: FNote, parentNote: FNote, expand?: boolean }) { const [ isExpanded, setExpanded ] = useState(expand); const notePath = getNotePath(parentNote, note); return (
setExpanded(!isExpanded)} /> {isExpanded && <> }
) } function GridNoteCard({ note, parentNote }: { note: FNote, parentNote: FNote }) { const [ noteTitle, setNoteTitle ] = useState(); const notePath = getNotePath(parentNote, note); useEffect(() => { tree.getNoteTitle(note.noteId, parentNote.noteId).then(setNoteTitle); }, [ note ]); return (
link.goToLink(e)} >
{noteTitle}
) } function NoteContent({ note, trim }: { note: FNote, trim?: boolean }) { const contentRef = useRef(null); useEffect(() => { content_renderer.getRenderedContent(note, { trim }) .then(({ $renderedContent, type }) => { contentRef.current?.replaceChildren(...$renderedContent); contentRef.current?.classList.add(`type-${type}`); }) .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 ]); return
; } function NoteChildren({ note, parentNote }: { note: FNote, parentNote: FNote }) { 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}` } }