diff --git a/apps/client/src/widgets/collections/NoteList.css b/apps/client/src/widgets/collections/NoteList.css index 612d088f4..08fab236c 100644 --- a/apps/client/src/widgets/collections/NoteList.css +++ b/apps/client/src/widgets/collections/NoteList.css @@ -15,4 +15,11 @@ .note-list-widget video { height: 100%; -} \ No newline at end of file +} + +/* #region Pagination */ +.note-list-pager span.current-page { + text-decoration: underline; + font-weight: bold; +} +/* #endregion */ \ No newline at end of file diff --git a/apps/client/src/widgets/collections/legacy/ListView.tsx b/apps/client/src/widgets/collections/legacy/ListView.tsx index f28f8c2bb..7c061921b 100644 --- a/apps/client/src/widgets/collections/legacy/ListView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListView.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useRef, useState } from "preact/hooks"; +import { Dispatch, StateUpdater, useEffect, useMemo, useRef, useState } from "preact/hooks"; import FNote from "../../../entities/fnote"; import Icon from "../../react/Icon"; import { ViewModeProps } from "../interface"; @@ -7,6 +7,7 @@ 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"); @@ -16,12 +17,12 @@ export default function ListView({ note, noteIds }: ViewModeProps) { const includedNoteIds = new Set(includedLinks.map((rel) => rel.value)); return noteIds.filter((noteId) => !includedNoteIds.has(noteId) && noteId !== "_hidden"); }, noteIds); - const { pageNotes } = usePagination(note, filteredNoteIds); + const { pageNotes, ...pagination } = usePagination(note, filteredNoteIds); return (
-
+ -
+
); @@ -97,9 +98,59 @@ function NoteChildren({ note }: { note: FNote}) { return childNotes?.map(childNote => ) } -function usePagination(note: FNote, noteIds: string[]) { +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(); + const [ pageNotes, setPageNotes ] = useState(); // Parse page size. const [ pageSize ] = useNoteLabel(note, "pageSize"); @@ -109,17 +160,18 @@ function usePagination(note: FNote, noteIds: string[]) { // 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)); + const pageNoteIds = noteIds.slice(startIdx, Math.min(endIdx, noteIds.length)); useEffect(() => { froca.getNotes(pageNoteIds).then(setPageNotes); }, [ note, noteIds, page, pageSize ]); return { - page, - setPage, - pageNotes - } + page, setPage, pageNotes, pageCount, + pageSize: normalizedPageSize, + totalNotes: noteIds.length + }; } \ No newline at end of file diff --git a/apps/client/src/widgets/view_widgets/list_or_grid_view.ts b/apps/client/src/widgets/view_widgets/list_or_grid_view.ts index b028fbe42..857f1c6f0 100644 --- a/apps/client/src/widgets/view_widgets/list_or_grid_view.ts +++ b/apps/client/src/widgets/view_widgets/list_or_grid_view.ts @@ -45,42 +45,8 @@ class ListOrGridView extends ViewMode<{}> { } renderPager() { - const $pager = this.$noteList.find(".note-list-pager").empty(); - if (!this.page || !this.pageSize) { - return; - } - const pageCount = Math.ceil(this.filteredNoteIds.length / this.pageSize); - $pager.toggle(pageCount > 1); - - let lastPrinted; - - for (let i = 1; i <= pageCount; i++) { - if (pageCount < 20 || i <= 5 || pageCount - i <= 5 || Math.abs(this.page - i) <= 2) { - lastPrinted = true; - - const startIndex = (i - 1) * this.pageSize + 1; - const endIndex = Math.min(this.filteredNoteIds.length, i * this.pageSize); - - $pager.append( - i === this.page - ? $("").text(i).css("text-decoration", "underline").css("font-weight", "bold") - : $('') - .text(i) - .attr("title", `Page of ${startIndex} - ${endIndex}`) - .on("click", () => { - this.page = i; - this.renderList(); - }), - "   " - ); - } else if (lastPrinted) { - $pager.append("...   "); - - lastPrinted = false; - } - } // no need to distinguish "note" vs "notes" since in case of one result, there's no paging at all $pager.append(`(${this.filteredNoteIds.length} notes)`);