Spaces:
Running
Running
| <script lang="ts" generics="TData"> | |
| import type { Table } from '@tanstack/table-core'; | |
| import { Button } from '$lib/components/ui/button'; | |
| import * as Select from '$lib/components/ui/select'; | |
| import CaretLeftIcon from 'phosphor-svelte/lib/CaretLeftIcon'; | |
| import CaretRightIcon from 'phosphor-svelte/lib/CaretRightIcon'; | |
| import CaretDoubleLeftIcon from 'phosphor-svelte/lib/CaretDoubleLeftIcon'; | |
| import CaretDoubleRightIcon from 'phosphor-svelte/lib/CaretDoubleRightIcon'; | |
| interface Props { | |
| table: Table<TData>; | |
| pageSizes?: number[]; | |
| } | |
| let { table, pageSizes = [10, 25, 50, 100] }: Props = $props(); | |
| const pageIndex = $derived(table.getState().pagination.pageIndex); | |
| const pageSize = $derived(table.getState().pagination.pageSize); | |
| const pageCount = $derived(table.getPageCount()); | |
| const totalRows = $derived(table.getFilteredRowModel().rows.length); | |
| </script> | |
| <div class="flex flex-wrap items-center justify-between gap-3 pt-3 text-xs"> | |
| <div class="text-muted-foreground"> | |
| {totalRows.toLocaleString()} row{totalRows === 1 ? '' : 's'} | |
| </div> | |
| <div class="flex flex-wrap items-center gap-4"> | |
| <div class="flex items-center gap-2"> | |
| <span class="text-muted-foreground">Rows per page</span> | |
| <Select.Root | |
| type="single" | |
| value={String(pageSize)} | |
| onValueChange={(v) => table.setPageSize(Number(v))} | |
| > | |
| <Select.Trigger size="sm" class="h-7 w-[70px]"> | |
| {pageSize} | |
| </Select.Trigger> | |
| <Select.Content> | |
| {#each pageSizes as n (n)} | |
| <Select.Item value={String(n)}>{n}</Select.Item> | |
| {/each} | |
| </Select.Content> | |
| </Select.Root> | |
| </div> | |
| <div class="text-muted-foreground tabular-nums"> | |
| Page {pageIndex + 1} of {Math.max(1, pageCount)} | |
| </div> | |
| <div class="flex items-center gap-1"> | |
| <Button | |
| variant="outline" | |
| size="icon-sm" | |
| class="size-7" | |
| onclick={() => table.setPageIndex(0)} | |
| disabled={!table.getCanPreviousPage()} | |
| aria-label="First page" | |
| > | |
| <CaretDoubleLeftIcon size={12} weight="bold" /> | |
| </Button> | |
| <Button | |
| variant="outline" | |
| size="icon-sm" | |
| class="size-7" | |
| onclick={() => table.previousPage()} | |
| disabled={!table.getCanPreviousPage()} | |
| aria-label="Previous page" | |
| > | |
| <CaretLeftIcon size={12} weight="bold" /> | |
| </Button> | |
| <Button | |
| variant="outline" | |
| size="icon-sm" | |
| class="size-7" | |
| onclick={() => table.nextPage()} | |
| disabled={!table.getCanNextPage()} | |
| aria-label="Next page" | |
| > | |
| <CaretRightIcon size={12} weight="bold" /> | |
| </Button> | |
| <Button | |
| variant="outline" | |
| size="icon-sm" | |
| class="size-7" | |
| onclick={() => table.setPageIndex(pageCount - 1)} | |
| disabled={!table.getCanNextPage()} | |
| aria-label="Last page" | |
| > | |
| <CaretDoubleRightIcon size={12} weight="bold" /> | |
| </Button> | |
| </div> | |
| </div> | |
| </div> | |