feat: unit reveal overlay with 40-frame autoplay animation
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
useMotionValueEvent,
|
||||
useReducedMotion,
|
||||
} from 'framer-motion'
|
||||
import UnitRevealOverlay from './UnitRevealOverlay'
|
||||
|
||||
const TOTAL_FRAMES = 298
|
||||
const FRAME_PATH = (n: number) =>
|
||||
@@ -39,6 +40,7 @@ export default function CloudRevealSection() {
|
||||
const [loaded, setLoaded] = useState(false)
|
||||
const [loadProgress, setLoadProgress] = useState(0)
|
||||
const hasSnapped = useRef(false)
|
||||
const [activeUnit, setActiveUnit] = useState<{ id: string; label: string; sub: string } | null>(null)
|
||||
|
||||
const { scrollYProgress } = useScroll({
|
||||
target: sectionRef,
|
||||
@@ -228,7 +230,10 @@ export default function CloudRevealSection() {
|
||||
</motion.div>
|
||||
|
||||
{/* HOTSPOTS — son frame'de görünür */}
|
||||
<UnitHotspots scrollYProgress={scrollYProgress} />
|
||||
<UnitHotspots
|
||||
scrollYProgress={scrollYProgress}
|
||||
onSelect={(unit) => setActiveUnit(unit)}
|
||||
/>
|
||||
|
||||
{/* Progress bar */}
|
||||
<div className="absolute bottom-8 left-10 right-10 z-10 h-[2px] bg-white/10">
|
||||
@@ -237,6 +242,14 @@ export default function CloudRevealSection() {
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Unit reveal overlay */}
|
||||
<UnitRevealOverlay
|
||||
unitId={activeUnit?.id ?? null}
|
||||
unitLabel={activeUnit?.label ?? ''}
|
||||
unitSub={activeUnit?.sub ?? ''}
|
||||
onClose={() => setActiveUnit(null)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -258,8 +271,10 @@ const HOTSPOTS: {
|
||||
|
||||
function UnitHotspots({
|
||||
scrollYProgress,
|
||||
onSelect,
|
||||
}: {
|
||||
scrollYProgress: ReturnType<typeof useScroll>['scrollYProgress']
|
||||
onSelect: (unit: { id: string; label: string; sub: string }) => void
|
||||
}) {
|
||||
const containerOpacity = useTransform(scrollYProgress, [0.92, 0.98], [0, 1])
|
||||
|
||||
@@ -310,10 +325,7 @@ function UnitHotspots({
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: i * 0.2 + 0.45, duration: 0.3, ease: 'easeOut' }}
|
||||
className="pointer-events-auto bg-black/60 backdrop-blur-md border border-white/20 rounded-lg px-3 py-2 text-left hover:bg-black/80 hover:border-white/40 transition-all duration-200 active:scale-95 cursor-pointer"
|
||||
onClick={() => {
|
||||
// İleride: daire içi frame sekansını başlat
|
||||
console.log('unit clicked:', spot.id)
|
||||
}}
|
||||
onClick={() => onSelect({ id: spot.id, label: spot.label, sub: spot.sub })}
|
||||
>
|
||||
<p className="text-white text-xs font-medium tracking-wide whitespace-nowrap">{spot.label}</p>
|
||||
<p className="text-white/50 text-[10px] mt-0.5 whitespace-nowrap">{spot.sub}</p>
|
||||
|
||||
Reference in New Issue
Block a user