feat: introduce reusable DataTableEmpty component to standardize empty state handling across tables

This commit is contained in:
Yoga Pangestu 2026-06-23 08:27:42 +07:00
parent 5986ec75a3
commit 06e313d168
6 changed files with 50 additions and 60 deletions

View File

@ -5,10 +5,7 @@ import { FlexRender, getCoreRowModel, useVueTable } from '@tanstack/vue-table';
import { computed, provide } from 'vue';
import DataTableToolbar from '@/components/data-table/DataTableToolbar.vue';
import { Button } from '@/components/ui/button';
import {
Empty, EmptyDescription,
EmptyHeader, EmptyTitle
} from '@/components/ui/empty';
import DataTableEmpty from './DataTableEmpty.vue';
import {
Table,
TableBody,
@ -199,14 +196,7 @@ function resolveRowSpan(row: TData, columnId: string): number | undefined {
</TableRow>
</template>
<TableEmpty v-else :colspan="resolvedColumns.length">
<Empty>
<EmptyHeader>
<EmptyTitle>Data tidak ditemukan</EmptyTitle>
<EmptyDescription>
Silakan lakukan pencarian atau filter untuk menemukan data yang Anda cari.
</EmptyDescription>
</EmptyHeader>
</Empty>
<DataTableEmpty plain />
</TableEmpty>
</TableBody>
</Table>

View File

@ -0,0 +1,40 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue';
import { cn } from '@/lib/utils';
import {
Empty,
EmptyDescription,
EmptyHeader,
EmptyTitle,
} from '@/components/ui/empty';
withDefaults(
defineProps<{
title?: string;
description?: string;
plain?: boolean;
class?: HTMLAttributes['class'];
}>(),
{
title: 'Data tidak ditemukan',
description: 'Silakan lakukan pencarian atau filter untuk menemukan data yang Anda cari.',
plain: false,
}
);
</script>
<template>
<div :class="cn(!plain && 'rounded-md border px-6 py-10', $props.class)">
<Empty>
<EmptyHeader>
<EmptyTitle>
<slot name="title">{{ title }}</slot>
</EmptyTitle>
<EmptyDescription>
<slot name="description">{{ description }}</slot>
</EmptyDescription>
</EmptyHeader>
<slot />
</Empty>
</div>
</template>

View File

@ -1,3 +1,5 @@
export { default as DataTable } from './DataTable.vue';
export { default as DataTableColumnHeader } from './DataTableColumnHeader.vue';
export { default as DataTableToolbar } from './DataTableToolbar.vue';
export { default as DataTableEmpty } from './DataTableEmpty.vue';

View File

@ -6,12 +6,7 @@ import { CuttingStatus } from '@/constants/cutting-status';
import DataTableToolbar from '@/components/data-table/DataTableToolbar.vue';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
Empty,
EmptyDescription,
EmptyHeader,
EmptyTitle,
} from '@/components/ui/empty';
import { DataTableEmpty } from '@/components/data-table';
import {
Table,
TableBody,
@ -299,16 +294,7 @@ function getGroupedMaterialUsage(materials: any[]): MaterialUsageGroup[] {
</div>
</div>
<div v-else class="rounded-md border px-6 py-10">
<Empty>
<EmptyHeader>
<EmptyTitle>Data tidak ditemukan</EmptyTitle>
<EmptyDescription>
Silakan lakukan pencarian untuk menemukan data yang Anda cari.
</EmptyDescription>
</EmptyHeader>
</Empty>
</div>
<DataTableEmpty v-else description="Silakan lakukan pencarian untuk menemukan data yang Anda cari." />
<div v-if="pagination" class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<p class="text-muted-foreground text-sm">

View File

@ -6,12 +6,7 @@ import { formatRupiah } from '@/lib/rupiah';
import MediaThumbnailCell from '@/components/media/MediaThumbnailCell.vue';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
Empty,
EmptyDescription,
EmptyHeader,
EmptyTitle,
} from '@/components/ui/empty';
import { DataTableEmpty } from '@/components/data-table';
import {
Table,
TableBody,
@ -172,16 +167,7 @@ function rowNumber(index: number): number {
</div>
</div>
<div v-else class="rounded-md border px-6 py-10">
<Empty>
<EmptyHeader>
<EmptyTitle>Data tidak ditemukan</EmptyTitle>
<EmptyDescription>
Silakan lakukan pencarian atau filter untuk menemukan data yang Anda cari.
</EmptyDescription>
</EmptyHeader>
</Empty>
</div>
<DataTableEmpty v-else />
<div v-if="pagination" class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<p class="text-muted-foreground text-sm">

View File

@ -5,12 +5,7 @@ import DataTableToolbar from '@/components/data-table/DataTableToolbar.vue';
import MediaThumbnailCell from '@/components/media/MediaThumbnailCell.vue';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
Empty,
EmptyDescription,
EmptyHeader,
EmptyTitle,
} from '@/components/ui/empty';
import { DataTableEmpty } from '@/components/data-table';
import {
Table,
TableBody,
@ -148,16 +143,7 @@ function rowNumber(index: number): number {
</div>
</div>
<div v-else class="rounded-md border px-6 py-10">
<Empty>
<EmptyHeader>
<EmptyTitle>Data tidak ditemukan</EmptyTitle>
<EmptyDescription>
Silakan lakukan pencarian atau filter untuk menemukan data yang Anda cari.
</EmptyDescription>
</EmptyHeader>
</Empty>
</div>
<DataTableEmpty v-else />
<div v-if="pagination" class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<p class="text-muted-foreground text-sm">