Created
March 26, 2024 21:22
-
-
Save kkharji/eeba896ac87e1bf34de5b6dabd6eaa4b to your computer and use it in GitHub Desktop.
This file contains hidden or 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
import { createSolidTable, flexRender, getCoreRowModel, getPaginationRowModel } from "@tanstack/solid-table"; | |
import type { HeaderGroup, Row, RowData, TableOptions, Table as TanTable } from "@tanstack/solid-table"; | |
import { createMemo, For, Match, type Resource, Show, splitProps, Switch } from "solid-js"; | |
import Paging from "./table/paging"; | |
import ArchiveBox from "~/assets/archiveBox.svg"; | |
import lists from "~/lib/lists"; | |
export type TableProps<T = any> = Omit<TableOptions<T>, "data" | "getCoreRowModel"> & { | |
data: Resource<T[]> | |
emptyDataMessage?: string | |
initialPageSize?: number | |
theadClassName?: string | |
rowClassName?: string | |
cellClassName?: string | |
headerCellClassName?: string | |
resourceState?: Resource<any>["state"] | |
}; | |
export type IResourceTable<T = any> = typeof ResourceTable<T>; | |
export default function ResourceTable<T extends RowData = any>(props: TableProps<T>) { | |
const [, tanProps] = splitProps(props, ["data"]); | |
const state = createMemo(() => props.resourceState ?? props.data.state); | |
const isEmpty = createMemo(() => state() === "ready" && props.data()?.length === 0); | |
const table = createSolidTable<T>({ | |
...tanProps, | |
get data() { | |
if (state() === "refreshing") | |
return props.data.latest!; | |
if (state() === "ready") | |
return [...props.data()!]; | |
return []; | |
}, | |
state: { | |
...props.state, | |
}, | |
manualPagination: props.manualPagination ?? (props.onPaginationChange === undefined ? undefined : true), | |
getCoreRowModel: getCoreRowModel(), | |
getPaginationRowModel: props.getPaginationRowModel ?? getPaginationRowModel(), | |
}); | |
const rows = createMemo(() => { | |
return state() === "pending" | |
? lists.generateEmpty(props.initialPageSize ?? table.getState().pagination.pageSize) | |
: table.getRowModel().rows; | |
}); | |
return ( | |
<> | |
<table class='table-pin-rows table-pin-cols table-zebra table w-full'> | |
<thead class={props.theadClassName}> | |
<For each={table.getHeaderGroups()}> | |
{headerGroup => <tr children={<Th headerCellClassName={props.headerCellClassName} headerGroup={headerGroup} />} />} | |
</For> | |
</thead> | |
<Switch> | |
<Match when={state() !== "errored"}> | |
<tbody class={state() === "pending" ? "animate-pulse" : ""}> | |
<For each={rows()}> | |
{row => <tr class={props.rowClassName} children={<Td cellClassName={props.cellClassName} table={table} row={row} />} />} | |
</For> | |
</tbody> | |
</Match> | |
</Switch> | |
</table> | |
<Switch> | |
<Match when={isEmpty()}> | |
<div class="flex flex-col items-center justify-center gap-3 p-24 text-slate-500"> | |
<ArchiveBox class="w-10" /> | |
{props.emptyDataMessage ?? "No Data"} | |
</div> | |
</Match> | |
<Match when={state() === "errored"}> | |
<div class="flex flex-col items-center justify-center gap-3 p-24 text-red-700"> | |
<ArchiveBox class="w-10" /> | |
{props.data.error ?? "Something Wrong Happend!"} | |
</div> | |
</Match> | |
</Switch> | |
<Show when={props.state?.pagination}> | |
<Paging table={table} /> | |
</Show> | |
</> | |
); | |
} | |
function Th<T>(props: { headerGroup: HeaderGroup<T>; headerCellClassName?: string }) { | |
return <For each={props.headerGroup.headers}> | |
{header => ( | |
<th | |
class={props.headerCellClassName} | |
children={header.isPlaceholder ? undefined : flexRender(header.column.columnDef.header, header.getContext())} | |
/> | |
)} | |
</For>; | |
} | |
function Td<T>(props: { table: TanTable<T>; row: Row<T> | undefined; cellClassName?: string }) { | |
const cells = () => props.row === undefined | |
? lists.generateEmpty(props.table.getVisibleFlatColumns().length) | |
: props.row.getVisibleCells(); | |
return ( | |
<For each={cells()}> | |
{cell => ( | |
<td | |
class={props.cellClassName} | |
children={cell === undefined | |
? <div class="rounded bg-slate-300 text-slate-300 dark:bg-slate-800 dark:text-slate-800" textContent="Loading ..." /> | |
: flexRender(cell.column.columnDef.cell, cell.getContext())} /> | |
)} | |
</For> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment