Files
clinicpro/assets/admin/components/ui/Modal.tsx
T
hamed 942634c98e refactor: update UI components for consistency and dark mode support
- Refactored PaymentsPage, RatingsPage, RepresentationDetailPage, RepresentationsPage, SecretariesPage, SettlementsPage, SmsPage, UserDetailPage, and UsersPage to use consistent class names for styling.
- Updated button styles to use new utility classes for primary, secondary, and danger buttons.
- Enhanced dark mode support across various components by adjusting text and background colors.
- Introduced new utility classes for form inputs, labels, and info rows to standardize styling.
- Implemented Zustand for persistent UI state management, including dark mode toggle functionality.
- Updated CSS to include new styles for skeleton loading and animations.
- Added optional dependencies for improved compatibility with different platforms.
2026-06-10 12:30:14 +03:30

74 lines
2.3 KiB
TypeScript

import React, { useEffect } from 'react';
import { XMarkIcon } from '@heroicons/react/24/outline';
type ModalSize = 'sm' | 'md' | 'lg' | 'xl';
const sizeMap: Record<ModalSize, string> = {
sm: 'max-w-sm',
md: 'max-w-lg',
lg: 'max-w-2xl',
xl: 'max-w-4xl',
};
interface Props {
open: boolean;
title: string;
size?: ModalSize;
onClose: () => void;
children: React.ReactNode;
footer?: React.ReactNode;
}
export default function Modal({ open, title, size = 'md', onClose, children, footer }: Props) {
useEffect(() => {
if (!open) return;
const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };
document.addEventListener('keydown', onKey);
return () => document.removeEventListener('keydown', onKey);
}, [open, onClose]);
if (!open) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 animate-fade-in">
{/* Backdrop */}
<div
className="absolute inset-0 bg-black/50 dark:bg-black/70 backdrop-blur-sm"
onClick={onClose}
/>
{/* Panel */}
<div
className={`
relative bg-white dark:bg-gray-900
rounded-2xl shadow-2xl dark:shadow-black/40
border border-slate-200/60 dark:border-gray-700/50
w-full ${sizeMap[size]} flex flex-col max-h-[90vh]
animate-scale-in
`}
>
{/* Header */}
<div className="flex items-center justify-between px-6 py-4 border-b border-slate-100 dark:border-gray-700/50 shrink-0">
<h2 className="font-semibold text-slate-900 dark:text-slate-100 text-base">{title}</h2>
<button
onClick={onClose}
className="w-8 h-8 flex items-center justify-center rounded-lg text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 hover:bg-slate-100 dark:hover:bg-gray-700 transition-colors"
>
<XMarkIcon className="w-5 h-5" />
</button>
</div>
{/* Body */}
<div className="flex-1 overflow-y-auto px-6 py-5">{children}</div>
{/* Footer */}
{footer && (
<div className="flex items-center justify-end gap-3 px-6 py-4 border-t border-slate-100 dark:border-gray-700/50 shrink-0 bg-slate-50/50 dark:bg-gray-800/30 rounded-b-2xl">
{footer}
</div>
)}
</div>
</div>
);
}