diff --git a/assets/js/components/BattleDialog.jsx b/assets/js/components/BattleDialog.jsx
index 78838ba..a4f9148 100644
--- a/assets/js/components/BattleDialog.jsx
+++ b/assets/js/components/BattleDialog.jsx
@@ -1,6 +1,9 @@
import React, { useEffect, useState } from 'react';
import Dialog from '@mui/material/Dialog';
import { createTheme, ThemeProvider } from '@mui/material/styles';
+import Avatar from './battle-dialog/Avatar';
+import StatRow from './battle-dialog/StatRow';
+import BonusPoints from './battle-dialog/BonusPoints';
const darkTheme = createTheme({ palette: { mode: 'dark' } });
@@ -50,124 +53,6 @@ const RESULT_META = {
},
};
-function Avatar({ name, color, avatarUrl, bonusPoints = 0 }) {
- const isRed = 'red' === color;
- const initials = (name || '?').slice(0, 2).toUpperCase();
-
- const gradient = isRed
- ? 'linear-gradient(135deg, rgba(173,10,5,0.6) 0%, rgba(246,125,82,0.4) 100%)'
- : 'linear-gradient(135deg, rgba(35,111,135,0.6) 0%, rgba(41,128,185,0.4) 100%)';
- const glow = isRed
- ? '0 0 0 3px rgba(173,10,5,0.2), 0 0 28px rgba(173,10,5,0.35)'
- : '0 0 0 3px rgba(35,111,135,0.2), 0 0 28px rgba(35,111,135,0.35)';
- const border = isRed
- ? 'rgba(173,10,5,0.5)'
- : 'rgba(35,111,135,0.5)';
- const textColor = isRed ? '#f67d52' : '#95cff5';
-
- return (
-
-
-
- {avatarUrl ? (
-

- ) : (
- initials
- )}
-
- {0 < bonusPoints && (
-
-
-
- )}
-
-
- {name}
-
-
- {isRed ? 'Red' : 'Blue'}
-
-
- );
-}
-
-function StatRow({ icon, label, value, valueColor }) {
- return (
-
-
-
- {label}
-
-
- {value}
-
-
- );
-}
-
export default function BattleDialog({ games }) {
const [open, setOpen] = useState(false);
const [game, setGame] = useState(null);
@@ -250,7 +135,10 @@ export default function BattleDialog({ games }) {
-
game.blueBonusPoints ? game.redBonusPoints : 0} />
+ game.blueBonusPoints ? game.redBonusPoints : 0}
+ />
{game.redPoints ?? '—'}
@@ -258,11 +146,25 @@ export default function BattleDialog({ games }) {
{game.bluePoints ?? '—'}
-
+
{(game.redBonusPoints ?? 0).toFixed(1)}
:
-
+
{(game.blueBonusPoints ?? 0).toFixed(1)}
@@ -274,7 +176,10 @@ export default function BattleDialog({ games }) {
{meta.label}
- game.redBonusPoints ? game.blueBonusPoints : 0} />
+ game.redBonusPoints ? game.blueBonusPoints : 0}
+ />
@@ -286,7 +191,10 @@ export default function BattleDialog({ games }) {
)}
{0 < pointDiff && (
-
+
)}
-
- {(0 < game.redBonusPoints
- || 0 < game.blueBonusPoints
- || game.redBonusStats?.blindHits
- || game.blueBonusStats?.blindHits
- ) && (
-
-
- {/* Red Bonus */}
-
-
- Red Bonus Statistics
-
-
-
- {0 < game.redBonusStats?.blindHits && }
- {0 < game.redBonusStats?.chainBest && }
- {0 < game.redBonusStats?.edgeMines && }
- {0 < game.redBonusStats?.lastMineHits && }
- {0 < game.redBonusStats?.biggestReveal && }
- {!game.redBonusStats?.blindHits && !game.redBonusStats?.chainBest && !game.redBonusStats?.edgeMines && !game.redBonusStats?.lastMineHits && !game.redBonusStats?.biggestReveal
- && }
-
-
-
- {/* Blue Bonus */}
-
-
- Blue Bonus Statistics
-
-
-
- {0 < game.blueBonusStats?.blindHits && }
- {0 < game.blueBonusStats?.chainBest && }
- {0 < game.blueBonusStats?.edgeMines && }
- {0 < game.blueBonusStats?.lastMineHits && }
- {0 < game.blueBonusStats?.biggestReveal && }
- {!game.blueBonusStats?.blindHits && !game.blueBonusStats?.chainBest && !game.blueBonusStats?.edgeMines && !game.blueBonusStats?.lastMineHits && !game.blueBonusStats?.biggestReveal
- && }
-
-
-
-
- )}
+
diff --git a/assets/js/components/battle-dialog/Avatar.jsx b/assets/js/components/battle-dialog/Avatar.jsx
new file mode 100644
index 0000000..9f62eeb
--- /dev/null
+++ b/assets/js/components/battle-dialog/Avatar.jsx
@@ -0,0 +1,98 @@
+/**
+ * This file is part of the SplendidBear Websites' projects.
+ *
+ * Copyright (c) 2026 @ www.splendidbear.org
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import React from 'react';
+
+export default function Avatar({ name, color, avatarUrl, bonusPoints = 0 }) {
+ const isRed = 'red' === color;
+ const initials = (name || '?').slice(0, 2).toUpperCase();
+
+ const gradient = isRed
+ ? 'linear-gradient(135deg, rgba(173,10,5,0.6) 0%, rgba(246,125,82,0.4) 100%)'
+ : 'linear-gradient(135deg, rgba(35,111,135,0.6) 0%, rgba(41,128,185,0.4) 100%)';
+ const glow = isRed
+ ? '0 0 0 3px rgba(173,10,5,0.2), 0 0 28px rgba(173,10,5,0.35)'
+ : '0 0 0 3px rgba(35,111,135,0.2), 0 0 28px rgba(35,111,135,0.35)';
+ const border = isRed
+ ? 'rgba(173,10,5,0.5)'
+ : 'rgba(35,111,135,0.5)';
+ const textColor = isRed ? '#f67d52' : '#95cff5';
+
+ return (
+
+
+
+ {avatarUrl ? (
+

+ ) : (
+ initials
+ )}
+
+ {0 < bonusPoints && (
+
+
+
+ )}
+
+
+ {name}
+
+
+ {isRed ? 'Red' : 'Blue'}
+
+
+ );
+}
diff --git a/assets/js/components/battle-dialog/BonusPoints.jsx b/assets/js/components/battle-dialog/BonusPoints.jsx
new file mode 100644
index 0000000..5b2d162
--- /dev/null
+++ b/assets/js/components/battle-dialog/BonusPoints.jsx
@@ -0,0 +1,139 @@
+import { useMemo } from 'react';
+import StatRow from './StatRow';
+
+export default function BonusPoints({ game }) {
+ const hasBonuspoints = useMemo(
+ () => 0 < game?.redBonusPoints
+ || 0 < game?.blueBonusPoints
+ || game?.redBonusStats?.blindHits
+ || game?.blueBonusStats?.blindHits,
+ [
+ game?.blueBonusPoints,
+ game?.blueBonusStats?.blindHits,
+ game?.redBonusPoints,
+ game?.redBonusStats?.blindHits,
+ ],
+ );
+
+ const hasRedNoBonuses = useMemo(
+ () => !game.redBonusStats?.blindHits
+ && !game.redBonusStats?.chainBest
+ && !game.redBonusStats?.edgeMines
+ && !game.redBonusStats?.lastMineHits
+ && !game.redBonusStats?.biggestReveal,
+ [
+ game.redBonusStats?.biggestReveal,
+ game.redBonusStats?.blindHits,
+ game.redBonusStats?.chainBest,
+ game.redBonusStats?.edgeMines,
+ game.redBonusStats?.lastMineHits,
+ ],
+ );
+
+ const hasBlueNoBonuses = useMemo(
+ () => !game.blueBonusStats?.blindHits
+ && !game.blueBonusStats?.chainBest
+ && !game.blueBonusStats?.edgeMines
+ && !game.blueBonusStats?.lastMineHits
+ && !game.blueBonusStats?.biggestReveal,
+ [
+ game.blueBonusStats?.biggestReveal,
+ game.blueBonusStats?.blindHits,
+ game.blueBonusStats?.chainBest,
+ game.blueBonusStats?.edgeMines,
+ game.blueBonusStats?.lastMineHits,
+ ],
+ );
+
+ if (!hasBonuspoints) {
+ return '';
+ }
+
+ return (
+
+
+ {/* Red Bonus */}
+
+
+ Red Bonus Statistics
+
+
+
+ {0 < game.redBonusStats?.blindHits
+ && }
+ {0 < game.redBonusStats?.chainBest
+ && }
+ {0 < game.redBonusStats?.edgeMines
+ && }
+ {0 < game.redBonusStats?.lastMineHits
+ && }
+ {0 < game.redBonusStats?.biggestReveal
+ && }
+ {hasRedNoBonuses
+ && }
+
+
+
+
+ Blue Bonus Statistics
+
+
+
+ {0 < game.blueBonusStats?.blindHits
+ && }
+ {0 < game.blueBonusStats?.chainBest
+ && }
+ {0 < game.blueBonusStats?.edgeMines
+ && }
+ {0 < game.blueBonusStats?.lastMineHits
+ && }
+ {0 < game.blueBonusStats?.biggestReveal
+ && }
+ {hasBlueNoBonuses
+ && }
+
+
+
+
+ );
+}
diff --git a/assets/js/components/battle-dialog/StatRow.jsx b/assets/js/components/battle-dialog/StatRow.jsx
new file mode 100644
index 0000000..5aba0f4
--- /dev/null
+++ b/assets/js/components/battle-dialog/StatRow.jsx
@@ -0,0 +1,40 @@
+/**
+ * This file is part of the SplendidBear Websites' projects.
+ *
+ * Copyright (c) 2026 @ www.splendidbear.org
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import React from 'react';
+
+export default function StatRow({ icon, label, value, valueColor }) {
+ return (
+
+
+
+ {label}
+
+
+ {value}
+
+
+ );
+}