feat(game): 更新游戏状态栏和彩金池组件
- 重构桌面版状态栏布局,优化响应式设计和组件结构 - 添加hud变体类型的彩金池ticker组件,支持新的视觉样式 - 为移动版状态栏调整网格布局和间距设置 - 在多个语言包中添加彩金池促销文案 - 设置默认彩金池金额并改进计时器逻辑 - 优化移动版入口文件中的组件排列方式
This commit is contained in:
BIN
src/assets/system/jackpot-bg.png
Normal file
BIN
src/assets/system/jackpot-bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 231 KiB |
BIN
src/assets/system/jackpot-title.png
Normal file
BIN
src/assets/system/jackpot-title.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
@@ -1,11 +1,14 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import diamond from '@/assets/system/diamond.webp'
|
import diamond from '@/assets/system/diamond.webp'
|
||||||
|
import jackpotBg from '@/assets/system/jackpot-bg.png'
|
||||||
|
import jackpotTitle from '@/assets/system/jackpot-title.png'
|
||||||
import { SmartImage } from '@/components/smart-image.tsx'
|
import { SmartImage } from '@/components/smart-image.tsx'
|
||||||
import { cn } from '@/lib/utils.ts'
|
import { cn } from '@/lib/utils.ts'
|
||||||
import { useGameSessionStore } from '@/store/game'
|
import { useGameSessionStore } from '@/store/game'
|
||||||
|
|
||||||
const JACKPOT_POOL_TICK_MS = 1000
|
const JACKPOT_POOL_TICK_MS = 1000
|
||||||
|
const DEFAULT_JACKPOT_POOL_AMOUNT = 1_000_000
|
||||||
const jackpotPoolFormatter = new Intl.NumberFormat('en-US', {
|
const jackpotPoolFormatter = new Intl.NumberFormat('en-US', {
|
||||||
maximumFractionDigits: 2,
|
maximumFractionDigits: 2,
|
||||||
minimumFractionDigits: 2,
|
minimumFractionDigits: 2,
|
||||||
@@ -13,7 +16,7 @@ const jackpotPoolFormatter = new Intl.NumberFormat('en-US', {
|
|||||||
|
|
||||||
type JackpotPoolTickerProps = {
|
type JackpotPoolTickerProps = {
|
||||||
className?: string
|
className?: string
|
||||||
variant?: 'inline' | 'standalone'
|
variant?: 'hud' | 'inline' | 'standalone'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function JackpotPoolTicker({
|
export function JackpotPoolTicker({
|
||||||
@@ -24,7 +27,7 @@ export function JackpotPoolTicker({
|
|||||||
const jackpotPool = useGameSessionStore(
|
const jackpotPool = useGameSessionStore(
|
||||||
(state) => state.dashboard.jackpotPool,
|
(state) => state.dashboard.jackpotPool,
|
||||||
)
|
)
|
||||||
const poolCurrent = jackpotPool?.current ?? null
|
const poolCurrent = jackpotPool?.current ?? DEFAULT_JACKPOT_POOL_AMOUNT
|
||||||
const poolSpeedPerSecond = jackpotPool?.speedPerSecond ?? 0
|
const poolSpeedPerSecond = jackpotPool?.speedPerSecond ?? 0
|
||||||
const poolUpdatedAt = jackpotPool?.updatedAt ?? null
|
const poolUpdatedAt = jackpotPool?.updatedAt ?? null
|
||||||
const [nowMs, setNowMs] = useState(() => Date.now())
|
const [nowMs, setNowMs] = useState(() => Date.now())
|
||||||
@@ -32,7 +35,7 @@ export function JackpotPoolTicker({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setNowMs(Date.now())
|
setNowMs(Date.now())
|
||||||
|
|
||||||
if (poolCurrent === null || poolSpeedPerSecond <= 0) {
|
if (poolSpeedPerSecond <= 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,13 +46,9 @@ export function JackpotPoolTicker({
|
|||||||
return () => {
|
return () => {
|
||||||
window.clearInterval(timerId)
|
window.clearInterval(timerId)
|
||||||
}
|
}
|
||||||
}, [poolCurrent, poolSpeedPerSecond])
|
}, [poolSpeedPerSecond])
|
||||||
|
|
||||||
const displayAmount = useMemo(() => {
|
const displayAmount = useMemo(() => {
|
||||||
if (poolCurrent === null) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatedAtMs = poolUpdatedAt ? Date.parse(poolUpdatedAt) : Number.NaN
|
const updatedAtMs = poolUpdatedAt ? Date.parse(poolUpdatedAt) : Number.NaN
|
||||||
const baseTimeMs = Number.isFinite(updatedAtMs) ? updatedAtMs : nowMs
|
const baseTimeMs = Number.isFinite(updatedAtMs) ? updatedAtMs : nowMs
|
||||||
const elapsedSeconds = Math.max(0, (nowMs - baseTimeMs) / 1000)
|
const elapsedSeconds = Math.max(0, (nowMs - baseTimeMs) / 1000)
|
||||||
@@ -57,11 +56,8 @@ export function JackpotPoolTicker({
|
|||||||
return poolCurrent + elapsedSeconds * poolSpeedPerSecond
|
return poolCurrent + elapsedSeconds * poolSpeedPerSecond
|
||||||
}, [nowMs, poolCurrent, poolSpeedPerSecond, poolUpdatedAt])
|
}, [nowMs, poolCurrent, poolSpeedPerSecond, poolUpdatedAt])
|
||||||
|
|
||||||
if (displayAmount === null) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const amountLabel = jackpotPoolFormatter.format(displayAmount)
|
const amountLabel = jackpotPoolFormatter.format(displayAmount)
|
||||||
|
const isHud = variant === 'hud'
|
||||||
const isInline = variant === 'inline'
|
const isInline = variant === 'inline'
|
||||||
const amountCharacterCounts = new Map<string, number>()
|
const amountCharacterCounts = new Map<string, number>()
|
||||||
const amountCharacterItems = Array.from(amountLabel).map((character) => {
|
const amountCharacterItems = Array.from(amountLabel).map((character) => {
|
||||||
@@ -75,6 +71,96 @@ export function JackpotPoolTicker({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (isHud) {
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
aria-label={t('game.jackpotPool.ariaLabel', { amount: amountLabel })}
|
||||||
|
className={cn(
|
||||||
|
'relative min-w-0 shrink-0 overflow-hidden whitespace-nowrap bg-center bg-no-repeat',
|
||||||
|
'h-design-55 w-design-126 px-design-7 pb-design-4 pt-design-3',
|
||||||
|
'md:h-design-150 md:w-design-340 md:px-design-22 md:pb-design-14 md:pt-design-12',
|
||||||
|
'[background-size:100%_100%]',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
style={{ backgroundImage: `url(${jackpotBg})` }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute left-[12%] top-[25%] h-[2px] w-[23%] bg-gradient-to-r from-transparent via-[#27DFFF] to-transparent shadow-[0_0_calc(var(--design-unit)*8)_rgba(39,223,255,0.9)]"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute right-[12%] top-[25%] h-[2px] w-[23%] bg-gradient-to-r from-transparent via-[#27DFFF] to-transparent shadow-[0_0_calc(var(--design-unit)*8)_rgba(39,223,255,0.9)]"
|
||||||
|
/>
|
||||||
|
<div className="absolute left-1/2 top-[9%] z-10 flex -translate-x-1/2 flex-col items-center leading-none">
|
||||||
|
<span className="text-design-4 font-black uppercase tracking-[0.16em] text-[#EAF8FC] [text-shadow:0_calc(var(--design-unit)*1)_0_rgba(4,35,51,0.96),0_0_calc(var(--design-unit)*5)_rgba(174,237,255,0.52)] md:text-design-15 md:tracking-[0.22em]">
|
||||||
|
{t('game.jackpotPool.promoLine1')}
|
||||||
|
</span>
|
||||||
|
<span className="mt-design-1 text-design-4 font-black uppercase tracking-[0.16em] text-[#EAF8FC] [text-shadow:0_calc(var(--design-unit)*1)_0_rgba(4,35,51,0.96),0_0_calc(var(--design-unit)*5)_rgba(174,237,255,0.52)] md:text-design-13 md:tracking-[0.22em]">
|
||||||
|
{t('game.jackpotPool.promoLine2')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<img
|
||||||
|
alt=""
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute inset-x-[6%] top-[30%] z-10 h-auto w-[88%] object-contain drop-shadow-[0_calc(var(--design-unit)*4)_0_rgba(0,45,68,0.95)]"
|
||||||
|
src={jackpotTitle}
|
||||||
|
/>
|
||||||
|
<div className="absolute left-1/2 top-[66%] z-10 flex h-[25%] w-[82%] -translate-x-1/2 items-center justify-center">
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute inset-0 h-full w-full"
|
||||||
|
focusable="false"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
viewBox="0 0 1000 180"
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<filter
|
||||||
|
colorInterpolationFilters="sRGB"
|
||||||
|
height="160%"
|
||||||
|
id="jackpotAmountFrameGlow"
|
||||||
|
width="116%"
|
||||||
|
x="-8%"
|
||||||
|
y="-30%"
|
||||||
|
>
|
||||||
|
<feDropShadow
|
||||||
|
dx="0"
|
||||||
|
dy="0"
|
||||||
|
floodColor="#28f8ff"
|
||||||
|
floodOpacity="0.58"
|
||||||
|
stdDeviation="1"
|
||||||
|
/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<polygon
|
||||||
|
filter="url(#jackpotAmountFrameGlow)"
|
||||||
|
fill="rgba(0, 14, 24, 0.44)"
|
||||||
|
points="32,1 968,1 999,32 999,148 968,179 32,179 1,148 1,32"
|
||||||
|
stroke="#29F5FF"
|
||||||
|
strokeWidth="1"
|
||||||
|
vectorEffect="non-scaling-stroke"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute z-10 translate-y-[1%] font-jackpot-amount text-design-14 font-normal leading-none tabular-nums tracking-[0.025em] md:text-design-37"
|
||||||
|
style={{
|
||||||
|
WebkitTextFillColor: '#72F9FF',
|
||||||
|
WebkitTextStroke: 'calc(var(--design-unit) * 0.5) #C9FFFF',
|
||||||
|
fontVariationSettings: '"wght" 450',
|
||||||
|
filter:
|
||||||
|
'drop-shadow(0 0 calc(var(--design-unit) * 1.8) rgba(45, 255, 255, 0.9)) drop-shadow(0 0 calc(var(--design-unit) * 4) rgba(31, 235, 255, 0.5))',
|
||||||
|
textShadow:
|
||||||
|
'0 calc(var(--design-unit) * 1) 0 rgba(0, 38, 48, 0.82)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
${amountLabel}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
aria-label={t('game.jackpotPool.ariaLabel', { amount: amountLabel })}
|
aria-label={t('game.jackpotPool.ariaLabel', { amount: amountLabel })}
|
||||||
|
|||||||
@@ -42,194 +42,196 @@ export function DesktopStatusLine() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'relative w-full flex flex-col text-design-22'}>
|
<div className="relative w-full text-design-22">
|
||||||
<div className={'w-full px-design-16 mb-design-10'}>
|
<div className="flex w-full items-start gap-design-14 px-design-16">
|
||||||
<MessageBroadcast showJackpotPool={false} />
|
<div className="flex min-w-0 flex-1 flex-col">
|
||||||
</div>
|
<div className="mb-design-10 w-full">
|
||||||
<SmartBackground
|
<MessageBroadcast showJackpotPool={false} />
|
||||||
src={statusLine}
|
</div>
|
||||||
size="100% 100%"
|
<SmartBackground
|
||||||
className="w-full h-design-75 bg-no-repeat bg-center flex items-center justify-center"
|
src={statusLine}
|
||||||
>
|
size="100% 100%"
|
||||||
{/* 状态栏左侧 */}
|
className="flex h-design-75 w-full items-center justify-center bg-center bg-no-repeat"
|
||||||
<div
|
>
|
||||||
className={
|
{/* 状态栏左侧 */}
|
||||||
'relative h-full flex-1 flex items-center justify-center gap-design-50 overflow-visible'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{showStreakLimitOnly && (
|
|
||||||
<div
|
<div
|
||||||
className={'pointer-events-none absolute bg-center bg-no-repeat'}
|
className={
|
||||||
style={{
|
'relative flex h-full w-design-760 shrink-0 items-center justify-center gap-design-64 overflow-visible'
|
||||||
top: 'calc(var(--design-unit)*-14)',
|
}
|
||||||
right: 'calc(var(--design-unit)*-190)',
|
>
|
||||||
bottom: 'calc(var(--design-unit)*-1)',
|
{showStreakLimitOnly && (
|
||||||
left: 0,
|
<div
|
||||||
backgroundImage: `url(${streakBg})`,
|
className={
|
||||||
backgroundPosition: 'center',
|
'pointer-events-none absolute bg-center bg-no-repeat'
|
||||||
backgroundSize: '113% 150%',
|
}
|
||||||
}}
|
style={{
|
||||||
/>
|
top: 'calc(var(--design-unit)*-14)',
|
||||||
)}
|
right: 'calc(var(--design-unit)*-190)',
|
||||||
|
bottom: 'calc(var(--design-unit)*-1)',
|
||||||
|
left: 0,
|
||||||
|
backgroundImage: `url(${streakBg})`,
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
backgroundSize: '113% 150%',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!showStreakLimitOnly && (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
'shrink-0 whitespace-nowrap font-bold text-[#CBD3D5]'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{t('gameDesktop.status.odds')}:{' '}
|
||||||
|
<span className={'text-[#E3D171]'}>{oddsLabel}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
'flex shrink-0 items-center gap-design-5 whitespace-nowrap font-bold text-[#CBD3D5]'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SmartImage
|
||||||
|
className={'w-design-37 h-design-47'}
|
||||||
|
alt={'fire'}
|
||||||
|
src={fire}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
{t('gameDesktop.status.streak')}:{' '}
|
||||||
|
<span
|
||||||
|
className={
|
||||||
|
'bg-gradient-to-b from-[#EBA661] to-[#FCC785] bg-clip-text text-transparent'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{streakLabel}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{!showStreakLimitOnly && (
|
|
||||||
<>
|
|
||||||
<div className={'text-[#CBD3D5] font-bold'}>
|
|
||||||
{t('gameDesktop.status.odds')}:{' '}
|
|
||||||
<span className={'text-[#E3D171]'}>{oddsLabel}</span>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'flex items-center gap-design-5 text-[#CBD3D5] font-bold'
|
'relative z-20 flex shrink-0 items-center gap-design-5 whitespace-nowrap font-bold text-[#CBD3D5]'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SmartImage
|
<SmartImage
|
||||||
className={'w-design-37 h-design-47'}
|
className={'w-design-25 h-design-33'}
|
||||||
alt={'fire'}
|
alt={'lock'}
|
||||||
src={fire}
|
src={lock}
|
||||||
/>
|
/>
|
||||||
<div>
|
<div className={'flex items-center gap-design-10'}>
|
||||||
{t('gameDesktop.status.streak')}:{' '}
|
<div>{t('gameDesktop.status.limit')}:</div>
|
||||||
<span
|
<div className={'flex items-center gap-design-5'}>
|
||||||
className={
|
<SmartImage
|
||||||
'bg-gradient-to-b from-[#EBA661] to-[#FCC785] bg-clip-text text-transparent'
|
className={'w-design-35 h-design-35'}
|
||||||
}
|
alt={'diamond'}
|
||||||
>
|
src={diamond}
|
||||||
{streakLabel}
|
/>
|
||||||
</span>
|
<div>{limitLabel}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
)}
|
|
||||||
|
|
||||||
<div
|
<div className="relative z-20 flex h-[105px] w-design-360 items-center justify-center">
|
||||||
className={
|
<SmartBackground
|
||||||
'relative z-20 flex items-center gap-design-5 text-[#CBD3D5] font-bold'
|
src={statusCenter}
|
||||||
}
|
className="pointer-events-none absolute inset-0 bg-no-repeat bg-center bg-contain transition-opacity duration-500 ease-out"
|
||||||
>
|
size="contain"
|
||||||
<SmartImage
|
style={{
|
||||||
className={'w-design-25 h-design-33'}
|
opacity: showWarningCountdown ? 0.18 : 1,
|
||||||
alt={'lock'}
|
transform: showWarningCountdown ? 'scale(0.985)' : 'scale(1)',
|
||||||
src={lock}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className={'flex items-center gap-design-10'}>
|
<div
|
||||||
<div>{t('gameDesktop.status.limit')}:</div>
|
className="pointer-events-none absolute inset-0 overflow-visible transition-all duration-500 ease-out"
|
||||||
<div className={'flex items-center gap-design-5'}>
|
style={{
|
||||||
<SmartImage
|
opacity: showWarningCountdown ? 1 : 0,
|
||||||
className={'w-design-35 h-design-35'}
|
transform: showWarningCountdown
|
||||||
alt={'diamond'}
|
? 'scale(1.1) translateY(calc(var(--design-unit)*1))'
|
||||||
src={diamond}
|
: 'scale(1.02) translateY(0)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LottiePlayer
|
||||||
|
animationData={down5Animation}
|
||||||
|
className="h-full w-full"
|
||||||
|
loop
|
||||||
|
autoplay
|
||||||
/>
|
/>
|
||||||
<div>{limitLabel}</div>
|
</div>
|
||||||
|
<DesktopCountdown
|
||||||
|
initialMs={countdownMs}
|
||||||
|
onRemainingMsChange={setRemainingMs}
|
||||||
|
className={countdownClassName}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="grid min-w-0 w-design-374 shrink-0 grid-cols-[minmax(0,0.78fr)_minmax(0,1.22fr)] items-center justify-items-stretch pl-design-6 pr-design-16">
|
||||||
|
<div className="flex min-w-0 items-center justify-center gap-design-6">
|
||||||
|
<span className="relative flex h-design-24 w-design-24 items-center justify-center">
|
||||||
|
<motion.span
|
||||||
|
aria-hidden="true"
|
||||||
|
className="absolute h-design-24 w-design-24 rounded-full bg-[rgba(120,255,127,0.22)] blur-[calc(var(--design-unit)*3)]"
|
||||||
|
animate={
|
||||||
|
prefersReducedMotion
|
||||||
|
? undefined
|
||||||
|
: {
|
||||||
|
opacity: [0.36, 0.88, 0.42],
|
||||||
|
scale: [0.9, 1.28, 0.98],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transition={
|
||||||
|
prefersReducedMotion
|
||||||
|
? undefined
|
||||||
|
: {
|
||||||
|
duration: 1.25,
|
||||||
|
ease: 'easeInOut',
|
||||||
|
repeat: Number.POSITIVE_INFINITY,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<motion.span
|
||||||
|
aria-hidden="true"
|
||||||
|
className="relative h-design-14 w-design-14 rounded-full bg-[#78FF7F] shadow-[0_0_calc(var(--design-unit)*8)_rgba(120,255,127,0.78),0_0_calc(var(--design-unit)*16)_rgba(120,255,127,0.34)]"
|
||||||
|
animate={
|
||||||
|
prefersReducedMotion
|
||||||
|
? undefined
|
||||||
|
: { opacity: [0.78, 1, 0.86], scale: [0.96, 1.12, 1] }
|
||||||
|
}
|
||||||
|
transition={
|
||||||
|
prefersReducedMotion
|
||||||
|
? undefined
|
||||||
|
: {
|
||||||
|
duration: 1.25,
|
||||||
|
ease: 'easeInOut',
|
||||||
|
repeat: Number.POSITIVE_INFINITY,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
phaseToneClassName,
|
||||||
|
'font-black tracking-[0.08em] [text-shadow:0_0_calc(var(--design-unit)*10)_rgba(120,255,127,0.44)]',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{phaseLabel}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex min-w-0 items-baseline justify-center gap-design-5 font-bold leading-none">
|
||||||
|
<span className="text-design-20 tracking-[0.06em] text-[#9FBAC0]">
|
||||||
|
{t('gameDesktop.status.roundId')}:
|
||||||
|
</span>
|
||||||
|
<span className="min-w-0 truncate text-design-24 font-black tracking-[0.06em] text-[#E7FFFF] [text-shadow:0_0_calc(var(--design-unit)*9)_rgba(75,255,254,0.38)]">
|
||||||
|
{roundId}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</SmartBackground>
|
||||||
</div>
|
</div>
|
||||||
|
<JackpotPoolTicker className="mt-design-0" variant="hud" />
|
||||||
<div className="relative z-20 flex h-[105px] w-design-360 items-center justify-center">
|
</div>
|
||||||
<SmartBackground
|
|
||||||
src={statusCenter}
|
|
||||||
className="pointer-events-none absolute inset-0 bg-no-repeat bg-center bg-contain transition-opacity duration-500 ease-out"
|
|
||||||
size="contain"
|
|
||||||
style={{
|
|
||||||
opacity: showWarningCountdown ? 0.18 : 1,
|
|
||||||
transform: showWarningCountdown ? 'scale(0.985)' : 'scale(1)',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
className="pointer-events-none absolute inset-0 overflow-visible transition-all duration-500 ease-out"
|
|
||||||
style={{
|
|
||||||
opacity: showWarningCountdown ? 1 : 0,
|
|
||||||
transform: showWarningCountdown
|
|
||||||
? 'scale(1.1) translateY(calc(var(--design-unit)*1))'
|
|
||||||
: 'scale(1.02) translateY(0)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<LottiePlayer
|
|
||||||
animationData={down5Animation}
|
|
||||||
className="h-full w-full"
|
|
||||||
loop
|
|
||||||
autoplay
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<DesktopCountdown
|
|
||||||
initialMs={countdownMs}
|
|
||||||
onRemainingMsChange={setRemainingMs}
|
|
||||||
className={countdownClassName}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="grid min-w-0 flex-1 grid-cols-[repeat(3,minmax(0,1fr))] items-center justify-items-stretch pl-design-6 pr-design-16">
|
|
||||||
<div className="flex min-w-0 items-center justify-center gap-design-6">
|
|
||||||
<span className="relative flex h-design-24 w-design-24 items-center justify-center">
|
|
||||||
<motion.span
|
|
||||||
aria-hidden="true"
|
|
||||||
className="absolute h-design-24 w-design-24 rounded-full bg-[rgba(120,255,127,0.22)] blur-[calc(var(--design-unit)*3)]"
|
|
||||||
animate={
|
|
||||||
prefersReducedMotion
|
|
||||||
? undefined
|
|
||||||
: { opacity: [0.36, 0.88, 0.42], scale: [0.9, 1.28, 0.98] }
|
|
||||||
}
|
|
||||||
transition={
|
|
||||||
prefersReducedMotion
|
|
||||||
? undefined
|
|
||||||
: {
|
|
||||||
duration: 1.25,
|
|
||||||
ease: 'easeInOut',
|
|
||||||
repeat: Number.POSITIVE_INFINITY,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<motion.span
|
|
||||||
aria-hidden="true"
|
|
||||||
className="relative h-design-14 w-design-14 rounded-full bg-[#78FF7F] shadow-[0_0_calc(var(--design-unit)*8)_rgba(120,255,127,0.78),0_0_calc(var(--design-unit)*16)_rgba(120,255,127,0.34)]"
|
|
||||||
animate={
|
|
||||||
prefersReducedMotion
|
|
||||||
? undefined
|
|
||||||
: { opacity: [0.78, 1, 0.86], scale: [0.96, 1.12, 1] }
|
|
||||||
}
|
|
||||||
transition={
|
|
||||||
prefersReducedMotion
|
|
||||||
? undefined
|
|
||||||
: {
|
|
||||||
duration: 1.25,
|
|
||||||
ease: 'easeInOut',
|
|
||||||
repeat: Number.POSITIVE_INFINITY,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
phaseToneClassName,
|
|
||||||
'font-black tracking-[0.08em] [text-shadow:0_0_calc(var(--design-unit)*10)_rgba(120,255,127,0.44)]',
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{phaseLabel}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex min-w-0 items-baseline justify-center gap-design-5 font-bold leading-none">
|
|
||||||
<span className="text-design-20 tracking-[0.06em] text-[#9FBAC0]">
|
|
||||||
{t('gameDesktop.status.roundId')}:
|
|
||||||
</span>
|
|
||||||
<span className="min-w-0 truncate text-design-24 font-black tracking-[0.06em] text-[#E7FFFF] [text-shadow:0_0_calc(var(--design-unit)*9)_rgba(75,255,254,0.38)]">
|
|
||||||
{roundId}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex min-w-0 items-center justify-center">
|
|
||||||
<JackpotPoolTicker
|
|
||||||
variant="inline"
|
|
||||||
className={cn(
|
|
||||||
'!h-design-52 !w-full max-w-full justify-center !px-design-5 md:!px-design-6',
|
|
||||||
'[&>div:first-child]:md:!mr-design-5 [&>div:first-child]:md:!h-design-20 [&>div:first-child]:md:!w-design-20',
|
|
||||||
'[&>span:first-of-type]:md:!mr-[20px] [&>span:first-of-type]:md:!text-design-10',
|
|
||||||
'[&>span:last-child]:!shrink-0 [&>span:last-child]:!text-design-9 md:[&>span:last-child]:!text-design-20',
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SmartBackground>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,28 +166,26 @@ export function MobileStatusMetrics() {
|
|||||||
<SmartBackground
|
<SmartBackground
|
||||||
src={statusLine}
|
src={statusLine}
|
||||||
size="100% 100%"
|
size="100% 100%"
|
||||||
className="relative flex h-design-26 w-full items-center overflow-visible bg-center bg-no-repeat px-design-10 font-bold leading-none text-[#CBD3D5]"
|
className="relative grid h-design-26 w-full grid-cols-3 items-center overflow-visible bg-center bg-no-repeat px-design-3 font-bold leading-none text-[#CBD3D5]"
|
||||||
style={{ fontSize: 'calc(var(--design-unit) * 7)' }}
|
style={{ fontSize: 'calc(var(--design-unit) * 5.5)' }}
|
||||||
>
|
>
|
||||||
{showStreakLimitOnly ? (
|
{showStreakLimitOnly ? (
|
||||||
<div
|
<div
|
||||||
className="pointer-events-none absolute left-0 right-0 z-0 bg-center bg-no-repeat opacity-95"
|
className="pointer-events-none absolute bottom-[calc(var(--design-unit)*-5)] left-0 right-[33.333%] top-[calc(var(--design-unit)*-6)] z-0 bg-center bg-no-repeat opacity-95"
|
||||||
style={{
|
style={{
|
||||||
backgroundImage: `url(${streakBg})`,
|
backgroundImage: `url(${streakBg})`,
|
||||||
backgroundSize: '120% 150%',
|
backgroundSize: '120% 150%',
|
||||||
bottom: 'calc(var(--design-unit)*-5)',
|
|
||||||
top: 'calc(var(--design-unit)*-6)',
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="relative z-10 flex min-w-0 flex-1 items-center justify-center">
|
<div className="relative z-10 flex min-w-0 items-center justify-center whitespace-nowrap">
|
||||||
{t('gameDesktop.status.odds')}:
|
{t('gameDesktop.status.odds')}:
|
||||||
<span className="ml-design-3 text-[#E3D171]">{oddsLabel}</span>
|
<span className="ml-design-1 text-[#E3D171]">{oddsLabel}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative z-10 flex min-w-0 flex-1 items-center justify-center gap-design-2">
|
<div className="relative z-10 flex min-w-0 items-center justify-center gap-design-1 whitespace-nowrap">
|
||||||
<SmartImage
|
<SmartImage
|
||||||
className="h-design-11 w-design-9"
|
className="h-design-8 w-design-7"
|
||||||
alt="fire"
|
alt="fire"
|
||||||
src={fire}
|
src={fire}
|
||||||
/>
|
/>
|
||||||
@@ -198,11 +196,11 @@ export function MobileStatusMetrics() {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div className="relative z-10 flex min-w-0 flex-1 items-center justify-center gap-design-2">
|
<div className="relative z-10 col-start-3 flex min-w-0 items-center justify-center gap-design-1 whitespace-nowrap">
|
||||||
<SmartImage className="h-design-10 w-design-8" alt="lock" src={lock} />
|
<SmartImage className="h-design-8 w-design-6" alt="lock" src={lock} />
|
||||||
<span>{t('gameDesktop.status.limit')}:</span>
|
<span>{t('gameDesktop.status.limit')}:</span>
|
||||||
<SmartImage
|
<SmartImage
|
||||||
className="h-design-10 w-design-10"
|
className="h-design-8 w-design-8"
|
||||||
alt="diamond"
|
alt="diamond"
|
||||||
src={diamond}
|
src={diamond}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -182,6 +182,8 @@ export default {
|
|||||||
ariaLabel: 'Current jackpot pool {{amount}}',
|
ariaLabel: 'Current jackpot pool {{amount}}',
|
||||||
iconAlt: 'Jackpot pool',
|
iconAlt: 'Jackpot pool',
|
||||||
label: 'Jackpot',
|
label: 'Jackpot',
|
||||||
|
promoLine1: 'Streak Win 10 Rounds',
|
||||||
|
promoLine2: 'And Hit The Super',
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
unifiedBetHint: 'Unified bet',
|
unifiedBetHint: 'Unified bet',
|
||||||
|
|||||||
@@ -181,6 +181,8 @@ export default {
|
|||||||
ariaLabel: 'Pool jackpot saat ini {{amount}}',
|
ariaLabel: 'Pool jackpot saat ini {{amount}}',
|
||||||
iconAlt: 'Pool jackpot',
|
iconAlt: 'Pool jackpot',
|
||||||
label: 'Jackpot',
|
label: 'Jackpot',
|
||||||
|
promoLine1: 'Menang 10 Ronde Beruntun',
|
||||||
|
promoLine2: 'Dan Raih Super Jackpot',
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
unifiedBetHint: 'Bet seragam',
|
unifiedBetHint: 'Bet seragam',
|
||||||
|
|||||||
@@ -184,6 +184,8 @@ export default {
|
|||||||
ariaLabel: 'Dana jackpot semasa {{amount}}',
|
ariaLabel: 'Dana jackpot semasa {{amount}}',
|
||||||
iconAlt: 'Dana jackpot',
|
iconAlt: 'Dana jackpot',
|
||||||
label: 'Jackpot',
|
label: 'Jackpot',
|
||||||
|
promoLine1: '10 Kemenangan Berturut',
|
||||||
|
promoLine2: 'Dan Raih Super Jackpot',
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
unifiedBetHint: 'Taruhan seragam',
|
unifiedBetHint: 'Taruhan seragam',
|
||||||
|
|||||||
@@ -179,6 +179,8 @@ export default {
|
|||||||
ariaLabel: '彩金池当前金额 {{amount}}',
|
ariaLabel: '彩金池当前金额 {{amount}}',
|
||||||
iconAlt: '彩金池',
|
iconAlt: '彩金池',
|
||||||
label: '彩金池',
|
label: '彩金池',
|
||||||
|
promoLine1: '连胜 10 局',
|
||||||
|
promoLine2: '并触发超级大奖',
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
unifiedBetHint: '统一下注额',
|
unifiedBetHint: '统一下注额',
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { JackpotPoolTicker } from '@/components/jackpot-pool-ticker.tsx'
|
||||||
import { MessageBroadcast } from '@/components/message-broadcast.tsx'
|
import { MessageBroadcast } from '@/components/message-broadcast.tsx'
|
||||||
import { MobileAnimal } from '@/features/game/components/mobile/mobile-animal.tsx'
|
import { MobileAnimal } from '@/features/game/components/mobile/mobile-animal.tsx'
|
||||||
import { MobileBettingStartAlert } from '@/features/game/components/mobile/mobile-betting-start-alert.tsx'
|
import { MobileBettingStartAlert } from '@/features/game/components/mobile/mobile-betting-start-alert.tsx'
|
||||||
@@ -12,11 +13,12 @@ export function MobileEntry() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<MobileHeader />
|
<MobileHeader />
|
||||||
<div className="w-full px-design-10 mb-design-5">
|
<div className="mx-auto mb-design-5 flex h-design-55 w-[calc(100%-20*var(--design-unit))] items-stretch gap-design-5">
|
||||||
<MessageBroadcast />
|
<div className="flex min-w-0 flex-1 flex-col gap-design-5">
|
||||||
</div>
|
<MessageBroadcast showJackpotPool={false} />
|
||||||
<div className="mx-auto mb-design-5 w-[calc(100%-20*var(--design-unit))]">
|
<MobileStatusMetrics />
|
||||||
<MobileStatusMetrics />
|
</div>
|
||||||
|
<JackpotPoolTicker variant="hud" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<main className="mx-auto flex w-[calc(100%-20*var(--design-unit))] flex-col gap-design-5 pb-design-8">
|
<main className="mx-auto flex w-[calc(100%-20*var(--design-unit))] flex-col gap-design-5 pb-design-8">
|
||||||
|
|||||||
Reference in New Issue
Block a user