import { useEffect, useState, useCallback } from 'react'
import { createPortal } from 'react-dom'
import { X } from 'lucide-react'
interface ConfettiPiece {
id: number
x: number
color: string
delay: number
duration: number
size: number
rotation: number
}
interface CelebrationProps {
isOpen: boolean
onClose: () => void
onReset?: () => void
}
// 生成随机纸屑
function generateConfetti(count: number): ConfettiPiece[] {
const colors = [
'var(--color-primary)', // 青色
'var(--color-success)', // 绿色
'var(--color-amber)', // 琥珀色
'#FF6B6B', // 珊瑚红
'#A78BFA', // 紫罗兰
'#FBBF24', // 金色
]
return Array.from({ length: count }, (_, i) => ({
id: i,
x: Math.random() * 100,
color: colors[Math.floor(Math.random() * colors.length)],
delay: Math.random() * 0.5,
duration: 2 + Math.random() * 2,
size: 8 + Math.random() * 8,
rotation: Math.random() * 360,
}))
}
function Confetti({ pieces }: { pieces: ConfettiPiece[] }) {
return (
{pieces.map((piece) => (
))}
)
}
function CelebrationModal({ isOpen, onClose, onReset }: CelebrationProps) {
const [confetti, setConfetti] = useState([])
useEffect(() => {
if (isOpen) {
// 生成纸屑
setConfetti(generateConfetti(60))
// 3秒后清除纸屑
const timer = setTimeout(() => setConfetti([]), 5000)
return () => clearTimeout(timer)
}
}, [isOpen])
if (!isOpen) return null
return createPortal(
<>
{/* 背景遮罩 */}
{/* 弹窗内容 */}
{/* 关闭按钮 */}
{/* 庆祝图标 */}
🎉
恭喜完成全部教程!
你已经掌握了所有知识点,太棒了!
{/* 统计信息 */}
{/* 操作按钮 */}
>,
document.body
)
}
export function Celebration() {
const [isOpen, setIsOpen] = useState(false)
const [hasShown, setHasShown] = useState(false)
// 监听完成事件
useEffect(() => {
const handleComplete = () => {
if (!hasShown) {
setIsOpen(true)
setHasShown(true)
}
}
window.addEventListener('tutorial-complete', handleComplete)
return () => window.removeEventListener('tutorial-complete', handleComplete)
}, [hasShown])
const handleClose = useCallback(() => {
setIsOpen(false)
}, [])
const handleReset = useCallback(() => {
setIsOpen(false)
// 触发重置事件
window.dispatchEvent(new CustomEvent('tutorial-reset'))
setHasShown(false)
}, [])
return (
)
}
// 触发庆祝的 hook
export function useCelebration() {
const triggerCelebration = useCallback(() => {
window.dispatchEvent(new CustomEvent('tutorial-complete'))
}, [])
return { triggerCelebration }
}