Created
April 20, 2024 08:23
-
-
Save svex99/8f194d51702a75e73af397bdc4d2e92b to your computer and use it in GitHub Desktop.
Svelte data-table with generics and back-end pagination (shadcn-svelte)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script context="module" lang="ts"> | |
export type Column<T> = { | |
accessor: keyof T; | |
header: string; | |
format?(item: T): string; | |
cell?: (item: T) => any; | |
}; | |
</script> | |
<script lang="ts" generics="T extends { id: string }"> | |
import { page } from '$app/stores'; | |
import { Render } from 'svelte-render'; | |
import * as Table from '$lib/components/ui/table'; | |
import { Button } from '$lib/components/ui/button'; | |
import { getOffsetPaginationQueryParams } from '$lib/utils/pagination'; | |
export let columns: Column<T>[] = []; | |
export let data: T[] = []; // Data will contain one item more than page size to indicate that there are more items. | |
export let caption: string = ''; | |
$: pagination = getOffsetPaginationQueryParams($page.url); | |
$: tableData = data.length > pagination.size ? data.slice(0, data.length - 1) : data; | |
</script> | |
<div> | |
<Table.Root> | |
{#if caption} | |
<Table.Caption>{caption}</Table.Caption> | |
{/if} | |
<Table.Header> | |
<Table.Row> | |
{#each columns as column} | |
<Table.Head>{column.header}</Table.Head> | |
{/each} | |
</Table.Row> | |
</Table.Header> | |
{#if tableData.length} | |
<Table.Body> | |
{#each tableData as item (item.id)} | |
<Table.Row> | |
{#each columns as column} | |
<Table.Cell> | |
{#if column.cell} | |
<Render of={column.cell(item)} /> | |
{:else if column.format} | |
{column.format(item)} | |
{:else} | |
{item[column.accessor]} | |
{/if} | |
</Table.Cell> | |
{/each} | |
</Table.Row> | |
{/each} | |
</Table.Body> | |
{:else} | |
<td colspan={columns.length} class="py-5 text-center text-muted-foreground"> | |
There is no data to display. | |
</td> | |
{/if} | |
</Table.Root> | |
{#if tableData.length} | |
<div> | |
<p class="text-xs text-muted-foreground">Showing {tableData.length} item(s)</p> | |
<div class="w-full flex items-center justify-center space-x-8"> | |
<Button | |
variant="outline" | |
size="sm" | |
class="w-[6rem] {pagination.page > 1 ? 'visible' : 'invisible'}" | |
href="{$page.url.pathname}?page={pagination.page - 1}&size={pagination.size}" | |
> | |
Previous | |
</Button> | |
<p class="text-muted-foreground text-sm">{pagination.page}</p> | |
<Button | |
variant="outline" | |
size="sm" | |
class="w-[6rem] {data.length > pagination.size ? 'visible' : 'invisible'}" | |
href="{$page.url.pathname}?page={pagination.page + 1}&size={pagination.size}" | |
> | |
Next | |
</Button> | |
</div> | |
</div> | |
{/if} | |
</div> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment