16 lines
9.7 KiB
JSON
16 lines
9.7 KiB
JSON
{
|
|
"name": "data-table",
|
|
"dependencies": [],
|
|
"registryDependencies": [],
|
|
"files": [
|
|
{
|
|
"name": "DataTable.vue",
|
|
"content": "<script setup lang=\"ts\">\nimport {\n type ColumnDef,\n FlexRender,\n type SortingState,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n useVueTable,\n} from '@tanstack/vue-table'\nimport { computed, ref } from 'vue'\nimport {\n ArrowDownNarrowWide,\n ArrowUpDown,\n ArrowUpNarrowWide,\n ChevronLeft,\n ChevronRight,\n ChevronsLeft,\n ChevronsRight,\n X,\n} from 'lucide-vue-next'\nimport {\n Table,\n TableBody,\n TableCell,\n TableEmpty,\n TableHead,\n TableHeader,\n TableRow,\n} from '../table'\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../dropdown-menu'\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectTrigger,\n} from '../select'\nimport { Input } from '../input'\nimport { Button } from '../button'\nimport RadixIconsMixerHorizontal from '~icons/radix-icons/mixer-horizontal'\n\ninterface tableProps {\n data: any[]\n columns: ColumnDef<any>[]\n}\n\nconst props = defineProps<tableProps>()\n\nconst sorting = ref<SortingState>([])\nconst globalFilter = ref('')\nconst columnVisibility = ref({})\nconst rowSelection = ref({})\nconst pageSizes = computed(() => [10, 20, 30, 40, 50])\n\nconst table = useVueTable({\n data: props.data,\n columns: props.columns,\n state: {\n get sorting() {\n return sorting.value\n },\n get globalFilter() {\n return globalFilter.value\n },\n get columnVisibility() {\n return columnVisibility.value\n },\n get rowSelection() {\n return rowSelection.value\n },\n },\n onSortingChange: (updaterOrValue) => {\n sorting.value\n = typeof updaterOrValue === 'function'\n ? updaterOrValue(sorting.value)\n : updaterOrValue\n },\n onGlobalFilterChange: (updaterOrValue) => {\n globalFilter.value\n = typeof updaterOrValue === 'function'\n ? updaterOrValue(globalFilter.value)\n : updaterOrValue\n },\n onRowSelectionChange: (updaterOrValue) => {\n rowSelection.value\n = typeof updaterOrValue === 'function'\n ? updaterOrValue(rowSelection.value)\n : updaterOrValue\n },\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: getSortedRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n getFilteredRowModel: getFilteredRowModel(),\n})\n\nfunction toggleColumnVisibility(column: any) {\n columnVisibility.value = {\n ...columnVisibility.value,\n [column.id]: !column.getIsVisible(),\n }\n}\n\nconst pageSize = computed({\n get() {\n return table.getState().pagination.pageSize.toString()\n },\n set(value) {\n table.setPageSize(Number(value))\n },\n})\n</script>\n\n<template>\n <div class=\"flex items-center justify-between\">\n <div class=\"flex flex-1 items-center space-x-2\">\n <div class=\"w-full max-w-[18rem]\">\n <Input\n v-model:value=\"globalFilter\"\n placeholder=\"Filter tasks...\"\n class=\"h-8\"\n />\n </div>\n <Button\n v-if=\"globalFilter\"\n variant=\"ghost\"\n class=\"h-8\"\n @click=\"globalFilter = ''\"\n >\n <span class=\"text-xs\">Reset</span>\n <X class=\"w-4 h-4 ml-1\" />\n </Button>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger>\n <Button variant=\"outline\" class=\"h-8\">\n <RadixIconsMixerHorizontal class=\"w-3.5 h-3.5 mr-2\" />\n <span class=\"text-xs\">View</span>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" class=\"w-40\">\n <DropdownMenuLabel> Toggle Columns </DropdownMenuLabel>\n <DropdownMenuSeparator />\n <DropdownMenuGroup>\n <DropdownMenuCheckboxItem\n v-for=\"column in table\n .getAllColumns()\n .filter((column) => !column.getCanHide())\"\n :key=\"column.id\"\n :checked=\"column.getIsVisible()\"\n @update:checked=\"toggleColumnVisibility(column)\"\n >\n <span class=\"text-sm\">{{ column.columnDef.header }}</span>\n </DropdownMenuCheckboxItem>\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n\n <Table class=\"mt-4 rounded-md border border-border\">\n <TableHeader>\n <TableRow\n v-for=\"headerGroup in table.getHeaderGroups()\"\n :key=\"headerGroup.id\"\n >\n <TableHead\n v-for=\"header in headerGroup.headers\"\n :key=\"header.id\"\n class=\"h-10 px-2.5\"\n :col-span=\"header.colSpan\"\n >\n <template v-if=\"!header.isPlaceholder\">\n <div class=\"flex items-center space-x-2\">\n <Button\n v-if=\"header.column.getCanSort()\"\n variant=\"ghost\"\n class=\"h-8 -translate-x-3\"\n @click=\"header.column.getToggleSortingHandler()?.($event)\"\n >\n <FlexRender\n :render=\"header.column.columnDef.header\"\n :props=\"header.getContext()\"\n />\n <ArrowUpDown\n v-if=\"\n header.column.getCanSort() && !header.column.getIsSorted()\n \"\n class=\"w-3.5 h-3.5 ml-1.5 text-muted\"\n />\n <ArrowUpNarrowWide\n v-if=\"header.column.getIsSorted() === 'asc'\"\n class=\"w-3.5 h-3.5 ml-1.5 text-muted\"\n />\n <ArrowDownNarrowWide\n v-if=\"header.column.getIsSorted() === 'desc'\"\n class=\"w-3.5 h-3.5 ml-1.5 text-muted\"\n />\n </Button>\n <span\n v-else\n class=\"flex items-center justify-center h-8 text-foreground\"\n >\n <FlexRender\n :render=\"header.column.columnDef.header\"\n :props=\"header.getContext()\"\n />\n </span>\n </div>\n </template>\n </TableHead>\n </TableRow>\n </TableHeader>\n\n <TableBody>\n <TableRow\n v-for=\"row in table.getRowModel().rows\"\n :key=\"row.id\"\n :class=\"row.getIsSelected() ? 'bg-outline-hover' : ''\"\n >\n <TableCell\n v-for=\"cell in row.getVisibleCells()\"\n :key=\"cell.id\"\n class=\"p-2.5\"\n >\n <FlexRender\n :render=\"cell.column.columnDef.cell\"\n :props=\"cell.getContext()\"\n />\n </TableCell>\n </TableRow>\n\n <TableEmpty\n v-if=\"table.getRowModel().rows.length === 0\"\n :colspan=\"table.getAllLeafColumns().length\"\n >\n No data available.\n </TableEmpty>\n </TableBody>\n </Table>\n\n <div class=\"flex items-center justify-end px-2 my-6\">\n <div class=\"flex-1 text-sm text-muted\">\n <span>\n {{ table.getFilteredSelectedRowModel().rows.length }} of {{ \" \" }}\n {{ table.getFilteredRowModel().rows.length }} row(s) selected\n </span>\n </div>\n <div class=\"flex items-center space-x-6 lg:space-x-8\">\n <div class=\"md:flex items-center space-x-2 hidden\">\n <p class=\"text-sm font-medium text-foreground\">\n Rows per page:\n </p>\n <Select v-model=\"pageSize\">\n <SelectTrigger class=\"h-8 w-[70px]\">\n {{ table.getState().pagination.pageSize }}\n </SelectTrigger>\n <SelectContent side=\"top\" align=\"start\">\n <SelectGroup>\n <SelectItem\n v-for=\"pageSize in pageSizes\"\n :key=\"pageSize\"\n :value=\"`${pageSize}`\"\n >\n {{ pageSize }}\n </SelectItem>\n </SelectGroup>\n </SelectContent>\n </Select>\n </div>\n\n <div\n class=\"flex text-foreground items-center justify-center text-sm font-medium\"\n >\n Page {{ table.getState().pagination.pageIndex + 1 }} of\n {{ table.getPageCount() }}\n </div>\n\n <div class=\"flex items-center space-x-2\">\n <Button\n variant=\"outline\"\n title=\"First page\"\n class=\"h-8 w-8 p-0\"\n :disabled=\"!table.getCanPreviousPage()\"\n @click=\"table.setPageIndex(0)\"\n >\n <ChevronsLeft class=\"w-4 h-4\" />\n </Button>\n <Button\n variant=\"outline\"\n title=\"Previous page\"\n class=\"h-8 w-8 p-0\"\n :disabled=\"!table.getCanPreviousPage()\"\n @click=\"table.previousPage()\"\n >\n <ChevronLeft class=\"w-4 h-4\" />\n </Button>\n <Button\n variant=\"outline\"\n title=\"Next page\"\n class=\"h-8 w-8 p-0\"\n :disabled=\"!table.getCanNextPage()\"\n @click=\"table.nextPage()\"\n >\n <ChevronRight class=\"w-4 h-4\" />\n </Button>\n <Button\n variant=\"outline\"\n title=\"Last page\"\n class=\"h-8 w-8 p-0\"\n :disabled=\"!table.getCanNextPage()\"\n @click=\"table.setPageIndex(table.getPageCount() - 1)\"\n >\n <ChevronsRight class=\"w-4 h-4\" />\n </Button>\n </div>\n </div>\n </div>\n</template>\n"
|
|
},
|
|
{
|
|
"name": "index.ts",
|
|
"content": "export { default as DataTable } from './DataTable.vue'\n"
|
|
}
|
|
],
|
|
"type": "components:ui"
|
|
} |