diff --git a/components/retroui/Empty.tsx b/components/retroui/Empty.tsx new file mode 100644 index 0000000..99f1eb2 --- /dev/null +++ b/components/retroui/Empty.tsx @@ -0,0 +1,77 @@ +import { Text } from "@/components/retroui/Text"; +import { cn } from "@/lib/utils"; +import { Ghost } from "lucide-react"; +import { HTMLAttributes } from "react"; + +interface IEmptyProps extends HTMLAttributes { + className?: string; +} + +const Empty = ({ className, ...props }: IEmptyProps) => { + return ( +
+ ); +}; +Empty.displayName = "Empty"; + +const EmptyContent = ({ className, ...props }: IEmptyProps) => { + return ( +
+ ); +}; +EmptyContent.displayName = "Empty.Content"; + +const EmptyIcon = ({ children, className, ...props }: IEmptyProps) => { + return ( +
+ {children || } +
+ ); +}; +EmptyIcon.displayName = "Empty.Icon"; + +const EmptyTitle = ({ className, ...props }: IEmptyProps) => { + return ( + + ); +}; +EmptyTitle.displayName = "Empty.Title"; + +const EmptySeparator = ({ className, ...props }: IEmptyProps) => { + return
; +}; +EmptySeparator.displayName = "Empty.Separator"; + +const EmptyDescription = ({ + className, + ...props +}: HTMLAttributes) => ( +

+); +EmptyDescription.displayName = "Empty.Description"; + +const EmptyComponent = Object.assign(Empty, { + Content: EmptyContent, + Icon: EmptyIcon, + Title: EmptyTitle, + Separator: EmptySeparator, + Description: EmptyDescription, +}); + +export { EmptyComponent as Empty }; diff --git a/components/retroui/index.ts b/components/retroui/index.ts index 62de553..b19c5fb 100644 --- a/components/retroui/index.ts +++ b/components/retroui/index.ts @@ -6,7 +6,6 @@ export * from "./Radio"; export * from "./Select"; export * from "./Switch"; export * from "./Label"; -export * from "./Input"; export * from "./Text"; export * from "./Accordion"; export * from "./Alert"; @@ -26,4 +25,5 @@ export * from "./Breadcrumb"; export * from "./CommandDisplay"; export * from "./Command"; export * from "./Loader"; -export * from "./ContextMenu"; \ No newline at end of file +export * from "./ContextMenu"; +export * from "./Empty"; \ No newline at end of file diff --git a/config/components.ts b/config/components.ts index e9e3e61..8f0e122 100644 --- a/config/components.ts +++ b/config/components.ts @@ -1,4 +1,3 @@ -import { table } from "console"; import { lazy } from "react"; export const componentConfig: { @@ -84,6 +83,10 @@ export const componentConfig: { name: "drawer", filePath: "components/retroui/Drawer.tsx", }, + empty: { + name: "empty", + filePath: "components/retroui/Empty.tsx", + }, input: { name: "input", filePath: "components/retroui/Input.tsx", @@ -716,5 +719,25 @@ export const componentConfig: { filePath: "preview/components/typography-p.tsx", preview: lazy(() => import("@/preview/components/typography-p")), }, + "empty-style-default": { + name: "empty-style-default", + filePath: "preview/components/empty-style-default.tsx", + preview: lazy(() => import("@/preview/components/empty-style-default")) + }, + "empty-style-custom-icon": { + name: "empty-style-custom-icon", + filePath: "preview/components/empty-style-custom-icon.tsx", + preview: lazy(() => import("@/preview/components/empty-style-custom-icon")) + }, + "empty-style-custom-everything": { + name: "empty-style-custom-everything", + filePath: "preview/components/empty-style-custom-everything.tsx", + preview: lazy(() => import("@/preview/components/empty-style-custom-everything")) + }, + "empty-style-table": { + name: "empty-style-table", + filePath: "preview/components/empty-style-table.tsx", + preview: lazy(() => import("@/preview/components/empty-style-table")) + }, }, }; diff --git a/config/navigation.ts b/config/navigation.ts index f13514e..0706e5f 100644 --- a/config/navigation.ts +++ b/config/navigation.ts @@ -58,6 +58,7 @@ export const navConfig: INavigationConfig = { { title: "Command", href: `${componentsRoute}/command` }, { title: "Dialog", href: `${componentsRoute}/dialog` }, { title: "Drawer", href: `${componentsRoute}/drawer`, tag: "New" }, + { title: "Empty", href: `${componentsRoute}/empty`, tag: "New" }, { title: "Input", href: `${componentsRoute}/input` }, { title: "Label", href: `${componentsRoute}/label` }, { title: "Loader", href: `${componentsRoute}/loader` }, diff --git a/content/docs/components/empty.mdx b/content/docs/components/empty.mdx new file mode 100644 index 0000000..f93b229 --- /dev/null +++ b/content/docs/components/empty.mdx @@ -0,0 +1,70 @@ +--- +title: Empty +description: The component that shows when there is no data to show! +lastUpdated: 13 Jan, 2026 +links: + source: https://github.com/Logging-Stuff/RetroUI/blob/main/components/retroui/Empty.tsx +--- + + + +
+
+ +## Installation + + + + + +#### Copy the code 👇 into your project: + + + + + +
+
+ +## Examples + +### Default + + + +
+
+ +### Custom Icon + + + +
+
+ +### Customize everything + + + +
+
+ +### Using with table + + + +
+
+ +## API Reference + +The Empty component is composed of several sub-components: + +
+ +- `Empty` - The main component wrapper +- `Empty.Content` - Wrapper for the content elements +- `Empty.Icon` - Section for displaying an icon +- `Empty.Title` - The main heading for the empty state +- `Empty.Separator` - A visual separator line +- `Empty.Description` - Supporting text for the empty state diff --git a/preview/components/empty-style-custom-everything.tsx b/preview/components/empty-style-custom-everything.tsx new file mode 100644 index 0000000..551e6c1 --- /dev/null +++ b/preview/components/empty-style-custom-everything.tsx @@ -0,0 +1,20 @@ +import { Button, Empty } from "@/components/retroui"; +import { InboxIcon } from "lucide-react"; + + +export default function CustomEverythingEmpty() { + return ( + + + + + + No data + + Get started by creating your first item + + + + + ); +} diff --git a/preview/components/empty-style-custom-icon.tsx b/preview/components/empty-style-custom-icon.tsx new file mode 100644 index 0000000..0221f61 --- /dev/null +++ b/preview/components/empty-style-custom-icon.tsx @@ -0,0 +1,19 @@ +import { Empty } from "@/components/retroui/Empty"; + +export default function CustomIconEmpty() { + return ( + + + + 👻 + + No data + + + There is nothing to show here yet. Imagine you wrote some good stuff + here. + + + + ); +} diff --git a/preview/components/empty-style-default.tsx b/preview/components/empty-style-default.tsx new file mode 100644 index 0000000..7ccaf02 --- /dev/null +++ b/preview/components/empty-style-default.tsx @@ -0,0 +1,16 @@ +import { Empty } from "@/components/retroui"; + +export default function DefaultEmpty() { + return ( + + + + No Results + + + Your search didn't match any items. Try adjusting your filters. + + + + ); +} diff --git a/preview/components/empty-style-table.tsx b/preview/components/empty-style-table.tsx new file mode 100644 index 0000000..01d6632 --- /dev/null +++ b/preview/components/empty-style-table.tsx @@ -0,0 +1,39 @@ +import { Empty } from "@/components/retroui/Empty"; + +import { Table } from "@/components/retroui/Table"; + +const invoices = []; + +export default function TableEmpty() { + return ( + + + + Invoice + Customer + Status + Method + Amount + + + + + {invoices?.length === 0 && ( + + + + + + Empty + + Get started by creating your first invoice. + + + + + + )} + +
+ ); +}