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 { 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 에 넘겨 유지.
|
||||
* 기본값은 프로미스나인 사이트와 동일 (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 }) {
|
||||
export default function StaggerGroup({
|
||||
children,
|
||||
className,
|
||||
style,
|
||||
staggerDelay = 0.1,
|
||||
yOffset = 30,
|
||||
duration = 0.4,
|
||||
}) {
|
||||
const containerVariants = {
|
||||
hidden: {},
|
||||
show: { transition: { staggerChildren: staggerDelay } },
|
||||
}
|
||||
|
||||
const itemVariants = {
|
||||
hidden: { opacity: 0, y: yOffset },
|
||||
show: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration },
|
||||
},
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className={className}
|
||||
|
|
|
|||
|
|
@ -73,9 +73,9 @@ export default function BossCrystal() {
|
|||
return (
|
||||
<motion.div
|
||||
className="h-full"
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.35, ease: [0.22, 1, 0.36, 1] }}
|
||||
transition={{ duration: 0.4 }}
|
||||
>
|
||||
{isLoading ? (
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'
|
||||
import Select from '../../../../components/common/Select'
|
||||
import StaggerGroup from '../../../../components/common/StaggerGroup'
|
||||
import { DIFFICULTIES, formatMeso } from '../admin/constants'
|
||||
|
||||
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
|
||||
>
|
||||
<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) => {
|
||||
const availableDiffs = DIFFICULTIES.filter((d) =>
|
||||
boss.difficulties.some((bd) => bd.difficulty === d.key)
|
||||
|
|
@ -168,7 +175,7 @@ export default function BossSelector({ characterName, bosses, selections, onChan
|
|||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</StaggerGroup>
|
||||
</OverlayScrollbarsComponent>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue