新增連勝與獲勝特效並更新 README
This commit is contained in:
79
src/App.tsx
79
src/App.tsx
@@ -57,6 +57,29 @@ type SettlementState = {
|
||||
uploading: boolean
|
||||
}
|
||||
|
||||
type StreakAnnouncement = {
|
||||
count: number
|
||||
key: number
|
||||
teamName: string
|
||||
title: string
|
||||
}
|
||||
|
||||
type VictoryAnnouncement = {
|
||||
key: number
|
||||
scoreLabel: string
|
||||
teamName: string
|
||||
title: string
|
||||
}
|
||||
|
||||
const STREAK_TITLES: Record<number, string> = {
|
||||
3: '大殺特殺',
|
||||
4: '暴走',
|
||||
5: '無人能擋',
|
||||
6: '主宰比賽',
|
||||
7: '像神一般的',
|
||||
8: '成為傳說',
|
||||
}
|
||||
|
||||
function App() {
|
||||
const location = useLocation()
|
||||
const isScoreboardRoute = location.pathname === '/scoreboard'
|
||||
@@ -90,6 +113,8 @@ function App() {
|
||||
open: false,
|
||||
uploading: false,
|
||||
})
|
||||
const [streakAnnouncement, setStreakAnnouncement] = useState<StreakAnnouncement | null>(null)
|
||||
const [victoryAnnouncement, setVictoryAnnouncement] = useState<VictoryAnnouncement | null>(null)
|
||||
|
||||
const parsedAreaA = useMemo(() => parseRoster(areaAInput), [areaAInput])
|
||||
const parsedAreaB = useMemo(() => parseRoster(areaBInput), [areaBInput])
|
||||
@@ -125,10 +150,36 @@ function App() {
|
||||
return () => window.clearTimeout(timer)
|
||||
}, [loadMessage, loadStatus])
|
||||
|
||||
useEffect(() => {
|
||||
if (!streakAnnouncement) {
|
||||
return
|
||||
}
|
||||
|
||||
const timer = window.setTimeout(() => {
|
||||
setStreakAnnouncement(null)
|
||||
}, 1800)
|
||||
|
||||
return () => window.clearTimeout(timer)
|
||||
}, [streakAnnouncement])
|
||||
|
||||
useEffect(() => {
|
||||
if (!victoryAnnouncement) {
|
||||
return
|
||||
}
|
||||
|
||||
const timer = window.setTimeout(() => {
|
||||
setVictoryAnnouncement(null)
|
||||
}, 2200)
|
||||
|
||||
return () => window.clearTimeout(timer)
|
||||
}, [victoryAnnouncement])
|
||||
|
||||
const resetScoring = (nextState: ScoreState = initialScoreState) => {
|
||||
setScoreState(nextState)
|
||||
setScoreHistory([])
|
||||
setPointLog([])
|
||||
setStreakAnnouncement(null)
|
||||
setVictoryAnnouncement(null)
|
||||
setSettlement({
|
||||
error: '',
|
||||
open: false,
|
||||
@@ -294,6 +345,8 @@ function App() {
|
||||
const winner: 0 | 1 = side === 'left' ? 0 : 1
|
||||
const previousPoint = pointLog.at(-1)
|
||||
const winCount = previousPoint?.winner === winner ? previousPoint.winCount + 1 : 0
|
||||
const streakCount = winCount + 1
|
||||
const streakTitle = STREAK_TITLES[streakCount]
|
||||
|
||||
const nextPointLog = [
|
||||
...pointLog,
|
||||
@@ -323,6 +376,28 @@ function App() {
|
||||
setScoreHistory((current) => [...current, { pointLog, scoreState }])
|
||||
setPointLog(nextPointLog)
|
||||
setScoreState(nextScoreState)
|
||||
|
||||
if (streakTitle) {
|
||||
setStreakAnnouncement({
|
||||
count: streakCount,
|
||||
key: Date.now(),
|
||||
teamName: side === 'left' ? getTeamDisplayName(leftTeam) : getTeamDisplayName(rightTeam),
|
||||
title: streakTitle,
|
||||
})
|
||||
}
|
||||
|
||||
const reachedTarget =
|
||||
nextScoreState.scoreLeft >= nextScoreState.targetScore ||
|
||||
nextScoreState.scoreRight >= nextScoreState.targetScore
|
||||
|
||||
if (reachedTarget) {
|
||||
setVictoryAnnouncement({
|
||||
key: Date.now() + 1,
|
||||
scoreLabel: `${nextScoreState.scoreLeft} : ${nextScoreState.scoreRight}`,
|
||||
teamName: side === 'left' ? getTeamDisplayName(leftTeam) : getTeamDisplayName(rightTeam),
|
||||
title: '拿下勝利',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const undoLastPoint = () => {
|
||||
@@ -335,6 +410,8 @@ function App() {
|
||||
setScoreHistory((current) => current.slice(0, -1))
|
||||
setPointLog(previous.pointLog)
|
||||
setScoreState(previous.scoreState)
|
||||
setStreakAnnouncement(null)
|
||||
setVictoryAnnouncement(null)
|
||||
}
|
||||
|
||||
const openSettlementDialog = () => {
|
||||
@@ -506,6 +583,8 @@ function App() {
|
||||
rightTeam={rightTeam}
|
||||
scoreState={scoreState}
|
||||
selectedGroup={selectedGroup}
|
||||
streakAnnouncement={streakAnnouncement}
|
||||
victoryAnnouncement={victoryAnnouncement}
|
||||
targetDate={targetDate}
|
||||
onApplyMatchup={applyMatchup}
|
||||
onCloseFinishDialog={closeSettlementDialog}
|
||||
|
||||
Reference in New Issue
Block a user