import { merge } from "../core/utils/object.ts"; import type Site from "../core/site.ts"; /** The options for the paginate helper */ export interface PaginateOptions { /** The number of elements per page */ size?: number; /** The function to generate the url of the pages */ url?: (page: number) => string; /** Function to modify or add extra data to each page */ each?: (data: PaginateResult, page: number) => void; } export type Paginator = ( results: T[], userOptions?: Partial, ) => PaginateResult[]; /** Pagination info */ export interface PaginationInfo { /** The current page number */ page: number; /** The total number of pages */ totalPages: number; /** The total number of elements */ totalResults: number; /** The url of the first page */ first: string; /** The url of the last page */ last: string; /** The url of the previous page */ previous: string | null; /** The url of the next page */ next: string | null; } /** The paginate result */ export interface PaginateResult { /** The page url */ url: string; /** The elements in this page */ results: T[]; /** The pagination info */ pagination: PaginationInfo; [key: string]: unknown; } export interface Options { /** The default pagination options */ options?: PaginateOptions; } export const defaults: Options = { options: { size: 10, }, }; /** * A plugin to paginate pages * Installed by default * @see https://lume.land/plugins/paginate/ */ export function paginate(userOptions?: Options) { const options = merge(defaults, userOptions); return (site: Site) => { if (!userOptions?.options?.url) { const ext = site.options.prettyUrls ? "/index.html" : ".html"; options.options.url = (page: number) => `./page-${page}${ext}`; } // Register the helper site.data("paginate", createPaginator(options.options)); }; } /** Create a paginator function */ export function createPaginator(defaults: PaginateOptions): Paginator { return function paginate( results: T[], userOptions: Partial = {}, ) { const options = merge(defaults, userOptions); const totalResults = results.length; const totalPages = Math.ceil(results.length / options.size); const result: PaginateResult[] = []; let page = 0; while (++page <= totalPages) { const data = createPageData(page); const from = (page - 1) * options.size; const to = from + options.size; data.results = results.slice(from, to); if (options.each) { options.each(data, page); } result.push(data); } return result; function createPageData(page: number): PaginateResult { return { url: options.url(page), results: [], pagination: { page, totalPages, totalResults, first: options.url(1), last: options.url(totalPages), previous: page > 1 ? options.url(page - 1) : null, next: totalPages > page ? options.url(page + 1) : null, }, }; } }; } export default paginate; /** Extends Data interface */ declare global { namespace Lume { export type { PaginateResult }; export interface Data { /** * The paginator helper * @see https://lume.land/plugins/paginate/ */ paginate: Paginator; /** * The pagination info * @see https://lume.land/plugins/paginate/ */ pagination?: PaginationInfo; /** * The pagination result * @see https://lume.land/plugins/paginate/ */ results?: Data[]; } } }