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>

Установка

npx shadcn-vue@latest add https://revueui.rootapi.dev/r/c-data-grid-2.json

Зависимости реестра

npm-зависимости

  • @tanstack/vue-table

Источник: порт из ReUI (Keenthemes, MIT)