diff --git a/src/components/empty-state/empty-state.tsx b/src/components/empty-state/empty-state.tsx
index 3d7186cd..5e08f57b 100644
--- a/src/components/empty-state/empty-state.tsx
+++ b/src/components/empty-state/empty-state.tsx
@@ -1,4 +1,4 @@
-import React, { forwardRef } from 'react';
+import React, { forwardRef, useMemo } from 'react';
import EmptyStateImage from '@/assets/empty_state.png';
import EmptyStateImageDark from '@/assets/empty_state_dark.png';
import { cn } from '@/lib/utils';
@@ -11,6 +11,22 @@ import {
EmptyMedia,
EmptyTitle,
} from '../empty/empty';
+import { Button } from '../button/button';
+
+export interface EmptyStateActionButton {
+ label: string;
+ onClick?: () => void;
+ icon?: React.ReactNode;
+ disabled?: boolean;
+}
+
+export interface EmptyStateFooterAction {
+ label: string;
+ href?: string;
+ onClick?: () => void;
+ icon?: React.ReactNode;
+ disabled?: boolean;
+}
export interface EmptyStateProps {
title: string;
@@ -18,6 +34,9 @@ export interface EmptyStateProps {
imageClassName?: string;
titleClassName?: string;
descriptionClassName?: string;
+ primaryAction?: EmptyStateActionButton;
+ secondaryAction?: EmptyStateActionButton;
+ footerAction?: EmptyStateFooterAction;
}
export const EmptyState = forwardRef<
@@ -32,11 +51,29 @@ export const EmptyState = forwardRef<
titleClassName,
descriptionClassName,
imageClassName,
+ primaryAction,
+ secondaryAction,
+ footerAction,
},
ref
) => {
const { effectiveTheme } = useTheme();
+ // Determine if we have any actions to show
+ const hasActions = useMemo(
+ () => !!(primaryAction || secondaryAction),
+ [primaryAction, secondaryAction]
+ );
+ const hasFooterAction = useMemo(() => !!footerAction, [footerAction]);
+
+ const emptyStateImage = useMemo(
+ () =>
+ effectiveTheme === 'dark'
+ ? EmptyStateImageDark
+ : EmptyStateImage,
+ [effectiveTheme]
+ );
+
return (
{/*
*/}

@@ -66,7 +99,66 @@ export const EmptyState = forwardRef<
{description}
-
+
+ {/* Action buttons section */}
+ {hasActions && (
+
+
+ {primaryAction && (
+
+ )}
+ {secondaryAction && (
+
+ )}
+
+
+ )}
+
+ {/* Footer action link */}
+ {hasFooterAction && footerAction && (
+
+ )}
+
+ {/* Render empty content if no actions */}
+ {!hasActions && !hasFooterAction &&
}
);
diff --git a/src/pages/editor-page/side-panel/custom-types-section/custom-types-section.tsx b/src/pages/editor-page/side-panel/custom-types-section/custom-types-section.tsx
index 6040ebaf..96bcf385 100644
--- a/src/pages/editor-page/side-panel/custom-types-section/custom-types-section.tsx
+++ b/src/pages/editor-page/side-panel/custom-types-section/custom-types-section.tsx
@@ -73,6 +73,14 @@ export const CustomTypesSection: React.FC = () => {
'side_panel.custom_types_section.empty_state.description'
)}
className="mt-20"
+ secondaryAction={
+ !readonly
+ ? {
+ label: 'New Type',
+ onClick: handleCreateCustomType,
+ }
+ : undefined
+ }
/>
) : filterText && filteredCustomTypes.length === 0 ? (
diff --git a/src/pages/editor-page/side-panel/refs-section/refs-section.tsx b/src/pages/editor-page/side-panel/refs-section/refs-section.tsx
index 8fa68b24..6045405c 100644
--- a/src/pages/editor-page/side-panel/refs-section/refs-section.tsx
+++ b/src/pages/editor-page/side-panel/refs-section/refs-section.tsx
@@ -216,6 +216,16 @@ export const RefsSection: React.FC
= () => {
'side_panel.refs_section.empty_state.description'
)}
className="mt-20"
+ secondaryAction={
+ !readonly
+ ? {
+ label: t(
+ 'side_panel.refs_section.add_relationship'
+ ),
+ onClick: handleCreateRelationship,
+ }
+ : undefined
+ }
/>
) : (
diff --git a/src/pages/editor-page/side-panel/tables-section/tables-section.tsx b/src/pages/editor-page/side-panel/tables-section/tables-section.tsx
index 44c3faae..1bf9a5aa 100644
--- a/src/pages/editor-page/side-panel/tables-section/tables-section.tsx
+++ b/src/pages/editor-page/side-panel/tables-section/tables-section.tsx
@@ -184,6 +184,19 @@ export const TablesSection: React.FC = () => {
'side_panel.tables_section.empty_state.description'
)}
className="mt-20"
+ secondaryAction={
+ !readonly
+ ? {
+ label: t(
+ 'side_panel.tables_section.add_table'
+ ),
+ onClick: () =>
+ handleCreateTable({
+ view: false,
+ }),
+ }
+ : undefined
+ }
/>
) : filterText && filteredTables.length === 0 ? (
diff --git a/src/pages/editor-page/side-panel/visuals-section/areas-tab/areas-tab.tsx b/src/pages/editor-page/side-panel/visuals-section/areas-tab/areas-tab.tsx
index 3973db05..1bdd0981 100644
--- a/src/pages/editor-page/side-panel/visuals-section/areas-tab/areas-tab.tsx
+++ b/src/pages/editor-page/side-panel/visuals-section/areas-tab/areas-tab.tsx
@@ -92,6 +92,16 @@ export const AreasTab: React.FC
= () => {
'side_panel.areas_section.empty_state.description'
)}
className="mt-20"
+ secondaryAction={
+ !readonly
+ ? {
+ label: t(
+ 'side_panel.areas_section.add_area'
+ ),
+ onClick: handleCreateArea,
+ }
+ : undefined
+ }
/>
) : filterText && filteredAreas.length === 0 ? (
diff --git a/src/pages/editor-page/side-panel/visuals-section/notes-tab/notes-tab.tsx b/src/pages/editor-page/side-panel/visuals-section/notes-tab/notes-tab.tsx
index ac449632..9a04963b 100644
--- a/src/pages/editor-page/side-panel/visuals-section/notes-tab/notes-tab.tsx
+++ b/src/pages/editor-page/side-panel/visuals-section/notes-tab/notes-tab.tsx
@@ -92,6 +92,16 @@ export const NotesTab: React.FC
= () => {
'side_panel.notes_section.empty_state.description'
)}
className="mt-20"
+ secondaryAction={
+ !readonly
+ ? {
+ label: t(
+ 'side_panel.notes_section.add_note'
+ ),
+ onClick: handleCreateNote,
+ }
+ : undefined
+ }
/>
) : filterText && filteredNotes.length === 0 ? (