refactor: replace preset detail modal layoutId morph with bottom sheet slide-up + category crossfade
- Remove layoutId from preset card in game-page-client.tsx and modal in preset-detail-modal.tsx to eliminate text smearing during morph animation. - Replace modal scale/opacity spring animation with bottom sheet y-slide spring (y: 100% → 0). - Wrap settings table content in AnimatePresence mode='wait' with keyed motion.div for crossfade when switching categories.
This commit is contained in:
@@ -751,7 +751,6 @@ export function GamePageClient({
|
|||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={preset.id}
|
key={preset.id}
|
||||||
layoutId={preset.id}
|
|
||||||
onClick={() => setSelectedPresetId(preset.id)}
|
onClick={() => setSelectedPresetId(preset.id)}
|
||||||
className={`shrink-0 w-72 flex flex-col gap-3 p-4 rounded-xl border transition-colors cursor-pointer hover:border-primary/30 ${
|
className={`shrink-0 w-72 flex flex-col gap-3 p-4 rounded-xl border transition-colors cursor-pointer hover:border-primary/30 ${
|
||||||
raw
|
raw
|
||||||
|
|||||||
@@ -164,14 +164,13 @@ export function PresetDetailModal({
|
|||||||
>
|
>
|
||||||
{/* Modal card */}
|
{/* Modal card */}
|
||||||
<motion.div
|
<motion.div
|
||||||
layoutId={preset.id}
|
|
||||||
className="relative w-full max-w-4xl max-h-[90vh] overflow-hidden rounded-xl border border-border bg-background flex flex-col"
|
className="relative w-full max-w-4xl max-h-[90vh] overflow-hidden rounded-xl border border-border bg-background flex flex-col"
|
||||||
initial={{ scale: 0.95, opacity: 0 }}
|
initial={{ y: "100%", opacity: 0 }}
|
||||||
animate={{ scale: 1, opacity: 1 }}
|
animate={{ y: 0, opacity: 1 }}
|
||||||
exit={{ scale: 0.95, opacity: 0 }}
|
exit={{ y: "100%", opacity: 0 }}
|
||||||
transition={{
|
transition={{
|
||||||
type: "spring",
|
type: "spring",
|
||||||
damping: 25,
|
damping: 30,
|
||||||
stiffness: 300,
|
stiffness: 300,
|
||||||
}}
|
}}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
@@ -427,7 +426,15 @@ export function PresetDetailModal({
|
|||||||
{/* Right panel */}
|
{/* Right panel */}
|
||||||
<div className="flex-1 overflow-y-auto p-5">
|
<div className="flex-1 overflow-y-auto p-5">
|
||||||
{hasCategories ? (
|
{hasCategories ? (
|
||||||
<div className="flex flex-col gap-4">
|
<AnimatePresence mode="wait">
|
||||||
|
<motion.div
|
||||||
|
key={currentCategory?.category ?? "empty"}
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
transition={{ duration: 0.15 }}
|
||||||
|
className="flex flex-col gap-4"
|
||||||
|
>
|
||||||
{/* Category navigation */}
|
{/* Category navigation */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<button
|
<button
|
||||||
@@ -482,7 +489,8 @@ export function PresetDetailModal({
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
|
</AnimatePresence>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col items-center justify-center py-16 gap-3 rounded-lg border border-border bg-text/2">
|
<div className="flex flex-col items-center justify-center py-16 gap-3 rounded-lg border border-border bg-text/2">
|
||||||
<p className="text-sm text-text/40">
|
<p className="text-sm text-text/40">
|
||||||
|
|||||||
Reference in New Issue
Block a user