diff --git a/assets/empty/country_dark.svg b/assets/empty/country_dark.svg
new file mode 100644
index 0000000..0a6a8f1
--- /dev/null
+++ b/assets/empty/country_dark.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/assets/empty/country_light.svg b/assets/empty/country_light.svg
new file mode 100644
index 0000000..cb93f82
--- /dev/null
+++ b/assets/empty/country_light.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/assets/empty/league_dark.svg b/assets/empty/league_dark.svg
new file mode 100644
index 0000000..7ed3cdd
--- /dev/null
+++ b/assets/empty/league_dark.svg
@@ -0,0 +1,7 @@
+
diff --git a/assets/empty/league_light.svg b/assets/empty/league_light.svg
new file mode 100644
index 0000000..933632e
--- /dev/null
+++ b/assets/empty/league_light.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/assets/empty/player_dark.svg b/assets/empty/player_dark.svg
new file mode 100644
index 0000000..e96d625
--- /dev/null
+++ b/assets/empty/player_dark.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/assets/empty/player_light.svg b/assets/empty/player_light.svg
new file mode 100644
index 0000000..cca3a47
--- /dev/null
+++ b/assets/empty/player_light.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/assets/empty/team_dark.svg b/assets/empty/team_dark.svg
new file mode 100644
index 0000000..fe15a8b
--- /dev/null
+++ b/assets/empty/team_dark.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/assets/empty/team_light.svg b/assets/empty/team_light.svg
new file mode 100644
index 0000000..f7c166c
--- /dev/null
+++ b/assets/empty/team_light.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/assets/league_dark.svg b/assets/league_dark.svg
new file mode 100644
index 0000000..9937644
--- /dev/null
+++ b/assets/league_dark.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/components/empty-placeholder.tsx b/components/empty-placeholder.tsx
new file mode 100644
index 0000000..e6b51e9
--- /dev/null
+++ b/components/empty-placeholder.tsx
@@ -0,0 +1,34 @@
+import { useTheme } from "@/context/ThemeContext";
+import { Image } from "expo-image";
+import React from "react";
+
+interface EmptyPlaceholderProps {
+ type: "team" | "league" | "player" | "country";
+ size?: number;
+}
+
+const imageMap: { [key: string]: any } = {
+ team_light: require("@/assets/empty/team_light.svg"),
+ team_dark: require("@/assets/empty/team_dark.svg"),
+ league_light: require("@/assets/empty/league_light.svg"),
+ league_dark: require("@/assets/empty/league_dark.svg"),
+ player_light: require("@/assets/empty/player_light.svg"),
+ player_dark: require("@/assets/empty/player_dark.svg"),
+ country_light: require("@/assets/empty/country_light.svg"),
+ country_dark: require("@/assets/empty/country_dark.svg"),
+};
+
+export function EmptyPlaceholder({ type, size = 64 }: EmptyPlaceholderProps) {
+ const { theme } = useTheme();
+ const isDark = theme === "dark";
+ const suffix = isDark ? "_dark" : "_light";
+ const imageKey = `${type}${suffix}`;
+
+ return (
+
+ );
+}
diff --git a/components/league-modal.tsx b/components/league-modal.tsx
index 2e113cf..f08196f 100644
--- a/components/league-modal.tsx
+++ b/components/league-modal.tsx
@@ -1,3 +1,4 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { Colors } from "@/constants/theme";
@@ -47,14 +48,14 @@ export function LeagueModal({
>
{/* 左侧图标 */}
- {league.logo ? (
+ {league.logo && league.logo.trim() !== "" && !league.logo.includes("placehold") ? (
) : (
-
+
)}
diff --git a/components/live-detail/live-league-info.tsx b/components/live-detail/live-league-info.tsx
index 74bb8af..36a4d35 100644
--- a/components/live-detail/live-league-info.tsx
+++ b/components/live-detail/live-league-info.tsx
@@ -1,3 +1,4 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { LiveScoreMatch } from "@/types/api";
@@ -23,15 +24,13 @@ export function LiveLeagueInfo({ match }: LiveLeagueInfoProps) {
activeOpacity={0.7}
>
- {match.league_logo ? (
+ {match.league_logo && match.league_logo.trim() !== "" && !match.league_logo.includes("placehold") ? (
) : (
-
-
-
+
)}
{match.league_name}
diff --git a/components/live-detail/live-score-header.tsx b/components/live-detail/live-score-header.tsx
index 4b06f97..b46d980 100644
--- a/components/live-detail/live-score-header.tsx
+++ b/components/live-detail/live-score-header.tsx
@@ -1,3 +1,4 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { addFavorite, checkFavorite, removeFavorite } from "@/lib/api";
@@ -265,10 +266,14 @@ export function LiveScoreHeader({ match, topInset }: LiveScoreHeaderProps) {
/>
-
+ {homeLogo && homeLogo.trim() !== "" && !homeLogo.includes("placehold") ? (
+
+ ) : (
+
+ )}
@@ -318,10 +323,14 @@ export function LiveScoreHeader({ match, topInset }: LiveScoreHeaderProps) {
-
+ {awayLogo && awayLogo.trim() !== "" && !awayLogo.includes("placehold") ? (
+
+ ) : (
+
+ )}
toggleTeamFavorite(match.away_team_key, false)}
diff --git a/components/match-card-league.tsx b/components/match-card-league.tsx
index b0ff3b9..549d031 100644
--- a/components/match-card-league.tsx
+++ b/components/match-card-league.tsx
@@ -1,12 +1,11 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { Colors } from "@/constants/theme";
import { useAppState } from "@/context/AppStateContext";
import { useTheme } from "@/context/ThemeContext";
import { addFavorite, removeFavorite } from "@/lib/api";
-import { getInitials, getLogoGradient } from "@/lib/avatar-utils";
import { Match } from "@/types/api";
-import { LinearGradient } from "expo-linear-gradient";
import { useRouter } from "expo-router";
import React, { useState } from "react";
import { Image, Pressable, StyleSheet, TouchableOpacity, View } from "react-native";
@@ -182,13 +181,10 @@ export function MatchCardLeague({
{(() => {
- const teamName = isTennis ? (match as any).eventFirstPlayer : (match.home || match.homeTeamName);
const logoUri = isTennis
? (match as any).eventFirstPlayerLogo
: ((match as any).homeLogo || match.homeTeamLogo);
const hasLogo = logoUri && logoUri.trim() !== "" && !logoUri.includes("placehold");
- const gradient = getLogoGradient(teamName || "");
- const initials = getInitials(teamName || "");
return hasLogo ? (
) : (
-
- {initials}
-
+
);
})()}
@@ -217,13 +206,10 @@ export function MatchCardLeague({
{(() => {
- const teamName = isTennis ? (match as any).eventSecondPlayer : (match.away || match.awayTeamName);
const logoUri = isTennis
? (match as any).eventSecondPlayerLogo
: ((match as any).awayLogo || match.awayTeamLogo);
const hasLogo = logoUri && logoUri.trim() !== "" && !logoUri.includes("placehold");
- const gradient = getLogoGradient(teamName || "");
- const initials = getInitials(teamName || "");
return hasLogo ? (
) : (
-
- {initials}
-
+
);
})()}
diff --git a/components/match-card.tsx b/components/match-card.tsx
index 0e1d3bb..808b675 100644
--- a/components/match-card.tsx
+++ b/components/match-card.tsx
@@ -1,3 +1,4 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { Colors } from "@/constants/theme";
@@ -467,13 +468,16 @@ export function MatchCard({
-
+ {homeLogo && homeLogo.trim() !== "" && !homeLogo.includes("placehold") ? (
+ {}}
+ />
+ ) : (
+
+ )}
-
+ {awayLogo && awayLogo.trim() !== "" && !awayLogo.includes("placehold") ? (
+ {}}
+ />
+ ) : (
+
+ )}
{row.logo && row.logo.trim() !== "" && !row.logo.includes("placehold") ? (
- ) : null}
+ ) : (
+
+ )}
{row.name}
diff --git a/components/match-detail/basketball/basketball-stats.tsx b/components/match-detail/basketball/basketball-stats.tsx
index 8dfc759..a8c269c 100644
--- a/components/match-detail/basketball/basketball-stats.tsx
+++ b/components/match-detail/basketball/basketball-stats.tsx
@@ -1,9 +1,8 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
-import { getInitials, getLogoGradient } from "@/lib/avatar-utils";
import { MatchDetailData } from "@/types/api";
import { Image } from "expo-image";
-import { LinearGradient } from "expo-linear-gradient";
import React, { useMemo, useState } from "react";
import {
ScrollView,
@@ -161,10 +160,6 @@ export function BasketballStats({ data, isDark }: BasketballStatsProps) {
const awayTeamLogo = match.awayTeamLogo || "";
const hasHomeLogo = homeTeamLogo && homeTeamLogo.trim() !== "" && !homeTeamLogo.includes("placehold");
const hasAwayLogo = awayTeamLogo && awayTeamLogo.trim() !== "" && !awayTeamLogo.includes("placehold");
- const homeGradient = getLogoGradient(homeTeamName);
- const awayGradient = getLogoGradient(awayTeamName);
- const homeInitials = getInitials(homeTeamName);
- const awayInitials = getInitials(awayTeamName);
return (
@@ -199,12 +194,7 @@ export function BasketballStats({ data, isDark }: BasketballStatsProps) {
{hasHomeLogo ? (
) : (
-
- {homeInitials}
-
+
)}
) : (
-
- {awayInitials}
-
+
)}
diff --git a/components/match-detail/football/football-score-table.tsx b/components/match-detail/football/football-score-table.tsx
index a3714a2..06d93fe 100644
--- a/components/match-detail/football/football-score-table.tsx
+++ b/components/match-detail/football/football-score-table.tsx
@@ -1,3 +1,4 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { MatchDetailData } from "@/types/api";
import React from "react";
@@ -89,7 +90,11 @@ export function FootballScoreTable({ data, isDark }: FootballScoreTableProps) {
{rows.map((row, idx) => (
-
+ {row.logo && row.logo.trim() !== "" && !row.logo.includes("placehold") ? (
+
+ ) : (
+
+ )}
{row.name}
diff --git a/components/match-detail/league-info.tsx b/components/match-detail/league-info.tsx
index 4416b0d..2339b9a 100644
--- a/components/match-detail/league-info.tsx
+++ b/components/match-detail/league-info.tsx
@@ -1,3 +1,4 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { MatchDetailData } from "@/types/api";
@@ -25,12 +26,10 @@ export function LeagueInfo({ data, isDark }: LeagueInfoProps) {
activeOpacity={0.7}
>
- {match.leagueLogo ? (
+ {match.leagueLogo && match.leagueLogo.trim() !== "" && !match.leagueLogo.includes("placehold") ? (
) : (
-
-
-
+
)}
{match.leagueName}
diff --git a/components/match-detail/score-header.tsx b/components/match-detail/score-header.tsx
index 4c68a7e..dac928b 100644
--- a/components/match-detail/score-header.tsx
+++ b/components/match-detail/score-header.tsx
@@ -1,7 +1,7 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { addFavorite, checkFavorite, removeFavorite } from "@/lib/api";
-import { getInitials, getLogoGradient } from "@/lib/avatar-utils";
import { storage } from "@/lib/storage";
import { MatchDetailData } from "@/types/api";
import { LinearGradient } from "expo-linear-gradient";
@@ -170,10 +170,6 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
const hasFirstLogo = firstPlayerLogo && firstPlayerLogo.trim() !== "" && !firstPlayerLogo.includes("placehold");
const hasSecondLogo = secondPlayerLogo && secondPlayerLogo.trim() !== "" && !secondPlayerLogo.includes("placehold");
- const firstGradient = getLogoGradient(firstPlayerName || "");
- const secondGradient = getLogoGradient(secondPlayerName || "");
- const firstInitials = getInitials(firstPlayerName || "");
- const secondInitials = getInitials(secondPlayerName || "");
return (
) : (
-
- {firstInitials}
-
+
)}
@@ -283,14 +272,7 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
style={styles.teamLogo}
/>
) : (
-
- {secondInitials}
-
+
)}
{(() => {
const hasLogo = league.logo && league.logo.trim() !== "" && !league.logo.includes("placehold");
- const gradient = getLogoGradient(league.name || "");
- const initials = getInitials(league.name || "");
return hasLogo ? (
) : (
-
- {initials}
-
+
);
})()}
diff --git a/components/upcoming-match-card.tsx b/components/upcoming-match-card.tsx
index fd23993..70a0bc6 100644
--- a/components/upcoming-match-card.tsx
+++ b/components/upcoming-match-card.tsx
@@ -1,3 +1,4 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { Colors } from "@/constants/theme";
@@ -122,12 +123,14 @@ export function UpcomingMatchCard({
- {match.homeTeamLogo && (
+ {match.homeTeamLogo && match.homeTeamLogo.trim() !== "" && !match.homeTeamLogo.includes("placehold") ? (
+ ) : (
+
)}
- {match.awayTeamLogo && (
+ {match.awayTeamLogo && match.awayTeamLogo.trim() !== "" && !match.awayTeamLogo.includes("placehold") ? (
+ ) : (
+
)}