From adb89b73e7b14a38c27d08dfc042a9973cac721d Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Tue, 14 Apr 2026 22:13:26 +0700 Subject: [PATCH] feat: add Empty component for improved no-data display in DataTable --- resources/js/components/data-table.tsx | 23 +++++- resources/js/components/ui/empty.tsx | 104 +++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 resources/js/components/ui/empty.tsx diff --git a/resources/js/components/data-table.tsx b/resources/js/components/data-table.tsx index 6b22d9e..1eb3f8d 100644 --- a/resources/js/components/data-table.tsx +++ b/resources/js/components/data-table.tsx @@ -35,7 +35,16 @@ import { } from "@/components/ui/dropdown-menu"; import React from "react"; import { Input } from "./ui/input"; -import { Settings2, ChevronDown, ListFilter, Trash2, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from "lucide-react"; +import { Settings2, ChevronDown, ListFilter, Trash2, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, List } from "lucide-react"; + +import { + Empty, + EmptyContent, + EmptyDescription, + EmptyHeader, + EmptyMedia, + EmptyTitle, +} from "@/components/ui/empty" interface DataTableFilterOption { columnId: string; @@ -303,7 +312,17 @@ export function DataTable({ ) : ( - Tidak ada data yang ditemukan. + + + + + + Ooops... + + Tidak ada data yang ditemukan. + + + )} diff --git a/resources/js/components/ui/empty.tsx b/resources/js/components/ui/empty.tsx new file mode 100644 index 0000000..ce4b009 --- /dev/null +++ b/resources/js/components/ui/empty.tsx @@ -0,0 +1,104 @@ +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +function Empty({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function EmptyHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +const emptyMediaVariants = cva( + "mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0", + { + variants: { + variant: { + default: "bg-transparent", + icon: "flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-6", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function EmptyMedia({ + className, + variant = "default", + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ) +} + +function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) { + return ( +
a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary", + className + )} + {...props} + /> + ) +} + +function EmptyContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { + Empty, + EmptyHeader, + EmptyTitle, + EmptyDescription, + EmptyContent, + EmptyMedia, +}