Files
gridpilot.gg/apps/website/ui/PageHero.tsx
2026-01-19 12:35:16 +01:00

90 lines
2.5 KiB
TypeScript

import { LucideIcon } from 'lucide-react';
import { ReactNode } from 'react';
import { Box } from './Box';
import { Button } from './Button';
import { Heading } from './Heading';
import { Icon } from './Icon';
import { Surface } from './Surface';
import { Text } from './Text';
export interface PageHeroProps {
title: string;
description?: string;
children?: ReactNode;
image?: ReactNode;
icon?: LucideIcon;
actions?: Array<{
label: string;
onClick: () => void;
variant?: 'primary' | 'secondary';
icon?: LucideIcon;
}>;
}
export const PageHero = ({
title,
description,
children,
image,
icon,
actions
}: PageHeroProps) => {
return (
<Surface
variant="dark"
rounded="xl"
padding={8}
style={{ position: 'relative', overflow: 'hidden', border: '1px solid var(--ui-color-border-default)' }}
>
<Box display="flex" flexDirection={{ base: 'col', lg: 'row' }} alignItems="center" gap={8}>
<Box flex={1}>
<Box display="flex" alignItems="center" gap={4} marginBottom={4}>
{icon && (
<Box padding={3} rounded="lg" bg="var(--ui-color-bg-surface-muted)">
<Icon icon={icon} size={8} intent="primary" />
</Box>
)}
<Heading level={1}>{title}</Heading>
</Box>
{description && (
<Text size="lg" variant="low" marginBottom={6} block>
{description}
</Text>
)}
{actions && (
<Box display="flex" gap={4} marginBottom={children ? 6 : 0}>
{actions.map((action) => (
<Button
key={action.label}
variant={action.variant || 'primary'}
onClick={action.onClick}
icon={action.icon ? <Icon icon={action.icon} size={4} /> : undefined}
>
{action.label}
</Button>
))}
</Box>
)}
{children}
</Box>
{image && (
<Box flex={1} display="flex" justifyContent="center">
{image}
</Box>
)}
</Box>
{/* Decorative elements */}
<Box
position="absolute"
top="-4rem"
right="-4rem"
width="16rem"
height="16rem"
bg="var(--ui-color-intent-primary)"
style={{ opacity: 0.05, filter: 'blur(64px)', borderRadius: '9999px' }}
/>
</Surface>
);
};