Skip to main content
Glama
PaginationControls.tsx5.7 kB
import { ChevronLeftIcon, ChevronRightIcon, DoubleArrowLeftIcon, } from "@radix-ui/react-icons"; import { Button } from "@ui/Button"; import { Combobox, Option } from "@ui/Combobox"; import { cn } from "@ui/cn"; interface OffsetPaginationControlsProps { currentPage: number; totalPages: number; onPageChange: (page: number) => void; className?: string; pageSize?: never; onPageSizeChange?: never; } interface CursorPaginationControlsProps { currentPage: number; hasMore: boolean; pageSize: number; onPageSizeChange: (pageSize: number) => void; onPreviousPage: () => void; onNextPage: () => void; canGoPrevious: boolean; className?: string; showPageSize?: boolean; } interface CursorPaginationControlsPropsWithDiscriminator extends CursorPaginationControlsProps { isCursorBasedPagination: true; } type PaginationControlsProps = | OffsetPaginationControlsProps | CursorPaginationControlsPropsWithDiscriminator; const PAGE_SIZE_OPTIONS: Option<number>[] = [ { label: "5", value: 5 }, { label: "10", value: 10 }, { label: "25", value: 25 }, { label: "50", value: 50 }, { label: "100", value: 100 }, ]; export function PaginationControls(props: PaginationControlsProps) { const { isCursorBasedPagination } = props as { isCursorBasedPagination?: boolean; }; if (isCursorBasedPagination) { const { currentPage, hasMore, pageSize, onPageSizeChange, onPreviousPage, onNextPage, canGoPrevious, className, showPageSize, } = props as CursorPaginationControlsPropsWithDiscriminator; return ( <CursorPaginationControls currentPage={currentPage} hasMore={hasMore} pageSize={pageSize} onPageSizeChange={onPageSizeChange} onPreviousPage={onPreviousPage} onNextPage={onNextPage} canGoPrevious={canGoPrevious} className={className} showPageSize={showPageSize} /> ); } const offsetProps = props as OffsetPaginationControlsProps; const { currentPage, totalPages, onPageChange, className } = offsetProps; return ( <OffsetPaginationControls currentPage={currentPage} totalPages={totalPages} onPageChange={onPageChange} className={className} /> ); } function OffsetPaginationControls({ currentPage, totalPages, onPageChange, className = "", }: OffsetPaginationControlsProps) { if (totalPages <= 1) { return null; } return ( <div className={cn("flex items-center justify-center gap-2", className)}> {/* First page button */} <Button variant="neutral" inline size="sm" icon={<DoubleArrowLeftIcon />} onClick={() => onPageChange(1)} disabled={currentPage === 1} aria-label="Go to first page" /> {/* Previous page button */} <Button variant="neutral" inline size="sm" icon={<ChevronLeftIcon />} onClick={() => onPageChange(Math.max(1, currentPage - 1))} disabled={currentPage === 1} aria-label="Go to previous page" /> {/* Page indicator */} <span className="text-sm text-content-secondary tabular-nums"> Page {currentPage} of {totalPages} </span> {/* Next page button */} <Button variant="neutral" inline size="sm" icon={<ChevronRightIcon />} onClick={() => onPageChange(Math.min(totalPages, currentPage + 1))} disabled={currentPage === totalPages} aria-label="Go to next page" /> {/* Last page button */} <Button variant="neutral" inline size="sm" icon={<ChevronRightIcon />} onClick={() => onPageChange(totalPages)} disabled={currentPage === totalPages} aria-label="Go to last page" /> </div> ); } function CursorPaginationControls({ currentPage, hasMore, pageSize, onPageSizeChange, onPreviousPage, onNextPage, canGoPrevious, className = "", showPageSize = true, }: CursorPaginationControlsProps) { return ( <div className={cn("flex items-center justify-center gap-2", className)}> {/* Page size selector - only show if showPageSize is true */} {showPageSize && ( <div className="flex items-center gap-1"> <span className="text-sm text-content-secondary tabular-nums"> Showing{" "} </span> <Combobox label="Page size" labelHidden options={PAGE_SIZE_OPTIONS} selectedOption={pageSize} setSelectedOption={(newValue) => { if (newValue) { onPageSizeChange(newValue); } }} disableSearch buttonClasses="w-fit" optionsWidth="fit" /> <span className="text-sm text-content-secondary tabular-nums"> projects per page </span> </div> )} {/* Previous page button */} <Button variant="neutral" inline size="sm" icon={<ChevronLeftIcon />} onClick={onPreviousPage} disabled={!canGoPrevious} aria-label="Go to previous page" /> {/* Page indicator */} <span className="text-sm text-content-secondary tabular-nums"> Page {currentPage.toLocaleString()} </span> {/* Next page button */} <Button variant="neutral" inline size="sm" icon={<ChevronRightIcon />} onClick={onNextPage} disabled={!hasMore} aria-label="Go to next page" /> </div> ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server