feat(game): 添加奖池功能支持
- 在国际化文件中添加奖池相关的翻译配置 - 定义 JackpotPoolState 和 GameJackpotPoolDto 类型接口 - 在 DashboardState 中添加 jackpotPool 字段 - 实现 normalizeJackpotPoolState 函数处理奖池数据转换 - 更新游戏 API 中的初始化和数据归一化逻辑 - 添加 Oxanium 字体依赖并配置奖池金额字体样式 - 实现 JackpotPoolTicker 组件显示动态增长的奖池金额 - 在消息广播组件中集成奖池显示功能 - 更新实时同步钩子中的奖池数据处理逻辑
This commit is contained in:
@@ -2,6 +2,7 @@ import { AnimatePresence, motion, useReducedMotion } from 'motion/react'
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import broadcast from '@/assets/system/broadcast.webp'
|
||||
import { JackpotPoolTicker } from '@/components/jackpot-pool-ticker.tsx'
|
||||
import { SmartImage } from '@/components/smart-image.tsx'
|
||||
import { cn } from '@/lib/utils.ts'
|
||||
import { useGameSessionStore } from '@/store/game'
|
||||
@@ -103,65 +104,71 @@ export function MessageBroadcast({ className }: MessageBroadcastProps) {
|
||||
aria-label={t('game.jackpotBroadcast.ariaLabel')}
|
||||
className={cn(
|
||||
'common-neon-inset flex w-full min-w-0 items-center overflow-hidden',
|
||||
'h-design-24 gap-design-5 !rounded-[3px] !px-design-7 !py-0 text-design-8',
|
||||
'md:h-design-65 md:gap-design-10 md:!rounded-[5px] md:!px-design-20 md:text-design-16',
|
||||
'h-design-24 gap-design-4 !rounded-[3px] !px-design-5 !py-0 text-design-8',
|
||||
'md:h-design-65 md:gap-design-12 md:!rounded-[5px] md:!px-design-20 md:text-design-16',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<SmartImage
|
||||
className="h-design-12 w-design-12 shrink-0 md:h-design-24 md:w-design-24"
|
||||
alt={t('game.jackpotBroadcast.iconAlt')}
|
||||
src={broadcast}
|
||||
/>
|
||||
<div className="relative h-design-16 min-w-0 flex-1 overflow-hidden md:h-design-28">
|
||||
<AnimatePresence>
|
||||
{activeBroadcast ? (
|
||||
<motion.div
|
||||
aria-label={activeBroadcastLabel}
|
||||
className="absolute inset-0 flex min-w-max items-center whitespace-nowrap font-semibold"
|
||||
key={activeBroadcast.id}
|
||||
initial={
|
||||
prefersReducedMotion
|
||||
? { opacity: 0 }
|
||||
: { opacity: 1, x: '108%' }
|
||||
}
|
||||
animate={
|
||||
prefersReducedMotion
|
||||
? { opacity: 1 }
|
||||
: { opacity: 1, x: '-108%' }
|
||||
}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{
|
||||
duration: prefersReducedMotion
|
||||
? 0.18
|
||||
: MESSAGE_BROADCAST_ANIMATION_MS / 1000,
|
||||
ease: prefersReducedMotion ? [0.16, 1, 0.3, 1] : 'linear',
|
||||
}}
|
||||
>
|
||||
<span className="text-[#D5F7FF]">
|
||||
{t('game.jackpotBroadcast.prefix')}
|
||||
</span>
|
||||
<span className="ml-design-4 text-[#4BFFFE] md:ml-design-8">
|
||||
{activeBroadcast.nickname}
|
||||
</span>
|
||||
<span className="mx-design-4 text-[#D5F7FF] md:mx-design-8">
|
||||
{t('game.jackpotBroadcast.separator')}
|
||||
</span>
|
||||
<span className="text-[#78FF7F]">
|
||||
{t('game.jackpotBroadcast.streak', {
|
||||
count: activeBroadcast.currentStreak,
|
||||
})}
|
||||
</span>
|
||||
<span className="mx-design-4 text-[#D5F7FF] md:mx-design-8">
|
||||
{t('game.jackpotBroadcast.winAction')}
|
||||
</span>
|
||||
<span className="text-[#FFB72B]">
|
||||
{formatWinAmount(activeBroadcast.totalWin)}
|
||||
</span>
|
||||
</motion.div>
|
||||
) : null}
|
||||
</AnimatePresence>
|
||||
<div className="flex min-w-0 flex-1 items-center gap-design-4 md:gap-design-10">
|
||||
<SmartImage
|
||||
className="h-design-12 w-design-12 shrink-0 md:h-design-24 md:w-design-24"
|
||||
alt={t('game.jackpotBroadcast.iconAlt')}
|
||||
src={broadcast}
|
||||
/>
|
||||
<div className="relative h-design-16 min-w-0 flex-1 overflow-hidden md:h-design-28">
|
||||
<AnimatePresence>
|
||||
{activeBroadcast ? (
|
||||
<motion.div
|
||||
aria-label={activeBroadcastLabel}
|
||||
className="absolute inset-0 flex min-w-max items-center whitespace-nowrap font-semibold"
|
||||
key={activeBroadcast.id}
|
||||
initial={
|
||||
prefersReducedMotion
|
||||
? { opacity: 0 }
|
||||
: { opacity: 1, x: '108%' }
|
||||
}
|
||||
animate={
|
||||
prefersReducedMotion
|
||||
? { opacity: 1 }
|
||||
: { opacity: 1, x: '-108%' }
|
||||
}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{
|
||||
duration: prefersReducedMotion
|
||||
? 0.18
|
||||
: MESSAGE_BROADCAST_ANIMATION_MS / 1000,
|
||||
ease: prefersReducedMotion ? [0.16, 1, 0.3, 1] : 'linear',
|
||||
}}
|
||||
>
|
||||
<span className="text-[#D5F7FF]">
|
||||
{t('game.jackpotBroadcast.prefix')}
|
||||
</span>
|
||||
<span className="ml-design-4 text-[#4BFFFE] md:ml-design-8">
|
||||
{activeBroadcast.nickname}
|
||||
</span>
|
||||
<span className="mx-design-4 text-[#D5F7FF] md:mx-design-8">
|
||||
{t('game.jackpotBroadcast.separator')}
|
||||
</span>
|
||||
<span className="text-[#78FF7F]">
|
||||
{t('game.jackpotBroadcast.streak', {
|
||||
count: activeBroadcast.currentStreak,
|
||||
})}
|
||||
</span>
|
||||
<span className="mx-design-4 text-[#D5F7FF] md:mx-design-8">
|
||||
{t('game.jackpotBroadcast.winAction')}
|
||||
</span>
|
||||
<span className="text-[#FFB72B]">
|
||||
{formatWinAmount(activeBroadcast.totalWin)}
|
||||
</span>
|
||||
</motion.div>
|
||||
) : null}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
<JackpotPoolTicker
|
||||
variant="inline"
|
||||
className="!w-fit max-w-[54%] shrink-0 md:max-w-[calc(var(--design-unit)*320)]"
|
||||
/>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user