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 ( -
+ {isLoading ? (
)} -
+ ) } 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 ( -
+ {/* 캐릭터 조회 */}
-
+
) }