diff --git a/frontend/src/components/common/StaggerGroup.jsx b/frontend/src/components/common/StaggerGroup.jsx
new file mode 100644
index 0000000..5a6ebb5
--- /dev/null
+++ b/frontend/src/components/common/StaggerGroup.jsx
@@ -0,0 +1,39 @@
+import { Children } from 'react'
+import { motion } from 'framer-motion'
+
+const containerVariants = {
+ hidden: {},
+ show: { transition: { staggerChildren: 0.07 } },
+}
+
+const itemVariants = {
+ hidden: { opacity: 0, y: 10 },
+ show: {
+ opacity: 1,
+ y: 0,
+ transition: { duration: 0.35, ease: [0.22, 1, 0.36, 1] },
+ },
+}
+
+/**
+ * 자식을 각 motion.div 로 감싸 순차 페이드인.
+ * 레이아웃에 영향 주지 않도록 wrapper div 는 flex/grid 특성이 없어야 하는 자리에서만 사용.
+ * space-y-* 같은 Tailwind 유틸은 그대로 className 에 넘겨 유지.
+ */
+export default function StaggerGroup({ children, className, style }) {
+ return (
+
+ {Children.map(children, (child, i) => (
+ child == null || child === false
+ ? null
+ : {child}
+ ))}
+
+ )
+}
diff --git a/frontend/src/features/FeaturePage.jsx b/frontend/src/features/FeaturePage.jsx
index f8c7a48..1a5aa60 100644
--- a/frontend/src/features/FeaturePage.jsx
+++ b/frontend/src/features/FeaturePage.jsx
@@ -11,11 +11,7 @@ export default function FeaturePage() {
}
return (
-
-
-
- }>
+
)
diff --git a/frontend/src/features/admin/pc/AdminFeaturePage.jsx b/frontend/src/features/admin/pc/AdminFeaturePage.jsx
index b0e891b..55e220f 100644
--- a/frontend/src/features/admin/pc/AdminFeaturePage.jsx
+++ b/frontend/src/features/admin/pc/AdminFeaturePage.jsx
@@ -49,14 +49,7 @@ export default function AdminFeaturePage() {
}
return (
-
-
-
- }>
+
)
diff --git a/frontend/src/features/boss-crystal/pc/BossCrystal.jsx b/frontend/src/features/boss-crystal/pc/BossCrystal.jsx
index f6e13e3..e47a8cf 100644
--- a/frontend/src/features/boss-crystal/pc/BossCrystal.jsx
+++ b/frontend/src/features/boss-crystal/pc/BossCrystal.jsx
@@ -1,5 +1,6 @@
import { useEffect, useLayoutEffect } from 'react'
import { useQuery, useQueries } from '@tanstack/react-query'
+import { motion } from 'framer-motion'
import { api } from '../../../api/client'
import { useLayout } from '../../../components/pc/Layout'
import CharacterPanel from './user/CharacterPanel'
@@ -70,7 +71,12 @@ export default function BossCrystal() {
const isMaxReached = currentSelectedCount >= MAX_PER_CHARACTER
return (
-
+
)
}
diff --git a/frontend/src/features/liberation/pc/Destiny.jsx b/frontend/src/features/liberation/pc/Destiny.jsx
index 6d92049..280fd9c 100644
--- a/frontend/src/features/liberation/pc/Destiny.jsx
+++ b/frontend/src/features/liberation/pc/Destiny.jsx
@@ -16,6 +16,7 @@ import PointsInput from './components/PointsInput'
import WeeklyDefault from './components/WeeklyDefault'
import DatePicker from '../../../components/common/DatePicker'
import ConfirmDialog from '../../../components/common/ConfirmDialog'
+import StaggerGroup from '../../../components/common/StaggerGroup'
export default function Destiny() {
const calcMode = useLiberationStore((s) => s.destinyCalcMode)
@@ -69,7 +70,7 @@ export default function Destiny() {
}
return (
- <>
+
{/* 계산 모드 탭 */}
- >
+
)
}
diff --git a/frontend/src/features/liberation/pc/Genesis.jsx b/frontend/src/features/liberation/pc/Genesis.jsx
index 6f3621e..9edeb9a 100644
--- a/frontend/src/features/liberation/pc/Genesis.jsx
+++ b/frontend/src/features/liberation/pc/Genesis.jsx
@@ -24,6 +24,7 @@ import ProgressBar from './components/ProgressBar'
import WeeklyDefault from './components/WeeklyDefault'
import DatePicker from '../../../components/common/DatePicker'
import ConfirmDialog from '../../../components/common/ConfirmDialog'
+import StaggerGroup from '../../../components/common/StaggerGroup'
export default function Genesis() {
const calcMode = useLiberationStore((s) => s.genesisCalcMode)
@@ -93,7 +94,7 @@ export default function Genesis() {
}
return (
- <>
+
{/* 계산 모드 탭 */}
- >
+
)
}
diff --git a/frontend/src/features/symbol/pc/Symbol.jsx b/frontend/src/features/symbol/pc/Symbol.jsx
index 735eb47..a0fce65 100644
--- a/frontend/src/features/symbol/pc/Symbol.jsx
+++ b/frontend/src/features/symbol/pc/Symbol.jsx
@@ -9,6 +9,7 @@ import { formatMesoKorean } from '../../../utils/formatting'
import { formatKoreanDate, computeCompletion, TYPE_ORDER, eventBonusForType } from '../utils'
import CharacterCard from './user/CharacterCard'
import SymbolCard from './user/SymbolCard'
+import StaggerGroup from '../../../components/common/StaggerGroup'
export default function Symbol() {
const { setFullscreen } = useLayout()
@@ -193,7 +194,7 @@ export default function Symbol() {
}, [symbols, progress, selectedChar?.event_skill])
return (
-
-
+
)
}