Initial CMPP frontend prototype

This commit is contained in:
hectorzhao
2026-06-30 16:09:46 +08:00
commit 2f3c274a30
98 changed files with 25255 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
import type { ReactNode } from 'react';
import { useEffect } from 'react';
import { createPortal } from 'react-dom';
import { X } from 'lucide-react';
import { Button } from '@/components/ui/Button';
type ModalProps = {
open: boolean;
title: ReactNode;
children: ReactNode;
footer?: ReactNode;
size?: 'md' | 'xl';
onClose: () => void;
};
export function Modal({ open, title, children, footer, size = 'md', onClose }: ModalProps) {
useEffect(() => {
function handleKeyDown(event: KeyboardEvent) {
if (event.key === 'Escape') {
onClose();
}
}
if (open) {
document.addEventListener('keydown', handleKeyDown);
}
return () => document.removeEventListener('keydown', handleKeyDown);
}, [open, onClose]);
if (!open) {
return null;
}
return createPortal(
<div className="ui-modal" role="presentation">
<button className="ui-modal__mask" type="button" aria-label="关闭弹窗" onClick={onClose} />
<section aria-modal="true" className={['ui-modal__panel', `ui-modal__panel--${size}`].join(' ')} role="dialog">
<header className="ui-modal__header">
<div className="ui-modal__title">{title}</div>
<Button icon={<X size={17} />} iconOnly variant="ghost" onClick={onClose}>
</Button>
</header>
<div className="ui-modal__body">{children}</div>
{footer ? <footer className="ui-modal__footer">{footer}</footer> : null}
</section>
</div>,
document.body,
);
}