data-grid

Data grid with auto width table layout

Data grid with auto width table layout

Загрузка превью…

src/data-grid/c-data-grid-6.vue

<script setup lang="ts">
/**
 * Порт `c-data-grid-6.tsx` ("Data grid with auto width table layout"):
 * `tableLayout = { width: "auto" }`.
 *
 * Аватарки (`images.unsplash.com`) и флаги (`flagcdn.com`) — реальные
 * сетевые запросы, недетерминированы в headless-стенде; заменены
 * локальным 1x1 data-URI (см. 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 {
  getCoreRowModel,
  getFilteredRowModel,
  getPaginationRowModel,
  getSortedRowModel,
  useVueTable,
} from "@tanstack/vue-table"
import type { ColumnDef, PaginationState, SortingState } from "@tanstack/vue-table"

const PIXEL =
  "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="

interface IData {
  id: string
  name: string
  email: string
  flag: string
  location: string
  joined: string
}

const demoData: IData[] = [
  { id: "1", name: "Alex Johnson", email: "alex@apple.com", flag: "us", location: "United States", joined: "Jan, 2026" },
  { id: "2", name: "Sarah Chen", email: "sarah@openai.com", flag: "gb", location: "United Kingdom", joined: "Jul, 2025" },
  { id: "3", name: "Michael Rodriguez", email: "michael@meta.com", flag: "ca", location: "Canada", joined: "Mar, 2019" },
  { id: "4", name: "Emma Wilson", email: "emma@tesla.com", flag: "au", location: "Australia", joined: "Jan, 2024" },
  { id: "5", name: "David Kim", email: "david@sap.com", flag: "de", location: "Germany", joined: "May, 2023" },
  { id: "6", name: "Aron Thompson", email: "aron@keenthemes.com", flag: "my", location: "Malaysia", joined: "Nov, 2018" },
  { id: "7", name: "James Brown", email: "james@bbva.es", flag: "es", location: "Spain", joined: "Jun, 2021" },
]

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 columns: ColumnDef<IData>[] = [
  {
    accessorKey: "name",
    id: "name",
    header: "Name",
    cell: (ctx) =>
      h("div", { class: "flex items-center gap-2" }, [
        h(Avatar, { class: "size-6" }, () => [
          h(AvatarImage, { src: PIXEL, alt: ctx.row.original.name }),
          h(AvatarFallback, () => initials(ctx.row.original.name)),
        ]),
        h(
          "a",
          { href: "#", class: "text-foreground hover:text-primary font-medium" },
          ctx.row.original.name
        ),
      ]),
    size: 225,
    enableSorting: true,
    enableHiding: false,
  },
  {
    accessorKey: "email",
    header: "Email",
    cell: (info) =>
      h(
        "a",
        {
          href: `mailto:${info.getValue()}`,
          class: "hover:text-primary hover:underline",
        },
        info.getValue() as string
      ),
    size: 200,
  },
  {
    accessorKey: "location",
    header: "Location",
    cell: (ctx) =>
      h("div", { class: "flex items-center gap-1.5" }, [
        h("img", {
          src: PIXEL,
          alt: ctx.row.original.flag,
          class: "size-4 rounded-full object-cover",
        }),
        h("div", { class: "text-foreground font-medium" }, ctx.row.original.location),
      ]),
    size: 175,
  },
  {
    accessorKey: "joined",
    header: "Joined",
    cell: (info) => info.getValue() as string,
    size: 120,
    meta: {
      cellClassName: "font-medium",
    },
  },
]

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
    },
  },
  onPaginationChange: (updater) => {
    pagination.value = typeof updater === "function" ? updater(pagination.value) : updater
  },
  onSortingChange: (updater) => {
    sorting.value = typeof updater === "function" ? updater(sorting.value) : updater
  },
  getCoreRowModel: getCoreRowModel(),
  getFilteredRowModel: getFilteredRowModel(),
  getPaginationRowModel: getPaginationRowModel(),
  getSortedRowModel: getSortedRowModel(),
})
</script>

<template>
  <DataGrid :table="table" :record-count="demoData.length" :table-layout="{ width: 'auto' }">
    <div class="w-full space-y-2.5">
      <DataGridContainer>
        <DataGridScrollArea>
          <DataGridTable />
        </DataGridScrollArea>
      </DataGridContainer>
      <DataGridPagination />
    </div>
  </DataGrid>
</template>

Установка

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

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

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

  • @tanstack/vue-table

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