Files
emaui/apps/portal/src/app/components/EmptyState.tsx
2026-06-10 07:03:50 +00:00

68 lines
2.4 KiB
TypeScript

import { Button, Paper, Stack, Text } from '@mantine/core';
import type { Icon } from '@tabler/icons-react';
import type { ReactNode } from 'react';
interface EmptyStateProps {
/** Kept for API compatibility; the illustration is used as the primary visual. */
icon?: Icon;
title: string;
description?: string;
action?: { label: string; onClick: () => void; icon?: ReactNode };
}
export function EmptyState({ title, description, action }: EmptyStateProps) {
return (
<Paper p="xl" withBorder>
<Stack align="center" gap="sm" py="lg">
<EmptyIllustration />
<Text fw={600} fz="lg">
{title}
</Text>
{description && (
<Text c="dimmed" size="sm" ta="center" maw={440}>
{description}
</Text>
)}
{action && (
<Button mt="xs" leftSection={action.icon} onClick={action.onClick}>
{action.label}
</Button>
)}
</Stack>
</Paper>
);
}
/** Lightweight maritime illustration: a document floating on stylized waves. */
function EmptyIllustration() {
const primary = 'var(--mantine-color-emaPrimary-6)';
const primaryLight = 'var(--mantine-color-emaPrimary-2)';
const teal = 'var(--mantine-color-emaTeal-5)';
const surface = 'var(--mantine-color-body)';
return (
<svg
width="148"
height="120"
viewBox="0 0 148 120"
fill="none"
role="img"
aria-hidden
>
<ellipse cx="74" cy="104" rx="58" ry="9" fill={primaryLight} opacity="0.45" />
{/* document */}
<g>
<rect x="46" y="20" width="56" height="68" rx="8" fill={surface} stroke={primary} strokeWidth="2.5" />
<rect x="56" y="34" width="36" height="4" rx="2" fill={primaryLight} />
<rect x="56" y="46" width="36" height="4" rx="2" fill={primaryLight} />
<rect x="56" y="58" width="24" height="4" rx="2" fill={primaryLight} />
<circle cx="92" cy="74" r="9" fill={teal} opacity="0.9" />
<path d="M88 74l3 3 5-6" stroke={surface} strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" />
</g>
{/* waves */}
<path d="M14 96c8 0 8-5 16-5s8 5 16 5 8-5 16-5 8 5 16 5 8-5 16-5 8 5 16 5" stroke={teal} strokeWidth="2.5" strokeLinecap="round" opacity="0.8" />
<path d="M22 106c8 0 8-5 16-5s8 5 16 5 8-5 16-5 8 5 16 5 8-5 16-5" stroke={primary} strokeWidth="2.5" strokeLinecap="round" opacity="0.45" />
</svg>
);
}