fix(modal): proper mobile bottom sheet — sticky header/footer, scrollable body

- rounded-t-2xl on mobile, full-width (no side padding)
- maxHeight = 100dvh - safe-area-top - 68px nav - safe-area-bottom
- header and footer flex-shrink-0, body flex-1 overflow-y-auto overflow-x-hidden
- save buttons in pinned footer, larger touch targets (py-3, rounded-xl)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-13 19:02:23 +02:00
parent 493f6ab7fc
commit 142d27e85c
+21 -16
View File
@@ -338,12 +338,15 @@ export function EventModal({ type, babyId, onClose, onSaved, initialEvent }: Pro
const segmentInactive = "border-slate-200 dark:border-slate-600 text-slate-500 dark:text-slate-400 hover:border-slate-300";
return (
<div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center p-4 pb-[calc(1rem+env(safe-area-inset-bottom)+64px)] sm:pb-4">
<div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center sm:p-4">
<div className="absolute inset-0 bg-black/30 backdrop-blur-sm" onClick={onClose} />
<div className="relative w-full max-w-md bg-white dark:bg-slate-800 rounded-2xl shadow-2xl z-10 max-h-[75vh] sm:max-h-[92vh] overflow-y-auto">
{/* Header */}
<div className="flex items-center justify-between px-5 py-4 border-b border-slate-100 dark:border-slate-700">
<div
className="relative w-full sm:max-w-md bg-white dark:bg-slate-800 rounded-t-2xl sm:rounded-2xl shadow-2xl z-10 flex flex-col overflow-hidden"
style={{ maxHeight: "calc(100dvh - env(safe-area-inset-top, 0px) - 68px - env(safe-area-inset-bottom, 0px))" }}
>
{/* Header — sticky */}
<div className="flex-shrink-0 flex items-center justify-between px-5 py-4 border-b border-slate-100 dark:border-slate-700">
<div className="flex items-center gap-3">
<div className={`w-9 h-9 rounded-xl ${config.bgClass} flex items-center justify-center`}>
<EventIcon name={config.icon} className={`w-5 h-5 ${config.colorClass}`} />
@@ -357,7 +360,8 @@ export function EventModal({ type, babyId, onClose, onSaved, initialEvent }: Pro
</button>
</div>
<div className="px-5 py-4 space-y-4">
{/* Scrollable body */}
<div className="flex-1 overflow-y-auto overflow-x-hidden px-5 py-4 space-y-4">
{/* Timer */}
{config.hasTimer && (
<div className="bg-slate-50 dark:bg-slate-700/50 rounded-xl p-4 text-center">
@@ -756,17 +760,18 @@ export function EventModal({ type, babyId, onClose, onSaved, initialEvent }: Pro
</div>
)}
{/* Actions */}
<div className="flex gap-2 pt-1 pb-1">
<button type="button" onClick={onClose}
className="flex-1 py-2.5 rounded-lg border border-slate-200 dark:border-slate-600 text-slate-600 dark:text-slate-300 text-sm font-medium hover:bg-slate-50 dark:hover:bg-slate-700 transition">
Annuler
</button>
<button type="button" onClick={handleSave} disabled={loading}
className="flex-[2] py-2.5 rounded-lg bg-indigo-600 hover:bg-indigo-700 disabled:bg-indigo-300 text-white text-sm font-medium transition">
{loading ? "..." : isEditing ? "Mettre à jour" : "Enregistrer"}
</button>
</div>
</div>
{/* Footer — sticky */}
<div className="flex-shrink-0 flex gap-2 px-5 py-4 border-t border-slate-100 dark:border-slate-700 bg-white dark:bg-slate-800">
<button type="button" onClick={onClose}
className="flex-1 py-3 rounded-xl border border-slate-200 dark:border-slate-600 text-slate-600 dark:text-slate-300 text-sm font-medium hover:bg-slate-50 dark:hover:bg-slate-700 transition">
Annuler
</button>
<button type="button" onClick={handleSave} disabled={loading}
className="flex-[2] py-3 rounded-xl bg-indigo-600 hover:bg-indigo-700 disabled:bg-indigo-300 text-white text-sm font-medium transition">
{loading ? "..." : isEditing ? "Mettre à jour" : "Enregistrer"}
</button>
</div>
</div>
</div>