860 lines
23 KiB
TypeScript
860 lines
23 KiB
TypeScript
import { ThemedText } from "@/components/themed-text";
|
|
import { ThemedView } from "@/components/themed-view";
|
|
import { IconSymbol } from "@/components/ui/icon-symbol";
|
|
import { LiveScoreMatch } from "@/types/api";
|
|
import { LinearGradient } from "expo-linear-gradient";
|
|
import React, { useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import {
|
|
Image,
|
|
LayoutChangeEvent,
|
|
Modal,
|
|
Pressable,
|
|
StyleSheet,
|
|
Switch,
|
|
TouchableOpacity,
|
|
View,
|
|
} from "react-native";
|
|
import Svg, {
|
|
Defs,
|
|
Path,
|
|
Stop,
|
|
LinearGradient as SvgLinearGradient,
|
|
} from "react-native-svg";
|
|
|
|
interface StatsCardProps {
|
|
match: LiveScoreMatch;
|
|
isDark: boolean;
|
|
}
|
|
|
|
export function StatsCard({ match, isDark }: StatsCardProps) {
|
|
const { t } = useTranslation();
|
|
const [flagSwitch, setFlagSwitch] = useState(true);
|
|
const [cardSwitch, setCardSwitch] = useState(true);
|
|
const [showInfo, setShowInfo] = useState(false);
|
|
const [chartWidth, setChartWidth] = useState(0);
|
|
|
|
const onChartLayout = (event: LayoutChangeEvent) => {
|
|
setChartWidth(event.nativeEvent.layout.width);
|
|
};
|
|
|
|
// 实时时间与进度计算
|
|
const getInitialMinutes = () => {
|
|
const statusIdx = parseInt(match.event_status) || 0;
|
|
const timeParts = match.event_time?.split(":") || [];
|
|
const tMin = parseInt(timeParts[0]) || 0;
|
|
const tSec = parseInt(timeParts[1]) || 0;
|
|
|
|
if (!isNaN(statusIdx) && /^\d+$/.test(match.event_status)) {
|
|
return { min: Math.max(0, statusIdx - tMin), sec: tSec };
|
|
}
|
|
return { min: tMin, sec: tSec };
|
|
};
|
|
|
|
const initial = getInitialMinutes();
|
|
const [minutes, setMinutes] = useState(initial.min);
|
|
const [seconds, setSeconds] = useState(initial.sec);
|
|
|
|
React.useEffect(() => {
|
|
const updated = getInitialMinutes();
|
|
setMinutes(updated.min);
|
|
setSeconds(updated.sec);
|
|
}, [match.event_time, match.event_status]);
|
|
|
|
React.useEffect(() => {
|
|
const statusStr = match.event_status?.toLowerCase() || "";
|
|
const isLive =
|
|
String(match.event_live) === "1" ||
|
|
statusStr.includes("live") ||
|
|
(parseInt(statusStr) > 0 && parseInt(statusStr) < 120);
|
|
|
|
if (!isLive || statusStr.includes("ht")) return;
|
|
|
|
const interval = setInterval(() => {
|
|
setSeconds((s) => {
|
|
if (s >= 59) {
|
|
setMinutes((m) => m + 1);
|
|
return 0;
|
|
}
|
|
return s + 1;
|
|
});
|
|
}, 1000);
|
|
return () => clearInterval(interval);
|
|
}, [match.event_key, match.event_live, match.event_status]);
|
|
|
|
const displayTime = `${minutes}:${seconds.toString().padStart(2, "0")}`;
|
|
const totalSeconds = minutes * 60 + seconds;
|
|
const progressPercent = Math.min(100, (totalSeconds / (90 * 60)) * 100);
|
|
|
|
// 从 statistics 中提取数据
|
|
const stats = (match.statistics || []) as any[];
|
|
const getStatValue = (type: string) => {
|
|
const stat = stats.find((s) => s.type === type);
|
|
if (stat && stat.home) {
|
|
return { home: stat.home, away: stat.away };
|
|
}
|
|
return { home: "0", away: "0" };
|
|
};
|
|
|
|
const possession = getStatValue("Ball Possession");
|
|
const corners = getStatValue("Corners");
|
|
const yellowCards = getStatValue("Yellow Cards");
|
|
|
|
// 解析控球率数值 (例如 "53%" -> 53)
|
|
const homePossession =
|
|
parseInt(possession.home.toString().replace("%", "")) || 50;
|
|
const awayPossession =
|
|
parseInt(possession.away.toString().replace("%", "")) || 50;
|
|
|
|
// 用随机数据模拟压力曲线
|
|
const generateData = React.useMemo(() => {
|
|
const data = [];
|
|
let h = 10;
|
|
let a = 10;
|
|
for (let i = 0; i < 90; i++) {
|
|
h = Math.max(0, Math.min(40, h + (Math.random() - 0.5) * 10));
|
|
a = Math.max(0, Math.min(40, a + (Math.random() - 0.5) * 10));
|
|
data.push({
|
|
time: i,
|
|
home: h,
|
|
away: a,
|
|
});
|
|
}
|
|
return data;
|
|
}, [match.event_key]);
|
|
|
|
const getWavePath = (
|
|
data: any[],
|
|
type: "home" | "away",
|
|
width: number,
|
|
height: number,
|
|
) => {
|
|
if (width === 0) return "";
|
|
const baseY = height / 2;
|
|
const points = data.map((d, i) => {
|
|
const x = (i / 89) * width;
|
|
const val = type === "home" ? d.home : d.away;
|
|
const y =
|
|
type === "home"
|
|
? baseY - (val / 50) * baseY
|
|
: baseY + (val / 50) * baseY;
|
|
return { x, y };
|
|
});
|
|
|
|
// 创建平滑曲线 (使用简单指令)
|
|
let d = `M 0 ${baseY}`;
|
|
points.forEach((p) => {
|
|
d += ` L ${p.x} ${p.y}`;
|
|
});
|
|
d += ` L ${width} ${baseY} Z`;
|
|
return d;
|
|
};
|
|
|
|
const chartData = generateData;
|
|
|
|
const iconTintColor = isDark ? "#888" : "#CCC";
|
|
const switchBg = isDark ? "#2C2C2E" : "#F0F0F0";
|
|
|
|
return (
|
|
<ThemedView style={[styles.container, isDark && styles.darkContainer]}>
|
|
{/* Header */}
|
|
<View style={styles.header}>
|
|
<View style={styles.headerLeft}>
|
|
<ThemedText style={styles.title}>
|
|
{t("detail.stats_card.title")}
|
|
</ThemedText>
|
|
<TouchableOpacity onPress={() => setShowInfo(true)}>
|
|
<IconSymbol
|
|
name="information-circle-outline"
|
|
size={16}
|
|
color={iconTintColor}
|
|
/>
|
|
</TouchableOpacity>
|
|
</View>
|
|
<View style={styles.switches}>
|
|
<View style={[styles.switchWrapper, { backgroundColor: switchBg }]}>
|
|
<IconSymbol name="flag" size={14} color="#4CAF50" />
|
|
<Switch
|
|
value={flagSwitch}
|
|
onValueChange={setFlagSwitch}
|
|
trackColor={{ false: "#DDD", true: "#3b5998" }}
|
|
thumbColor={flagSwitch ? "#A5D6A7" : "#FFF"}
|
|
style={styles.smallSwitch}
|
|
/>
|
|
</View>
|
|
<View style={[styles.switchWrapper, { backgroundColor: switchBg }]}>
|
|
<View style={[styles.miniCard, { backgroundColor: "#FFD700" }]} />
|
|
<Switch
|
|
value={cardSwitch}
|
|
onValueChange={setCardSwitch}
|
|
trackColor={{ false: "#DDD", true: "#3b5998" }}
|
|
thumbColor="#FFF"
|
|
style={styles.smallSwitch}
|
|
/>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Momentum Chart Area */}
|
|
<View style={styles.chartWrapper}>
|
|
<View style={styles.teamLogos}>
|
|
<Image
|
|
source={{ uri: match.home_team_logo }}
|
|
style={styles.chartLogo}
|
|
/>
|
|
<Image
|
|
source={{ uri: match.away_team_logo }}
|
|
style={[styles.chartLogo, { marginTop: 12 }]}
|
|
/>
|
|
</View>
|
|
|
|
<View style={styles.chartArea}>
|
|
{/* 背景色带 */}
|
|
<LinearGradient
|
|
colors={["rgba(59, 89, 152, 0.05)", "rgba(255, 171, 0, 0.05)"]}
|
|
style={styles.bgGradient}
|
|
/>
|
|
|
|
{/* 网格线和时间刻度 */}
|
|
<View style={styles.gridContainer}>
|
|
{["0'", "15'", "30'", "HT", "60'", "75'", "90'"].map((label, i) => (
|
|
<View key={i} style={styles.gridLine}>
|
|
<View
|
|
style={[styles.line, isDark && { backgroundColor: "#333" }]}
|
|
/>
|
|
<ThemedText
|
|
style={[styles.gridLabel, isDark && { color: "#888" }]}
|
|
>
|
|
{label}
|
|
</ThemedText>
|
|
</View>
|
|
))}
|
|
</View>
|
|
|
|
{/* 压力曲线模拟 (Wave Chart) */}
|
|
<View style={styles.waveContainer} onLayout={onChartLayout}>
|
|
{chartWidth > 0 && (
|
|
<Svg
|
|
width={chartWidth}
|
|
height={110}
|
|
style={{ position: "absolute" }}
|
|
>
|
|
<Defs>
|
|
<SvgLinearGradient
|
|
id="homeGradient"
|
|
x1="0"
|
|
y1="0"
|
|
x2="0"
|
|
y2="1"
|
|
>
|
|
<Stop offset="0" stopColor="#3b5998" stopOpacity="0.6" />
|
|
<Stop offset="1" stopColor="#3b5998" stopOpacity="0" />
|
|
</SvgLinearGradient>
|
|
<SvgLinearGradient
|
|
id="awayGradient"
|
|
x1="0"
|
|
y1="0"
|
|
x2="0"
|
|
y2="1"
|
|
>
|
|
<Stop offset="0" stopColor="#FFAB00" stopOpacity="0" />
|
|
<Stop offset="1" stopColor="#FFAB00" stopOpacity="0.6" />
|
|
</SvgLinearGradient>
|
|
</Defs>
|
|
{/* Home Wave */}
|
|
<Path
|
|
d={getWavePath(chartData, "home", chartWidth, 110)}
|
|
fill="url(#homeGradient)"
|
|
stroke="#3b5998"
|
|
strokeWidth="1.5"
|
|
/>
|
|
{/* Away Wave */}
|
|
<Path
|
|
d={getWavePath(chartData, "away", chartWidth, 110)}
|
|
fill="url(#awayGradient)"
|
|
stroke="#FFAB00"
|
|
strokeWidth="1.5"
|
|
/>
|
|
</Svg>
|
|
)}
|
|
</View>
|
|
|
|
{/* 动态标记:红黄牌 */}
|
|
{chartWidth > 0 &&
|
|
cardSwitch &&
|
|
match.cards?.map((card, idx) => {
|
|
const time = parseInt(card.time) || 0;
|
|
const left = (time / 90) * chartWidth;
|
|
const isHome = card.home_fault !== "";
|
|
const isYellow = (card.card || "")
|
|
.toLowerCase()
|
|
.includes("yellow");
|
|
return (
|
|
<View
|
|
key={`card-${idx}`}
|
|
style={[
|
|
styles.eventMarker,
|
|
{ left, top: isHome ? "5%" : "72%" },
|
|
]}
|
|
>
|
|
<View
|
|
style={[
|
|
styles.square,
|
|
{
|
|
backgroundColor: isYellow ? "#FFD700" : "#FF3B30",
|
|
width: 8,
|
|
height: 12,
|
|
borderRadius: 1,
|
|
},
|
|
]}
|
|
/>
|
|
</View>
|
|
);
|
|
})}
|
|
|
|
{/* 动态标记:进球 */}
|
|
{chartWidth > 0 &&
|
|
flagSwitch &&
|
|
match.goalscorers?.map((goal, idx) => {
|
|
const time = parseInt(goal.time) || 0;
|
|
const left = (time / 90) * chartWidth;
|
|
const isHome = !!goal.home_scorer;
|
|
return (
|
|
<View
|
|
key={`goal-${idx}`}
|
|
style={[
|
|
styles.eventMarker,
|
|
{ left, top: isHome ? "25%" : "55%" },
|
|
]}
|
|
>
|
|
<View style={styles.goalBox}>
|
|
<IconSymbol name="football" size={10} color="#000" />
|
|
</View>
|
|
</View>
|
|
);
|
|
})}
|
|
</View>
|
|
</View>
|
|
|
|
{/* Time Progress Slider */}
|
|
<View style={styles.sliderContainer}>
|
|
<ThemedText style={styles.currentTime}>{displayTime}</ThemedText>
|
|
<View style={styles.trackContainer}>
|
|
<View style={[styles.track, isDark && { backgroundColor: "#333" }]} />
|
|
<View
|
|
style={[styles.filledTrack, { width: `${progressPercent}%` }]}
|
|
/>
|
|
<View style={[styles.thumb, { left: "0%" }]} />
|
|
<View
|
|
style={[
|
|
styles.thumb,
|
|
{
|
|
left: `${progressPercent}%`,
|
|
backgroundColor: "#FFAB00",
|
|
borderColor: "#FFF",
|
|
},
|
|
]}
|
|
/>
|
|
<View
|
|
style={[
|
|
styles.thumb,
|
|
{ left: "100%", backgroundColor: isDark ? "#555" : "#333" },
|
|
]}
|
|
/>
|
|
</View>
|
|
<View style={styles.trackLabels}>
|
|
<ThemedText style={styles.trackLabel}>0:00</ThemedText>
|
|
<ThemedText style={styles.trackLabel}>HT</ThemedText>
|
|
<ThemedText style={styles.trackLabel}>FT</ThemedText>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Possession & Stats Bar */}
|
|
<View style={styles.possessionSection}>
|
|
<ThemedText style={styles.possessionTitle}>
|
|
{t("detail.stats_card.possession")}
|
|
</ThemedText>
|
|
<View style={styles.possessionBarRow}>
|
|
<View
|
|
style={[
|
|
styles.posBar,
|
|
{
|
|
flex: homePossession,
|
|
backgroundColor: "#3b5998",
|
|
borderTopLeftRadius: 10,
|
|
borderBottomLeftRadius: 10,
|
|
},
|
|
]}
|
|
>
|
|
<Image
|
|
source={{ uri: match.home_team_logo }}
|
|
style={styles.posLogo}
|
|
/>
|
|
<ThemedText style={styles.posValue}>{homePossession}%</ThemedText>
|
|
</View>
|
|
<View style={{ width: 4 }} />
|
|
<View
|
|
style={[
|
|
styles.posBar,
|
|
{
|
|
flex: awayPossession,
|
|
backgroundColor: "#FFAB00",
|
|
borderTopRightRadius: 10,
|
|
borderBottomRightRadius: 10,
|
|
flexDirection: "row-reverse",
|
|
},
|
|
]}
|
|
>
|
|
<Image
|
|
source={{ uri: match.away_team_logo }}
|
|
style={styles.posLogo}
|
|
/>
|
|
<ThemedText style={styles.posValue}>{awayPossession}%</ThemedText>
|
|
</View>
|
|
</View>
|
|
|
|
<View style={styles.miniStatsRow}>
|
|
<View style={[styles.miniStatBadge, isDark && styles.darkStatBadge]}>
|
|
<ThemedText style={styles.miniStatText}>{corners.home}</ThemedText>
|
|
<IconSymbol name="flag" size={14} color="#FFAB00" />
|
|
<ThemedText style={styles.miniStatText}>{corners.away}</ThemedText>
|
|
</View>
|
|
<View style={[styles.miniStatBadge, isDark && styles.darkStatBadge]}>
|
|
<ThemedText style={styles.miniStatText}>
|
|
{yellowCards.home}
|
|
</ThemedText>
|
|
<View style={styles.yellowCardIcon} />
|
|
<ThemedText style={styles.miniStatText}>
|
|
{yellowCards.away}
|
|
</ThemedText>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Momentum Info Modal */}
|
|
<Modal
|
|
visible={showInfo}
|
|
transparent
|
|
animationType="fade"
|
|
onRequestClose={() => setShowInfo(false)}
|
|
>
|
|
<Pressable
|
|
style={styles.modalOverlay}
|
|
onPress={() => setShowInfo(false)}
|
|
>
|
|
<ThemedView
|
|
style={[styles.modalContent, isDark && styles.darkModalContent]}
|
|
>
|
|
<ThemedText style={styles.modalTitle}>
|
|
{t("detail.stats_card.info_title")}
|
|
</ThemedText>
|
|
|
|
<ThemedText style={styles.modalDesc}>
|
|
{t("detail.stats_card.info_desc")}
|
|
</ThemedText>
|
|
|
|
<View style={styles.bulletPoint}>
|
|
<ThemedText style={styles.bulletText}>
|
|
• {t("detail.stats_card.point1")}
|
|
</ThemedText>
|
|
</View>
|
|
<View style={styles.bulletPoint}>
|
|
<ThemedText style={styles.bulletText}>
|
|
• {t("detail.stats_card.point2")}
|
|
</ThemedText>
|
|
</View>
|
|
<View style={styles.bulletPoint}>
|
|
<ThemedText style={styles.bulletText}>
|
|
• {t("detail.stats_card.point3")}
|
|
</ThemedText>
|
|
</View>
|
|
|
|
<View style={styles.teamInfoRow}>
|
|
<Image
|
|
source={{ uri: match.home_team_logo }}
|
|
style={styles.miniLogo}
|
|
/>
|
|
<View style={styles.wavePlaceholder}>
|
|
{[...Array(6)].map((_, i) => (
|
|
<View
|
|
key={i}
|
|
style={[
|
|
styles.waveDot,
|
|
{
|
|
backgroundColor: "#3b5998",
|
|
marginTop: i % 2 === 0 ? 0 : 6,
|
|
},
|
|
]}
|
|
/>
|
|
))}
|
|
</View>
|
|
<ThemedText style={styles.teamDesc} numberOfLines={1}>
|
|
{match.event_home_team}
|
|
</ThemedText>
|
|
</View>
|
|
|
|
<View style={styles.teamInfoRow}>
|
|
<Image
|
|
source={{ uri: match.away_team_logo }}
|
|
style={styles.miniLogo}
|
|
/>
|
|
<View style={styles.wavePlaceholder}>
|
|
{[...Array(6)].map((_, i) => (
|
|
<View
|
|
key={i}
|
|
style={[
|
|
styles.waveDot,
|
|
{
|
|
backgroundColor: "#FFAB00",
|
|
marginTop: i % 2 === 0 ? 6 : 0,
|
|
},
|
|
]}
|
|
/>
|
|
))}
|
|
</View>
|
|
<ThemedText style={styles.teamDesc} numberOfLines={1}>
|
|
{match.event_away_team}
|
|
</ThemedText>
|
|
</View>
|
|
|
|
<TouchableOpacity
|
|
style={styles.closeButton}
|
|
onPress={() => setShowInfo(false)}
|
|
>
|
|
<ThemedText style={styles.closeButtonText}>
|
|
{t("detail.stats_card.close")}
|
|
</ThemedText>
|
|
</TouchableOpacity>
|
|
</ThemedView>
|
|
</Pressable>
|
|
</Modal>
|
|
</ThemedView>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
margin: 16,
|
|
borderRadius: 20,
|
|
padding: 16,
|
|
backgroundColor: "#FFF",
|
|
marginBottom: 20,
|
|
shadowColor: "#000",
|
|
shadowOpacity: 0.05,
|
|
shadowRadius: 10,
|
|
elevation: 2,
|
|
},
|
|
darkContainer: {
|
|
backgroundColor: "#1E1E20",
|
|
},
|
|
header: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
justifyContent: "space-between",
|
|
marginBottom: 24,
|
|
},
|
|
headerLeft: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
gap: 8,
|
|
},
|
|
title: {
|
|
fontSize: 18,
|
|
fontWeight: "500",
|
|
color: "#666",
|
|
},
|
|
switches: {
|
|
flexDirection: "row",
|
|
gap: 12,
|
|
},
|
|
switchWrapper: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
backgroundColor: "#F0F0F0",
|
|
borderRadius: 15,
|
|
paddingLeft: 8,
|
|
paddingRight: 2,
|
|
height: 30,
|
|
},
|
|
smallSwitch: {
|
|
transform: [{ scaleX: 0.6 }, { scaleY: 0.6 }],
|
|
},
|
|
miniCard: {
|
|
width: 10,
|
|
height: 14,
|
|
borderRadius: 2,
|
|
},
|
|
chartWrapper: {
|
|
flexDirection: "row",
|
|
height: 140,
|
|
marginBottom: 10,
|
|
},
|
|
teamLogos: {
|
|
width: 40,
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
paddingBottom: 20,
|
|
},
|
|
chartLogo: {
|
|
width: 24,
|
|
height: 24,
|
|
borderRadius: 12,
|
|
},
|
|
chartArea: {
|
|
flex: 1,
|
|
position: "relative",
|
|
marginLeft: 8,
|
|
},
|
|
bgGradient: {
|
|
position: "absolute",
|
|
top: 0,
|
|
left: 0,
|
|
right: 0,
|
|
bottom: 30,
|
|
borderRadius: 4,
|
|
},
|
|
gridContainer: {
|
|
position: "absolute",
|
|
top: 0,
|
|
left: 0,
|
|
right: 0,
|
|
bottom: 0,
|
|
flexDirection: "row",
|
|
justifyContent: "space-between",
|
|
},
|
|
gridLine: {
|
|
height: "100%",
|
|
alignItems: "center",
|
|
},
|
|
line: {
|
|
width: 1,
|
|
height: "100%",
|
|
backgroundColor: "#F0F0F0",
|
|
marginBottom: 4,
|
|
},
|
|
gridLabel: {
|
|
fontSize: 12,
|
|
color: "#000",
|
|
fontWeight: "500",
|
|
},
|
|
waveContainer: {
|
|
position: "absolute",
|
|
top: 0,
|
|
left: 0,
|
|
right: 0,
|
|
bottom: 30,
|
|
},
|
|
waveBar: {
|
|
position: "absolute",
|
|
width: 1.5,
|
|
},
|
|
eventMarker: {
|
|
position: "absolute",
|
|
alignItems: "center",
|
|
},
|
|
square: {
|
|
width: 12,
|
|
height: 16,
|
|
borderRadius: 2,
|
|
},
|
|
goalBox: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
gap: 2,
|
|
backgroundColor: "#FFF",
|
|
padding: 2,
|
|
borderRadius: 4,
|
|
borderWidth: 1,
|
|
borderColor: "#E0E0E0",
|
|
},
|
|
sliderContainer: {
|
|
marginTop: 20,
|
|
paddingHorizontal: 10,
|
|
},
|
|
currentTime: {
|
|
fontSize: 14,
|
|
color: "#4CAF50",
|
|
fontWeight: "700",
|
|
textAlign: "center",
|
|
marginBottom: 4,
|
|
marginLeft: "10%", // Offset roughly
|
|
},
|
|
trackContainer: {
|
|
height: 20,
|
|
justifyContent: "center",
|
|
position: "relative",
|
|
},
|
|
track: {
|
|
height: 3,
|
|
backgroundColor: "#EEE",
|
|
borderRadius: 2,
|
|
},
|
|
filledTrack: {
|
|
position: "absolute",
|
|
height: 3,
|
|
backgroundColor: "#3b5998",
|
|
borderRadius: 2,
|
|
},
|
|
thumb: {
|
|
position: "absolute",
|
|
width: 10,
|
|
height: 10,
|
|
borderRadius: 5,
|
|
backgroundColor: "#3b5998",
|
|
borderWidth: 2,
|
|
borderColor: "#FFF",
|
|
marginLeft: -5,
|
|
},
|
|
trackLabels: {
|
|
flexDirection: "row",
|
|
justifyContent: "space-between",
|
|
marginTop: 8,
|
|
},
|
|
trackLabel: {
|
|
fontSize: 12,
|
|
color: "#666",
|
|
fontWeight: "500",
|
|
},
|
|
possessionSection: {
|
|
marginTop: 24,
|
|
alignItems: "center",
|
|
},
|
|
possessionTitle: {
|
|
fontSize: 16,
|
|
color: "#666",
|
|
marginBottom: 12,
|
|
},
|
|
possessionBarRow: {
|
|
flexDirection: "row",
|
|
height: 36,
|
|
width: "100%",
|
|
paddingHorizontal: 4,
|
|
},
|
|
posBar: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
paddingHorizontal: 12,
|
|
gap: 8,
|
|
},
|
|
posLogo: {
|
|
width: 20,
|
|
height: 20,
|
|
borderRadius: 10,
|
|
backgroundColor: "#FFF",
|
|
},
|
|
posValue: {
|
|
color: "#FFF",
|
|
fontSize: 14,
|
|
fontWeight: "700",
|
|
},
|
|
miniStatsRow: {
|
|
flexDirection: "row",
|
|
justifyContent: "center",
|
|
gap: 12,
|
|
marginTop: 16,
|
|
},
|
|
miniStatBadge: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
backgroundColor: "#F5F5F5",
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 6,
|
|
borderRadius: 20,
|
|
gap: 8,
|
|
minWidth: 80,
|
|
justifyContent: "center",
|
|
},
|
|
darkStatBadge: {
|
|
backgroundColor: "#2C2C2E",
|
|
},
|
|
miniStatText: {
|
|
fontSize: 14,
|
|
fontWeight: "600",
|
|
},
|
|
yellowCardIcon: {
|
|
width: 10,
|
|
height: 14,
|
|
backgroundColor: "#FFD700",
|
|
borderRadius: 2,
|
|
},
|
|
modalOverlay: {
|
|
flex: 1,
|
|
backgroundColor: "rgba(0,0,0,0.5)",
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
padding: 20,
|
|
},
|
|
modalContent: {
|
|
width: "100%",
|
|
backgroundColor: "#FFF",
|
|
borderRadius: 24,
|
|
padding: 24,
|
|
shadowColor: "#000",
|
|
shadowOpacity: 0.1,
|
|
shadowRadius: 20,
|
|
elevation: 10,
|
|
},
|
|
darkModalContent: {
|
|
backgroundColor: "#1E1E20",
|
|
},
|
|
modalTitle: {
|
|
fontSize: 20,
|
|
fontWeight: "700",
|
|
marginBottom: 16,
|
|
},
|
|
modalDesc: {
|
|
fontSize: 15,
|
|
lineHeight: 22,
|
|
marginBottom: 16,
|
|
},
|
|
bulletPoint: {
|
|
marginBottom: 8,
|
|
},
|
|
bulletText: {
|
|
fontSize: 15,
|
|
lineHeight: 22,
|
|
},
|
|
teamInfoRow: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
marginTop: 16,
|
|
gap: 12,
|
|
},
|
|
miniLogo: {
|
|
width: 24,
|
|
height: 24,
|
|
borderRadius: 12,
|
|
},
|
|
wavePlaceholder: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
width: 40,
|
|
height: 20,
|
|
gap: 2,
|
|
},
|
|
waveDot: {
|
|
width: 4,
|
|
height: 4,
|
|
borderRadius: 2,
|
|
},
|
|
teamDesc: {
|
|
flex: 1,
|
|
fontSize: 14,
|
|
color: "#666",
|
|
},
|
|
closeButton: {
|
|
backgroundColor: "#4B77FF",
|
|
borderRadius: 12,
|
|
paddingVertical: 12,
|
|
alignItems: "center",
|
|
marginTop: 24,
|
|
alignSelf: "flex-end",
|
|
paddingHorizontal: 24,
|
|
},
|
|
closeButtonText: {
|
|
color: "#FFF",
|
|
fontSize: 16,
|
|
fontWeight: "600",
|
|
},
|
|
});
|