Skip to content

Instantly share code, notes, and snippets.

@kkharji
Created March 26, 2024 21:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kkharji/eeba896ac87e1bf34de5b6dabd6eaa4b to your computer and use it in GitHub Desktop.
Save kkharji/eeba896ac87e1bf34de5b6dabd6eaa4b to your computer and use it in GitHub Desktop.
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