import { Dispatch, StateUpdater, useEffect, useMemo, useRef, useState } from "preact/hooks"; import FNote from "../../../entities/fnote"; import Icon from "../../react/Icon"; import { ViewModeProps } from "../interface"; import { useNoteLabel, useNoteLabelBoolean, useNoteProperty } from "../../react/hooks"; import froca from "../../../services/froca"; import NoteLink from "../../react/NoteLink"; import "./ListOrGridView.css"; import content_renderer from "../../../services/content_renderer"; import { ComponentChildren, VNode } from "preact"; export default function ListView({ note, noteIds }: ViewModeProps) { const [ isExpanded ] = useNoteLabelBoolean(note, "expanded"); const filteredNoteIds = useMemo(() => { // 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. 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); const { pageNotes, ...pagination } = usePagination(note, filteredNoteIds); return (
); } function NoteCard({ note, expand }: { note: FNote, expand?: boolean }) { const [ isExpanded, setExpanded ] = useState(expand); const isSearch = note.type === "search"; const notePath = isSearch ? note.noteId // for search note parent, we want to display a non-search path : `${note.noteId}/${note.noteId}`; return (
setExpanded(!isExpanded)} /> {isExpanded && <> }
) } 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("rendering error"); }) }, [ note ]); return
; } function NoteChildren({ note }: { note: 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 => ) } function Pager({ page, pageSize, setPage, pageCount, totalNotes }: Omit) { if (pageCount < 1) return; let lastPrinted = false; let children: ComponentChildren[] = []; for (let i = 1; i <= pageCount; i++) { if (pageCount < 20 || i <= 5 || pageCount - i <= 5 || Math.abs(page - i) <= 2) { lastPrinted = true; const startIndex = (i - 1) * pageSize + 1; const endIndex = Math.min(totalNotes, i * pageSize); if (i !== page) { children.push(( setPage(i)} > {i} )) } else { // Current page children.push({i}) } children.push(<>{" "} {" "}); } else if (lastPrinted) { children.push(<>{"... "} {" "}); lastPrinted = false; } } return (
{children}
) } interface PaginationContext { page: number; setPage: Dispatch>; pageNotes?: FNote[]; pageCount: number; pageSize: number; totalNotes: number; } function usePagination(note: FNote, noteIds: string[]): PaginationContext { const [ page, setPage ] = useState(1); const [ pageNotes, setPageNotes ] = useState(); // Parse page size. const [ pageSize ] = useNoteLabel(note, "pageSize"); const pageSizeNum = parseInt(pageSize ?? "", 10); const normalizedPageSize = (pageSizeNum && pageSizeNum > 0 ? pageSizeNum : 20); // Calculate start/end index. const startIdx = (page - 1) * normalizedPageSize; const endIdx = startIdx + normalizedPageSize; const pageCount = Math.ceil(noteIds.length / normalizedPageSize); // Obtain notes within the range. const pageNoteIds = noteIds.slice(startIdx, Math.min(endIdx, noteIds.length)); useEffect(() => { froca.getNotes(pageNoteIds).then(setPageNotes); }, [ note, noteIds, page, pageSize ]); return { page, setPage, pageNotes, pageCount, pageSize: normalizedPageSize, totalNotes: noteIds.length }; }