feat(game): 重构游戏组件并新增自动设置模态框

- 将多个组件中的背景图片样式替换为 SmartBackground 组件
- 在 CenterModal 中新增 isShowClose 属性控制关闭按钮显示
- 新增 DesktopAutoSettingModal 组件实现自动设置功能
- 新增 DesktopProceduresModal 和 DesktopWithdrawTopupModal 组件
- 配置 shadcn/ui 并集成 Geist 字体和动画库
- 更新 CSS 样式添加暗色主题变量和输入框样式
- 修复 utils 导入路径错误问题
This commit is contained in:
JiaJun
2026-05-08 17:56:06 +08:00
parent 9ee3192c49
commit 7622d4121f
35 changed files with 4184 additions and 137 deletions

View File

@@ -1,5 +1,5 @@
import { SmartImage } from '@/components/smart-image'
import { cn } from '@/lib/untils'
import { cn } from '@/lib/utils'
const animalModules = import.meta.glob('../../../../assets/animal/*.webp', {
eager: true,

View File

@@ -9,9 +9,10 @@ import controlBg from '@/assets/game/control-bg.png'
import leftBottomBg from '@/assets/game/left-bg.webp'
import reduce from '@/assets/game/reduce.webp'
import totalBg from '@/assets/game/total-bg.webp'
import { SmartBackground } from '@/components/smart-background.tsx'
import { SmartImage } from '@/components/smart-image.tsx'
import { ACTION_OPTIONS, CHIP_OPTIONS } from '@/constants'
import { cn } from '@/lib/untils.ts'
import { cn } from '@/lib/utils'
export function DesktopControl() {
const [chips, setChips] = useState(CHIP_OPTIONS)
@@ -66,14 +67,12 @@ export function DesktopControl() {
'flex h-design-100 w-full items-center gap-design-12 overflow-hidden'
}
>
<div
<SmartBackground
src={leftBottomBg}
size="100% 100%"
className={
'flex flex-col items-center gap-1 justify-center h-full w-design-110 shrink-0 bg-center bg-no-repeat'
}
style={{
backgroundImage: `url(${leftBottomBg})`,
backgroundSize: '100% 100%',
}}
>
<div className={'flex flex-col items-center justify-center'}>
<div>TREBD</div>
@@ -84,21 +83,17 @@ export function DesktopControl() {
alt={`animal`}
className={'w-design-20 h-design-10'}
/>
</div>
<div
</SmartBackground>
<SmartBackground
src={chipBg}
size="100% 100%"
className={
'desktop-control-chip relative z-10 flex h-full w-design-710 shrink-0 items-center gap-design-10 pl-design-20 pr-design-40 bg-center bg-no-repeat'
}
style={{
backgroundImage: `url(${chipBg})`,
backgroundSize: '100% 100%',
}}
>
<div
style={{
backgroundImage: `url(${chipLineBg})`,
backgroundSize: '100% 100%',
}}
<SmartBackground
src={chipLineBg}
size="100% 100%"
className={
'flex min-w-0 flex-1 items-center gap-design-10 overflow-visible'
}
@@ -215,7 +210,7 @@ export function DesktopControl() {
</motion.button>
)
})}
</div>
</SmartBackground>
<div
className={
@@ -238,27 +233,23 @@ export function DesktopControl() {
className={'w-design-40 h-design-40'}
/>
</div>
</div>
<div
</SmartBackground>
<SmartBackground
src={totalBg}
size="100% 100%"
className={
'desktop-control-total relative flex flex-col items-center justify-center z-10 h-full w-design-435 shrink-0 bg-center bg-no-repeat'
}
style={{
backgroundImage: `url(${totalBg})`,
backgroundSize: '100% 100%',
}}
>
<div>SELECTED:3/5</div>
<div>Total Bet150</div>
</div>
<div
</SmartBackground>
<SmartBackground
src={controlBg}
size="100% 100%"
className={cn(
'desktop-control-actions relative z-10 flex h-full w-design-385 shrink-0 items-center bg-center bg-no-repeat pl-design-15',
)}
style={{
backgroundImage: `url(${controlBg})`,
backgroundSize: '100% 100%',
}}
>
{ACTION_OPTIONS.map(({ id, label, Icon, bg }) => {
const isClicked = clickedId === id
@@ -278,25 +269,25 @@ export function DesktopControl() {
)}
>
{showBg && (
<motion.span
<SmartBackground
as={motion.span}
initial={{ opacity: 0 }}
animate={isClicked ? { opacity: 1 } : { opacity: 0 }}
transition={{
duration: isClicked ? 0.15 : 0.18,
ease: 'easeOut',
}}
src={bg}
className={cn(
'pointer-events-none absolute bg-center inset-0 bg-no-repeat h-design-100',
)}
style={{
backgroundImage: `url(${bg})`,
backgroundSize:
id === 'clear'
? '110% 90%'
: id === 'repeat'
? '98% 80%'
: '96% 80%',
}}
size={
id === 'clear'
? '110% 90%'
: id === 'repeat'
? '98% 80%'
: '96% 80%'
}
/>
)}
<motion.div
@@ -331,8 +322,11 @@ export function DesktopControl() {
</motion.button>
)
})}
</div>
<motion.button
</SmartBackground>
<SmartBackground
as={motion.button}
src={confirmBg}
size="100% 100%"
type="button"
onClick={handleConfirmClick}
whileHover={{ scale: 1.01 }}
@@ -340,22 +334,17 @@ export function DesktopControl() {
className={cn(
'relative z-10 h-full w-design-260 shrink-0 cursor-pointer bg-center bg-no-repeat flex items-center justify-center text-design-32 font-bold',
)}
style={{
backgroundImage: `url(${confirmBg})`,
backgroundSize: '100% 100%',
}}
>
{confirmClicked && (
<motion.span
<SmartBackground
as={motion.span}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.15 }}
className="pointer-events-none absolute inset-0 bg-center bg-no-repeat"
style={{
backgroundImage: `url(${confirmBg})`,
backgroundSize: '100% 100%',
}}
src={confirmBg}
size="100% 100%"
/>
)}
<motion.span
@@ -365,7 +354,7 @@ export function DesktopControl() {
>
confirm
</motion.span>
</motion.button>
</SmartBackground>
</div>
)
}

View File

@@ -1,7 +1,7 @@
import dayjs from 'dayjs'
import duration from 'dayjs/plugin/duration'
import { useEffect, useMemo, useState } from 'react'
import { cn } from '@/lib/untils'
import { cn } from '@/lib/utils'
dayjs.extend(duration)

View File

@@ -1,4 +1,5 @@
import historyBg from '@/assets/system/history-bg.png'
import { SmartBackground } from '@/components/smart-background.tsx'
export function DesktopGameHistory() {
const data = [
@@ -115,12 +116,10 @@ export function DesktopGameHistory() {
]
return (
<div
<SmartBackground
src={historyBg}
size="100% 100%"
className="desktop-game-history-glow flex h-full min-h-0 w-full flex-col items-center overflow-hidden bg-center bg-no-repeat py-2"
style={{
backgroundImage: `url(${historyBg})`,
backgroundSize: '100% 100%',
}}
>
<div
className={
@@ -178,6 +177,6 @@ export function DesktopGameHistory() {
)
})}
</div>
</div>
</SmartBackground>
)
}

View File

@@ -1,26 +1,26 @@
import statusCenter from '@/assets/system/status-center.webp'
import statusLine from '@/assets/system/status-line.webp'
import { SmartBackground } from '@/components/smart-background.tsx'
import { DesktopCountdown } from '@/features/game/components/desktop/desktop-countdown.tsx'
import { DesktopTitle } from '@/features/game/components/desktop/desktop-title.tsx'
export function DesktopStatusLine() {
return (
<div className={'relative w-full flex flex-col text-design-22'}>
<div
<SmartBackground
src={statusLine}
size="100% 100%"
className="w-full h-design-60 bg-no-repeat bg-center flex items-center justify-center"
style={{
backgroundImage: `url(${statusLine})`,
backgroundSize: '100% 100%',
}}
>
<div className={'flex-1 flex items-center justify-center'}>
<div>Odds: 1:33</div>
<div>Streak: X2</div>
<div>Limit: 100</div>
</div>
<div
<SmartBackground
src={statusCenter}
className="w-design-360 h-[105px] font-countdown bg-no-repeat bg-center bg-contain flex items-center justify-center"
style={{ backgroundImage: `url(${statusCenter})` }}
size="contain"
>
<DesktopCountdown
initialSeconds={30}
@@ -28,7 +28,7 @@ export function DesktopStatusLine() {
console.log('countdown finished')
}}
/>
</div>
</SmartBackground>
<div className={'flex-1 flex items-center justify-center gap-10'}>
<div>Round ID:20241026120</div>
<div className={'flex items-center gap-2'}>
@@ -41,7 +41,7 @@ export function DesktopStatusLine() {
<div>(Menerima Taruhan)</div>
</div>
</div>
</div>
</SmartBackground>
<div
className={
'absolute top-design-60 left-1/2 -translate-x-1/2 -z-10 w-full px-design-16'

View File

@@ -0,0 +1,5 @@
function DesktopTopup() {
return <div>DesktopTopup</div>
}
export default DesktopTopup

View File

@@ -0,0 +1,5 @@
function DesktopWithdraw() {
return <div>DesktopWithdraw</div>
}
export default DesktopWithdraw

View File

@@ -1,6 +1,6 @@
import type { ReactNode } from 'react'
import { cn } from '@/lib/untils'
import { cn } from '@/lib/utils'
type GameTone = 'neutral' | 'brand' | 'success' | 'warning' | 'danger'