redesigned createItemModal with responsive and light /dark mode

This commit is contained in:
Satyam Rastogi
2026-05-15 15:19:51 +05:30
parent ff35b3076b
commit a85b90d283
+73 -62
View File
@@ -20,84 +20,95 @@ const CreateItemModal = ({ isOpen, onClose, title, icon: Icon, iconColor = "text
onClose(); onClose();
}; };
const inputBase = "w-full bg-white dark:bg-[#18181b] border border-zinc-200 dark:border-white/10 rounded-xl px-4 py-3 text-sm text-zinc-900 dark:text-white placeholder-zinc-400 dark:placeholder-zinc-600 focus:outline-none focus:border-[#00f0ff] focus:ring-1 focus:ring-[#00f0ff] transition-all";
return createPortal( return createPortal(
<div className="fixed inset-0 z-[9999] flex items-center justify-center p-4" role="dialog" aria-modal="true"> <div className="fixed inset-0 z-[9999] flex items-center justify-center p-3 sm:p-4" role="dialog" aria-modal="true">
<div className="absolute inset-0 bg-black/60 backdrop-blur-sm" onClick={onClose} /> <div className="absolute inset-0 bg-black/50 dark:bg-black/60 backdrop-blur-sm" onClick={onClose} />
<div className="relative w-full max-w-md bg-[#121214] rounded-2xl shadow-[0_0_40px_rgba(0,0,0,0.8)] border border-white/10 overflow-hidden animate-in zoom-in-95 duration-200"> <div className="relative w-full max-w-md max-h-[92vh] sm:max-h-[90vh] bg-white dark:bg-[#121214] rounded-2xl shadow-2xl shadow-zinc-900/20 dark:shadow-[0_0_40px_rgba(0,0,0,0.8)] border border-zinc-200 dark:border-white/10 overflow-hidden flex flex-col animate-in zoom-in-95 duration-200">
{/* Header */} {/* Header */}
<div className="px-6 py-5 border-b border-white/10 flex justify-between items-center bg-white/5"> <div className="px-5 sm:px-6 py-4 sm:py-5 border-b border-zinc-200 dark:border-white/10 flex justify-between items-center bg-zinc-50 dark:bg-white/5 shrink-0">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3 min-w-0">
{Icon && ( {Icon && (
<div className={`p-2 rounded-xl ${iconBg} ${iconColor}`}> <div className={`p-2 rounded-xl ${iconBg} ${iconColor} shrink-0`}>
<Icon size={20} /> <Icon size={20} />
</div> </div>
)} )}
<h2 className="text-lg font-bold text-white tracking-widest uppercase">{title}</h2> <h2 className="text-base sm:text-lg font-bold text-zinc-900 dark:text-white tracking-widest uppercase truncate">{title}</h2>
</div> </div>
<button onClick={onClose} className="p-2 rounded-lg hover:bg-white/10 text-zinc-500 hover:text-white transition-colors"> <button onClick={onClose} className="p-2 rounded-lg hover:bg-zinc-100 dark:hover:bg-white/10 text-zinc-500 hover:text-zinc-900 dark:hover:text-white transition-colors shrink-0">
<X size={18} /> <X size={18} />
</button> </button>
</div> </div>
{/* Content */} {/* Content */}
<form onSubmit={handleSubmit} className="p-6 space-y-5"> <form onSubmit={handleSubmit} className="flex-1 flex flex-col min-h-0">
{fields.map((field, i) => ( <div className="flex-1 overflow-y-auto px-5 sm:px-6 py-5 space-y-5">
<div key={i} className="space-y-1.5"> {fields.map((field, i) => (
<label htmlFor={field.name} className="text-xs font-bold uppercase tracking-wider text-zinc-400">{field.label}</label> <div key={i} className="space-y-1.5">
{field.type === 'textarea' ? ( <label htmlFor={field.name} className="text-xs font-bold uppercase tracking-wider text-zinc-600 dark:text-zinc-400">{field.label}</label>
<textarea {field.type === 'textarea' ? (
id={field.name} <textarea
name={field.name} id={field.name}
className="w-full bg-[#18181b] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-zinc-600 focus:outline-none focus:border-[#00f0ff] focus:ring-1 focus:ring-[#00f0ff] transition-all" name={field.name}
rows={4} className={inputBase}
placeholder={field.placeholder || ''} rows={4}
required={field.required} placeholder={field.placeholder || ''}
value={formData[field.name] || ''} required={field.required}
onChange={e => setFormData({ ...formData, [field.name]: e.target.value })} value={formData[field.name] || ''}
/> onChange={e => setFormData({ ...formData, [field.name]: e.target.value })}
) : field.type === 'select' ? ( />
<select ) : field.type === 'select' ? (
id={field.name} <select
name={field.name} id={field.name}
className="w-full bg-[#18181b] border border-white/10 rounded-xl px-4 py-3 text-sm text-white focus:outline-none focus:border-[#00f0ff] focus:ring-1 focus:ring-[#00f0ff] transition-all" name={field.name}
required={field.required} className={inputBase}
value={formData[field.name] || ''} required={field.required}
onChange={e => setFormData({ ...formData, [field.name]: e.target.value })} value={formData[field.name] || ''}
> onChange={e => setFormData({ ...formData, [field.name]: e.target.value })}
<option value="" disabled>Select {field.label}</option> >
{field.options.map(o => <option key={o.value} value={o.value}>{o.label}</option>)} <option value="" disabled>Select {field.label}</option>
</select> {field.options.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
) : field.type === 'file' ? ( </select>
<input ) : field.type === 'file' ? (
id={field.name} <input
name={field.name} id={field.name}
type="file" name={field.name}
accept={field.accept} type="file"
className="w-full text-sm text-zinc-400 file:mr-4 file:py-2.5 file:px-4 file:rounded-xl file:border file:border-white/10 file:text-sm file:font-bold file:bg-[#18181b] file:text-white hover:file:bg-white/5 transition-all" accept={field.accept}
required={field.required} className="w-full text-sm text-zinc-600 dark:text-zinc-400 file:mr-4 file:py-2.5 file:px-4 file:rounded-xl file:border file:border-zinc-200 dark:file:border-white/10 file:text-sm file:font-bold file:bg-zinc-50 dark:file:bg-[#18181b] file:text-zinc-900 dark:file:text-white hover:file:bg-zinc-100 dark:hover:file:bg-white/5 transition-all"
onChange={e => setFormData({ ...formData, [field.name]: e.target.files[0] })} required={field.required}
/> onChange={e => setFormData({ ...formData, [field.name]: e.target.files[0] })}
) : ( />
<input ) : (
id={field.name} <input
name={field.name} id={field.name}
type={field.type || 'text'} name={field.name}
className="w-full bg-[#18181b] border border-white/10 rounded-xl px-4 py-3 text-sm text-white placeholder-zinc-600 focus:outline-none focus:border-[#00f0ff] focus:ring-1 focus:ring-[#00f0ff] transition-all" type={field.type || 'text'}
placeholder={field.placeholder || ''} className={inputBase}
required={field.required} placeholder={field.placeholder || ''}
value={formData[field.name] || ''} required={field.required}
onChange={e => setFormData({ ...formData, [field.name]: e.target.value })} value={formData[field.name] || ''}
/> onChange={e => setFormData({ ...formData, [field.name]: e.target.value })}
)} />
</div> )}
))} </div>
))}
</div>
{/* Footer */} {/* Footer */}
<div className="pt-4 flex justify-end gap-3"> <div className="px-5 sm:px-6 py-4 border-t border-zinc-200 dark:border-white/10 bg-zinc-50 dark:bg-white/[0.02] flex flex-col-reverse sm:flex-row sm:justify-end gap-2 sm:gap-3 shrink-0">
<button type="button" onClick={onClose} className="px-5 py-2.5 text-sm font-bold text-zinc-400 hover:text-white transition-colors"> <button
type="button"
onClick={onClose}
className="px-5 py-2.5 text-sm font-bold rounded-xl border border-zinc-200 dark:border-white/10 text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-white/5 hover:text-zinc-900 dark:hover:text-white transition-colors"
>
Cancel Cancel
</button> </button>
<button type="submit" className={`px-6 py-2.5 text-sm font-bold rounded-xl border ${submitColor} hover:brightness-110 transition-all shadow-[0_0_15px_rgba(0,0,0,0.5)]`}> <button
type="submit"
className={`px-6 py-2.5 text-sm font-bold rounded-xl border ${submitColor} hover:brightness-110 transition-all shadow-sm dark:shadow-[0_0_15px_rgba(0,0,0,0.5)]`}
>
{submitLabel} {submitLabel}
</button> </button>
</div> </div>