StaggerGroup 파라미터를 프로미스나인 사이트와 동일하게 맞춤 + 보스 리스트 애니메이션
- StaggerGroup 기본값: y 30px / duration 0.4s / 간격 0.1s, default ease (프로미스나인 AlbumDetail 패턴과 일치) - staggerDelay / yOffset / duration prop 받도록 커스터마이즈 가능 - BossCrystal fade-in 파라미터도 동일하게 맞춤 - BossSelector 보스 리스트에 StaggerGroup 적용 (항목 많으므로 간격 0.04s, y 20px, duration 0.3s 로 가볍게) - CharacterPanel 은 Reorder.Group 드래그 로직과 충돌하므로 제외 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d1764dea94
commit
1344a2f7a9
3 changed files with 38 additions and 21 deletions
|
|
@ -1,26 +1,36 @@
|
||||||
import { Children } from 'react'
|
import { Children } from 'react'
|
||||||
import { motion } from 'framer-motion'
|
import { motion } from 'framer-motion'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 자식을 각 motion.div 로 감싸 순차 페이드인.
|
||||||
|
* 기본값은 프로미스나인 사이트와 동일 (y 30, duration 0.4, 간격 0.1s).
|
||||||
|
*
|
||||||
|
* @param {number} staggerDelay - 자식 간 간격 (초)
|
||||||
|
* @param {number} yOffset - 시작 y 오프셋 (px)
|
||||||
|
* @param {number} duration - 각 자식 애니메이션 지속시간 (초)
|
||||||
|
*/
|
||||||
|
export default function StaggerGroup({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
style,
|
||||||
|
staggerDelay = 0.1,
|
||||||
|
yOffset = 30,
|
||||||
|
duration = 0.4,
|
||||||
|
}) {
|
||||||
const containerVariants = {
|
const containerVariants = {
|
||||||
hidden: {},
|
hidden: {},
|
||||||
show: { transition: { staggerChildren: 0.07 } },
|
show: { transition: { staggerChildren: staggerDelay } },
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemVariants = {
|
const itemVariants = {
|
||||||
hidden: { opacity: 0, y: 10 },
|
hidden: { opacity: 0, y: yOffset },
|
||||||
show: {
|
show: {
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
y: 0,
|
y: 0,
|
||||||
transition: { duration: 0.35, ease: [0.22, 1, 0.36, 1] },
|
transition: { duration },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 자식을 각 motion.div 로 감싸 순차 페이드인.
|
|
||||||
* 레이아웃에 영향 주지 않도록 wrapper div 는 flex/grid 특성이 없어야 하는 자리에서만 사용.
|
|
||||||
* space-y-* 같은 Tailwind 유틸은 그대로 className 에 넘겨 유지.
|
|
||||||
*/
|
|
||||||
export default function StaggerGroup({ children, className, style }) {
|
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
className={className}
|
className={className}
|
||||||
|
|
|
||||||
|
|
@ -73,9 +73,9 @@ export default function BossCrystal() {
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
className="h-full"
|
className="h-full"
|
||||||
initial={{ opacity: 0, y: 10 }}
|
initial={{ opacity: 0, y: 30 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.35, ease: [0.22, 1, 0.36, 1] }}
|
transition={{ duration: 0.4 }}
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'
|
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'
|
||||||
import Select from '../../../../components/common/Select'
|
import Select from '../../../../components/common/Select'
|
||||||
|
import StaggerGroup from '../../../../components/common/StaggerGroup'
|
||||||
import { DIFFICULTIES, formatMeso } from '../admin/constants'
|
import { DIFFICULTIES, formatMeso } from '../admin/constants'
|
||||||
|
|
||||||
const LABEL_EN = { easy: 'EASY', normal: 'NORMAL', hard: 'HARD', chaos: 'CHAOS', extreme: 'EXTREME' }
|
const LABEL_EN = { easy: 'EASY', normal: 'NORMAL', hard: 'HARD', chaos: 'CHAOS', extreme: 'EXTREME' }
|
||||||
|
|
@ -67,7 +68,13 @@ export default function BossSelector({ characterName, bosses, selections, onChan
|
||||||
}}
|
}}
|
||||||
defer
|
defer
|
||||||
>
|
>
|
||||||
<div className="divide-y px-2" style={{ '--tw-divide-opacity': 1 }}>
|
<StaggerGroup
|
||||||
|
className="divide-y px-2"
|
||||||
|
style={{ '--tw-divide-opacity': 1 }}
|
||||||
|
staggerDelay={0.04}
|
||||||
|
yOffset={20}
|
||||||
|
duration={0.3}
|
||||||
|
>
|
||||||
{bosses.map((boss) => {
|
{bosses.map((boss) => {
|
||||||
const availableDiffs = DIFFICULTIES.filter((d) =>
|
const availableDiffs = DIFFICULTIES.filter((d) =>
|
||||||
boss.difficulties.some((bd) => bd.difficulty === d.key)
|
boss.difficulties.some((bd) => bd.difficulty === d.key)
|
||||||
|
|
@ -168,7 +175,7 @@ export default function BossSelector({ characterName, bosses, selections, onChan
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</StaggerGroup>
|
||||||
</OverlayScrollbarsComponent>
|
</OverlayScrollbarsComponent>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue