website refactor

This commit is contained in:
2026-01-18 21:31:08 +01:00
parent 502d4aa092
commit b43a23a48c
96 changed files with 3461 additions and 4067 deletions

View File

@@ -1,51 +1,63 @@
import React, { ReactNode } from 'react';
import React, { ReactNode, useEffect } from 'react';
import { createPortal } from 'react-dom';
import { Box } from './primitives/Box';
import { Stack } from './primitives/Stack';
import { Button } from './Button';
import { Text } from './Text';
import { X } from 'lucide-react';
import { Surface } from './primitives/Surface';
import { IconButton } from './IconButton';
import { Button } from './Button';
import { X } from 'lucide-react';
import { Heading } from './Heading';
import { Text } from './Text';
interface ModalProps {
export interface ModalProps {
children: ReactNode;
isOpen: boolean;
onClose?: () => void;
onOpenChange?: (open: boolean) => void;
onOpenChange?: (isOpen: boolean) => void;
title?: string;
description?: string;
icon?: React.ReactNode;
children: ReactNode;
footer?: ReactNode;
size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
primaryActionLabel?: string;
onPrimaryAction?: () => void;
secondaryActionLabel?: string;
onSecondaryAction?: () => void;
isLoading?: boolean;
size?: 'sm' | 'md' | 'lg' | 'xl';
footer?: ReactNode;
description?: string;
icon?: ReactNode;
}
export function Modal({
isOpen,
onClose,
export const Modal = ({
children,
isOpen,
onClose,
onOpenChange,
title,
description,
icon,
children,
footer,
size = 'md',
primaryActionLabel,
onPrimaryAction,
secondaryActionLabel,
onSecondaryAction,
isLoading = false,
size = 'md',
}: ModalProps) {
footer,
description,
icon
}: ModalProps) => {
useEffect(() => {
if (isOpen) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = 'unset';
}
return () => {
document.body.style.overflow = 'unset';
};
}, [isOpen]);
if (!isOpen) return null;
const sizeMap = {
sm: 'max-w-md',
md: 'max-w-lg',
lg: 'max-w-2xl',
xl: 'max-w-4xl',
sm: '24rem',
md: '32rem',
lg: '48rem',
xl: '64rem',
full: '100%',
};
const handleClose = () => {
@@ -53,96 +65,82 @@ export function Modal({
if (onOpenChange) onOpenChange(false);
};
return (
<Box
position="fixed"
inset={0}
zIndex={60}
display="flex"
alignItems="center"
justifyContent="center"
bg="bg-black/60"
px={4}
className="backdrop-blur-sm"
role="dialog"
aria-modal="true"
return createPortal(
<Box
position="fixed"
inset={0}
zIndex={100}
display="flex"
alignItems="center"
justifyContent="center"
padding={4}
bg="rgba(0, 0, 0, 0.8)"
>
{/* Backdrop click to close */}
<Box position="absolute" inset={0} onClick={handleClose} />
<Box
position="relative"
w="full"
maxWidth={sizeMap[size]}
rounded="2xl"
bg="bg-[#0f1115]"
border
borderColor="border-[#262626]"
shadow="2xl"
overflow="hidden"
tabIndex={-1}
<Box
position="absolute"
inset={0}
onClick={handleClose}
/>
<Surface
variant="default"
rounded="lg"
shadow="xl"
style={{
width: '100%',
maxWidth: sizeMap[size],
maxHeight: '90vh',
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
position: 'relative',
border: '1px solid var(--ui-color-border-default)'
}}
>
{/* Header */}
<Box p={6} borderBottom borderColor="border-white/5">
<Stack direction="row" align="center" justify="between">
<Stack direction="row" align="center" gap={3}>
{icon && <Box>{icon}</Box>}
<Box>
{title && (
<Text size="xl" weight="bold" color="text-white" block>
{title}
</Text>
)}
{description && (
<Text size="sm" color="text-gray-400" block mt={1}>
{description}
</Text>
)}
</Box>
</Stack>
<IconButton
icon={X}
onClick={handleClose}
variant="ghost"
size="sm"
title="Close modal"
/>
</Stack>
<Box
display="flex"
alignItems="center"
justifyContent="between"
padding={4}
borderBottom
>
<Box display="flex" alignItems="center" gap={3}>
{icon}
<Box>
{title && <Heading level={3}>{title}</Heading>}
{description && <Box marginTop={1}><Text size="sm" variant="low">{description}</Text></Box>}
</Box>
</Box>
<IconButton icon={X} onClick={handleClose} variant="ghost" title="Close modal" />
</Box>
{/* Content */}
<Box p={6} overflowY="auto" maxHeight="calc(100vh - 200px)">
<Box flex={1} overflow="auto" padding={6}>
{children}
</Box>
{/* Footer */}
{(primaryActionLabel || secondaryActionLabel || footer) && (
<Box p={6} borderTop borderColor="border-white/5">
{footer || (
<Stack direction="row" justify="end" gap={3}>
{secondaryActionLabel && (
<Button
variant="ghost"
onClick={onSecondaryAction || onClose}
disabled={isLoading}
>
{secondaryActionLabel}
</Button>
)}
{primaryActionLabel && (
<Button
variant="primary"
onClick={onPrimaryAction}
isLoading={isLoading}
>
{primaryActionLabel}
</Button>
)}
</Stack>
{(footer || primaryActionLabel || secondaryActionLabel) && (
<Box padding={4} borderTop bg="rgba(255,255,255,0.02)" display="flex" justifyContent="end" gap={3}>
{footer}
{secondaryActionLabel && (
<Button
onClick={onSecondaryAction || handleClose}
variant="ghost"
>
{secondaryActionLabel}
</Button>
)}
{primaryActionLabel && (
<Button
onClick={onPrimaryAction}
variant="primary"
>
{primaryActionLabel}
</Button>
)}
</Box>
)}
</Box>
</Box>
</Surface>
</Box>,
document.body
);
}
};