data-grid
Data grid with cell border
Data grid with cell border
Загрузка превью…
src/data-grid/c-data-grid-2.vue
<script setup lang="ts">
/**
* Порт `c-data-grid-2.tsx` ("Data grid with cell border"): `tableLayout.
* cellBorder = true` плюс `Card` вокруг `DataGridContainer`.
*
* Аватарки в оригинале грузятся с `images.unsplash.com` — реальный сетевой
* запрос, недетерминирован в headless-стенде; заменены локальным 1x1
* data-URI (тот же приём, что и в `block-card`/`block-avatar`, см.
* docs/PORTING.md §5 "picsum.photos").
*/
import { h, ref } from "vue"
import { DataGrid, DataGridContainer, DataGridScrollArea, DataGridTable, DataGridPagination } from "@/components/reui/data-grid"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Card } from "@/components/ui/card"
import {
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useVueTable,
} from "@tanstack/vue-table"
import type { ColumnDef, ColumnOrderState, PaginationState, SortingState } from "@tanstack/vue-table"
const PIXEL =
"data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="
interface IData {
id: string
name: string
email: string
company: string
role: string
balance: number
}
const demoData: IData[] = [
{ id: "1", name: "Alex Johnson", email: "alex@example.com", company: "Apple", role: "CEO", balance: 5143.03 },
{ id: "2", name: "Sarah Chen", email: "sarah@example.com", company: "OpenAI", role: "CTO", balance: 5243.03 },
{ id: "3", name: "Michael Rodriguez", email: "michael@example.com", company: "Meta", role: "Designer", balance: 5343.03 },
{ id: "4", name: "Emma Wilson", email: "emma@example.com", company: "Tesla", role: "Developer", balance: 5443.03 },
{ id: "5", name: "David Kim", email: "david@example.com", company: "SAP", role: "Lawyer", balance: 5543.03 },
{ id: "6", name: "Aron Thompson", email: "lisa@example.com", company: "Keenthemes", role: "Director", balance: 5643.03 },
{ id: "7", name: "James Brown", email: "james@example.com", company: "BBVA", role: "Product Manager", balance: 5743.03 },
]
function initials(name: string): string {
return name
.split(" ")
.map((n) => n[0])
.join("")
}
const pagination = ref<PaginationState>({ pageIndex: 0, pageSize: 5 })
const sorting = ref<SortingState>([{ id: "name", desc: true }])
const columnOrder = ref<ColumnOrderState>([])
const columns: ColumnDef<IData>[] = [
{
accessorKey: "name",
id: "name",
header: "Name",
cell: (ctx) =>
h("div", { class: "flex items-center gap-3" }, [
h(Avatar, { class: "size-8" }, () => [
h(AvatarImage, { src: PIXEL, alt: ctx.row.original.name }),
h(AvatarFallback, () => initials(ctx.row.original.name)),
]),
h("div", { class: "space-y-px" }, [
h("div", { class: "text-foreground font-medium" }, ctx.row.original.name),
h("div", { class: "text-muted-foreground" }, ctx.row.original.email),
]),
]),
size: 250,
enableSorting: true,
enableHiding: false,
},
{
accessorKey: "company",
header: "Company",
cell: (info) => h("span", info.getValue() as string),
size: 100,
meta: {
headerClassName: "",
},
},
{
accessorKey: "role",
header: "Occupation",
cell: (info) => h("span", info.getValue() as string),
size: 100,
meta: {
headerClassName: "",
},
},
{
accessorKey: "balance",
header: "Salary",
cell: (info) => h("span", { class: "font-semibold" }, `$${(info.getValue() as number).toFixed(2)}`),
size: 100,
},
]
const table = useVueTable({
get data() {
return demoData
},
columns,
get pageCount() {
return Math.ceil(demoData.length / pagination.value.pageSize)
},
getRowId: (row: IData) => row.id,
state: {
get pagination() {
return pagination.value
},
get sorting() {
return sorting.value
},
get columnOrder() {
return columnOrder.value
},
},
onPaginationChange: (updater) => {
pagination.value = typeof updater === "function" ? updater(pagination.value) : updater
},
onSortingChange: (updater) => {
sorting.value = typeof updater === "function" ? updater(sorting.value) : updater
},
onColumnOrderChange: (updater) => {
columnOrder.value = typeof updater === "function" ? updater(columnOrder.value) : updater
},
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
})
</script>
<template>
<DataGrid :table="table" :record-count="demoData.length" :table-layout="{ cellBorder: true }">
<div class="w-full space-y-2.5">
<Card class="p-0">
<DataGridContainer>
<DataGridScrollArea>
<DataGridTable />
</DataGridScrollArea>
</DataGridContainer>
</Card>
<DataGridPagination />
</div>
</DataGrid>
</template>