941 lines
21 KiB
Vue
941 lines
21 KiB
Vue
<script setup lang="ts">
|
||
import { onActivated, computed, ref, watch, onDeactivated } from 'vue';
|
||
import { useRouter } from 'vue-router';
|
||
import { useI18n } from 'vue-i18n';
|
||
import emptyMatchesImg from '../assets/images/empty-matches.svg';
|
||
import vsImg from '../assets/images/vs.png';
|
||
import cardBg from '../assets/images/card-bg.webp';
|
||
import bentoBetBg from '../assets/images/bento-bet-bg.png';
|
||
import BannerCarousel from '../components/BannerCarousel.vue';
|
||
import { usePlayerHome } from '../composables/usePlayerHome';
|
||
import TeamEmblem from '../components/TeamEmblem.vue';
|
||
import GoldSpinner from '../components/GoldSpinner.vue';
|
||
import { usePullToRefresh } from '../composables/usePullToRefresh';
|
||
import { formatLocalMatchDateTime } from '@thebet365/shared';
|
||
import type { PlayerHomeMatch } from '../composables/usePlayerHome';
|
||
|
||
type HotTab = 'hot' | 'upcoming';
|
||
|
||
const matchCardBg = `url(${cardBg})`;
|
||
const bentoBetCardBg = `url(${bentoBetBg})`;
|
||
const { t, locale } = useI18n();
|
||
const router = useRouter();
|
||
const { banners, hotMatches, upcomingMatches, loading, load, announcementItems } = usePlayerHome();
|
||
const activeFeaturedIndex = ref(0);
|
||
const touchStartX = ref(0);
|
||
const touchDeltaX = ref(0);
|
||
|
||
let rotateInterval: number | undefined;
|
||
|
||
function startFeaturedRotation() {
|
||
stopFeaturedRotation();
|
||
if (hotMatches.value.length > 1) {
|
||
rotateInterval = window.setInterval(() => {
|
||
activeFeaturedIndex.value = (activeFeaturedIndex.value + 1) % hotMatches.value.length;
|
||
}, 4500);
|
||
}
|
||
}
|
||
|
||
function stopFeaturedRotation() {
|
||
if (rotateInterval) {
|
||
window.clearInterval(rotateInterval);
|
||
rotateInterval = undefined;
|
||
}
|
||
}
|
||
|
||
watch(() => hotMatches.value.length, () => {
|
||
activeFeaturedIndex.value = 0;
|
||
startFeaturedRotation();
|
||
});
|
||
|
||
function onFeaturedTouchStart(e: TouchEvent) {
|
||
touchStartX.value = e.touches[0].clientX;
|
||
touchDeltaX.value = 0;
|
||
stopFeaturedRotation();
|
||
}
|
||
|
||
function onFeaturedTouchMove(e: TouchEvent) {
|
||
touchDeltaX.value = e.touches[0].clientX - touchStartX.value;
|
||
}
|
||
|
||
function onFeaturedTouchEnd() {
|
||
const threshold = 40;
|
||
if (hotMatches.value.length > 1) {
|
||
if (touchDeltaX.value > threshold) {
|
||
activeFeaturedIndex.value = (activeFeaturedIndex.value - 1 + hotMatches.value.length) % hotMatches.value.length;
|
||
} else if (touchDeltaX.value < -threshold) {
|
||
activeFeaturedIndex.value = (activeFeaturedIndex.value + 1) % hotMatches.value.length;
|
||
}
|
||
}
|
||
touchDeltaX.value = 0;
|
||
startFeaturedRotation();
|
||
}
|
||
|
||
const bannerFallbackTo = computed(() => {
|
||
const id = announcementItems.value[0]?.id;
|
||
return id ? `/announcements/${id}` : '/announcements';
|
||
});
|
||
|
||
const displayedMatches = computed<PlayerHomeMatch[]>(() => upcomingMatches.value);
|
||
const limitedMatches = computed(() => displayedMatches.value.slice(0, 6));
|
||
|
||
const emptyMessage = computed(() => t('home.upcoming_empty'));
|
||
|
||
const { pullDistance, refreshing, spinning, progress } = usePullToRefresh({
|
||
onRefresh: async () => { await load(true); },
|
||
});
|
||
|
||
onActivated(() => {
|
||
void load(true);
|
||
startFeaturedRotation();
|
||
});
|
||
|
||
onDeactivated(() => {
|
||
stopFeaturedRotation();
|
||
});
|
||
|
||
const pullIndicatorStyle = () => ({
|
||
height: `${pullDistance.value}px`,
|
||
opacity: Math.min(pullDistance.value / 48, 1),
|
||
});
|
||
|
||
function goMatch(id: string) {
|
||
router.push(`/match/${id}`);
|
||
}
|
||
|
||
function formatKickoff(startTime: string) {
|
||
return formatLocalMatchDateTime(startTime, locale.value, { variant: 'full' });
|
||
}
|
||
|
||
</script>
|
||
|
||
<template>
|
||
<div>
|
||
<div
|
||
class="pull-indicator"
|
||
:style="pullIndicatorStyle()"
|
||
>
|
||
<GoldSpinner v-if="spinning" :size="28" :progress="progress" :active="spinning" />
|
||
</div>
|
||
|
||
<BannerCarousel :banners="banners" :fallback-to="bannerFallbackTo" />
|
||
|
||
<div class="quick-bento">
|
||
<div
|
||
class="bento-item bento-item--large bento-item--featured-carousel"
|
||
@touchstart.passive="onFeaturedTouchStart"
|
||
@touchmove.passive="onFeaturedTouchMove"
|
||
@touchend="onFeaturedTouchEnd"
|
||
>
|
||
<!-- Fixed header, does not swipe/scroll -->
|
||
<div v-if="hotMatches.length" class="bento-header-row fixed-header">
|
||
<span class="featured-tag">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" width="12" height="12" class="tag-icon"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>
|
||
{{ t('home.hot_matches') }}
|
||
</span>
|
||
<span class="bento-badge">HOT</span>
|
||
</div>
|
||
|
||
<div class="carousel-viewport">
|
||
<div
|
||
class="carousel-track"
|
||
:style="{ transform: `translateX(-${activeFeaturedIndex * 100}%)` }"
|
||
>
|
||
<template v-if="hotMatches.length">
|
||
<div
|
||
v-for="match in hotMatches"
|
||
:key="match.id"
|
||
class="carousel-slide"
|
||
@click="goMatch(match.id)"
|
||
>
|
||
<div class="bento-content--vertical">
|
||
<div class="bento-header-row placeholder-header" aria-hidden="true">
|
||
<span class="featured-tag">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" width="12" height="12" class="tag-icon"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>
|
||
{{ t('home.hot_matches') }}
|
||
</span>
|
||
<span class="bento-badge">HOT</span>
|
||
</div>
|
||
|
||
<div class="featured-vs-area">
|
||
<div class="featured-team">
|
||
<TeamEmblem
|
||
size="sm"
|
||
:team-code="match.homeTeamCode"
|
||
:team-name="match.homeTeamName"
|
||
:logo-url="match.homeTeamLogoUrl"
|
||
/>
|
||
<span class="featured-team-name">{{ match.homeTeamName }}</span>
|
||
</div>
|
||
|
||
<span class="featured-vs">VS</span>
|
||
|
||
<div class="featured-team">
|
||
<TeamEmblem
|
||
size="sm"
|
||
:team-code="match.awayTeamCode"
|
||
:team-name="match.awayTeamName"
|
||
:logo-url="match.awayTeamLogoUrl"
|
||
/>
|
||
<span class="featured-team-name">{{ match.awayTeamName }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="featured-footer">
|
||
<span class="featured-time">{{ formatKickoff(match.startTime) }}</span>
|
||
<span class="featured-action-btn">{{ t('announcements.go_link') }} ›</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<div v-else class="carousel-slide" @click="router.push('/bet')">
|
||
<div class="bento-content--vertical">
|
||
<div class="bento-header-row">
|
||
<span class="bento-icon bento-icon--bet">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" width="22" height="22"><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 000 20 14.5 14.5 0 000-20M2 12h20"/></svg>
|
||
</span>
|
||
<span class="bento-badge">HOT</span>
|
||
</div>
|
||
<div class="bento-text">
|
||
<span class="bento-title bento-title--lg">{{ t('nav.bet') }}</span>
|
||
<span class="bento-desc">{{ t('home.bento_desc') }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="hotMatches.length > 1" class="carousel-dots">
|
||
<span
|
||
v-for="(_, i) in hotMatches"
|
||
:key="i"
|
||
class="carousel-dot"
|
||
:class="{ active: i === activeFeaturedIndex }"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<button type="button" class="bento-item bento-item--small" @click="router.push('/wallet/recharge')">
|
||
<span class="bento-icon bento-icon--recharge">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"><rect x="2" y="5" width="20" height="14" rx="2"/><path d="M2 10h20M12 15h4"/></svg>
|
||
</span>
|
||
<span class="bento-title bento-title--sm">{{ t('recharge.title') }}</span>
|
||
</button>
|
||
|
||
<button type="button" class="bento-item bento-item--small" @click="router.push('/bets')">
|
||
<span class="bento-icon bento-icon--history">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
|
||
<path d="M6 4h12a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1Z" stroke-linejoin="round"/>
|
||
<path d="M8 9h8M8 12.5h8M8 16h5" stroke-linecap="round"/>
|
||
</svg>
|
||
</span>
|
||
<span class="bento-title bento-title--sm">{{ t('home.view_bet_history') }}</span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="section-header">
|
||
<div class="section-title">{{ t('home.upcoming_tab') }}</div>
|
||
</div>
|
||
|
||
<div
|
||
v-for="(match, index) in limitedMatches"
|
||
:key="match.id"
|
||
class="match-card"
|
||
:class="{ 'match-card--live-anim': index < 3 }"
|
||
@click="goMatch(match.id)"
|
||
>
|
||
<div class="match-info">
|
||
<div class="match-teams">{{ match.homeTeamName }} vs {{ match.awayTeamName }}</div>
|
||
<div class="match-time">{{ formatKickoff(match.startTime) }}</div>
|
||
</div>
|
||
<div class="match-flags" aria-hidden="true">
|
||
<TeamEmblem
|
||
size="md"
|
||
:team-code="match.homeTeamCode"
|
||
:team-name="match.homeTeamName"
|
||
:logo-url="match.homeTeamLogoUrl"
|
||
/>
|
||
<div class="vs-arena">
|
||
<svg class="hz-lightning" viewBox="0 0 72 28" aria-hidden="true">
|
||
<defs>
|
||
<linearGradient :id="`hzBoltGrad-${match.id}`" x1="0%" y1="0%" x2="100%" y2="0%">
|
||
<stop offset="0%" stop-color="#5eb8ff" stop-opacity="0.2" />
|
||
<stop offset="35%" stop-color="#b8ecff" stop-opacity="1" />
|
||
<stop offset="50%" stop-color="#ffffff" stop-opacity="1" />
|
||
<stop offset="65%" stop-color="#ffd080" stop-opacity="1" />
|
||
<stop offset="100%" stop-color="#ff9040" stop-opacity="0.2" />
|
||
</linearGradient>
|
||
</defs>
|
||
<path
|
||
class="hz-path hz-path-main"
|
||
:stroke="`url(#hzBoltGrad-${match.id})`"
|
||
d="M1 14 H16 L20 5 L24 23 L28 9 L32 14 H40 L44 6 L48 22 L52 12 L56 14 H71"
|
||
/>
|
||
<path
|
||
class="hz-path hz-path-sub"
|
||
:stroke="`url(#hzBoltGrad-${match.id})`"
|
||
d="M3 19 H14 L18 15 L22 19 H50 L54 16 L58 19 H69"
|
||
/>
|
||
</svg>
|
||
<span class="hz-beam" aria-hidden="true" />
|
||
<img :src="vsImg" alt="" class="vs-img" />
|
||
</div>
|
||
<TeamEmblem
|
||
size="md"
|
||
:team-code="match.awayTeamCode"
|
||
:team-name="match.awayTeamName"
|
||
:logo-url="match.awayTeamLogoUrl"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="displayedMatches.length > 6" class="view-all-container">
|
||
<button type="button" class="view-all-link" @click="router.push('/bet')">
|
||
{{ t('home.view_all_matches') }} ›
|
||
</button>
|
||
</div>
|
||
|
||
<div v-if="!loading && !displayedMatches.length" class="empty">
|
||
<img :src="emptyMatchesImg" alt="" class="empty-icon" />
|
||
<p>{{ emptyMessage }}</p>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.pull-indicator {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
overflow: hidden;
|
||
transition: height 0.15s ease;
|
||
}
|
||
|
||
.section-header {
|
||
margin-top: 14px;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.quick-bento {
|
||
display: grid;
|
||
grid-template-columns: 1.2fr 1fr;
|
||
grid-template-rows: 54px 54px;
|
||
gap: 8px;
|
||
margin-bottom: 16px;
|
||
padding: 0 2px;
|
||
}
|
||
|
||
.bento-item {
|
||
display: flex;
|
||
align-items: center;
|
||
border-radius: 12px;
|
||
border: 1px solid #E5E7EB;
|
||
background: #FFFFFF;
|
||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
||
cursor: pointer;
|
||
transition: transform 0.15s, box-shadow 0.15s, border-color 0.15s;
|
||
padding: 10px 12px;
|
||
text-decoration: none;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.bento-item:active {
|
||
transform: scale(0.97);
|
||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
|
||
}
|
||
|
||
.bento-item--large {
|
||
grid-row: 1 / 3;
|
||
height: 100%;
|
||
background: linear-gradient(135deg, #F3F8FC 0%, #FFFFFF 100%);
|
||
border-color: rgba(0, 61, 107, 0.15);
|
||
position: relative;
|
||
overflow: hidden;
|
||
padding: 0;
|
||
}
|
||
|
||
.bento-item--featured-carousel {
|
||
/* Carousel container styles */
|
||
}
|
||
|
||
.carousel-viewport {
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
position: relative;
|
||
}
|
||
|
||
.carousel-track {
|
||
display: flex;
|
||
height: 100%;
|
||
width: 100%;
|
||
transition: transform 0.4s cubic-bezier(0.25, 1, 0.5, 1);
|
||
}
|
||
|
||
.carousel-slide {
|
||
flex: 0 0 100%;
|
||
min-width: 100%;
|
||
height: 100%;
|
||
padding: 10px 10px 8px 12px;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.carousel-dots {
|
||
position: absolute;
|
||
bottom: 4px;
|
||
left: 0;
|
||
right: 0;
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 4px;
|
||
z-index: 10;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.carousel-dot {
|
||
width: 4px;
|
||
height: 4px;
|
||
border-radius: 50%;
|
||
background: rgba(0, 61, 107, 0.15);
|
||
transition: background 0.25s, width 0.25s;
|
||
}
|
||
|
||
.carousel-dot.active {
|
||
width: 12px;
|
||
border-radius: 2px;
|
||
background: #003D6B;
|
||
}
|
||
|
||
.featured-tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 3px;
|
||
font-size: 9px;
|
||
font-weight: 700;
|
||
color: #003D6B;
|
||
background: rgba(0, 61, 107, 0.06);
|
||
padding: 3px 6px;
|
||
border-radius: 6px;
|
||
line-height: 1;
|
||
}
|
||
|
||
.tag-icon {
|
||
color: #F97316;
|
||
}
|
||
|
||
.featured-vs-area {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-around;
|
||
width: 100%;
|
||
margin: 6px 0;
|
||
gap: 4px;
|
||
}
|
||
|
||
.featured-team {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 2px;
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.featured-team-name {
|
||
font-size: 9px;
|
||
font-weight: 800;
|
||
color: #1A1A2E;
|
||
text-align: center;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
width: 100%;
|
||
}
|
||
|
||
.featured-vs {
|
||
font-size: 11px;
|
||
font-weight: 800;
|
||
color: #F97316;
|
||
font-style: italic;
|
||
opacity: 0.95;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.featured-footer {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
width: 100%;
|
||
border-top: 1px dashed rgba(0, 61, 107, 0.1);
|
||
padding-top: 5px;
|
||
margin-top: 2px;
|
||
}
|
||
|
||
.featured-time {
|
||
font-size: 8px;
|
||
color: #6B7280;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.featured-action-btn {
|
||
font-size: 8.5px;
|
||
font-weight: 800;
|
||
color: #003D6B;
|
||
background: rgba(0, 61, 107, 0.05);
|
||
padding: 2px 6px;
|
||
border-radius: 4px;
|
||
transition: background 0.15s;
|
||
}
|
||
|
||
.bento-item--featured:active .featured-action-btn {
|
||
background: rgba(0, 61, 107, 0.12);
|
||
}
|
||
|
||
.bento-item--large .bento-title {
|
||
color: #003D6B;
|
||
}
|
||
|
||
.bento-item--large .bento-desc {
|
||
color: #6B7280;
|
||
}
|
||
|
||
.bento-item--large .bento-badge {
|
||
background: #F97316;
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
.bento-content--vertical {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
height: 100%;
|
||
width: 100%;
|
||
}
|
||
|
||
.bento-header-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
width: 100%;
|
||
}
|
||
|
||
.fixed-header {
|
||
position: absolute;
|
||
top: 10px;
|
||
left: 12px;
|
||
right: 10px;
|
||
width: auto;
|
||
z-index: 20;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.placeholder-header {
|
||
visibility: hidden;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.bento-badge {
|
||
font-size: 8px;
|
||
font-weight: 800;
|
||
color: #FFFFFF;
|
||
background: #003D6B;
|
||
padding: 2px 5px;
|
||
border-radius: 4px;
|
||
letter-spacing: 0.05em;
|
||
line-height: 1;
|
||
transform: translateY(2px);
|
||
}
|
||
|
||
.bento-item--large:active {
|
||
border-color: rgba(0, 61, 107, 0.3);
|
||
}
|
||
|
||
.bento-item--small {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
gap: 8px;
|
||
justify-content: flex-start;
|
||
height: 100%;
|
||
}
|
||
|
||
.bento-content {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.bento-icon {
|
||
width: 34px;
|
||
height: 34px;
|
||
border-radius: 8px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.bento-item--large .bento-icon {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 10px;
|
||
}
|
||
|
||
.bento-icon--bet {
|
||
background: rgba(0, 61, 107, 0.08);
|
||
color: #003D6B;
|
||
}
|
||
|
||
.bento-icon--recharge {
|
||
background: rgba(5, 150, 105, 0.08);
|
||
color: #059669;
|
||
}
|
||
|
||
.bento-icon--history {
|
||
background: rgba(248, 151, 31, 0.08);
|
||
color: #E8870A;
|
||
}
|
||
|
||
.bento-text {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 1px;
|
||
}
|
||
|
||
.bento-title {
|
||
font-size: 13px;
|
||
font-weight: 800;
|
||
color: #1A1A2E;
|
||
text-align: left;
|
||
}
|
||
|
||
.bento-title--sm {
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.bento-title--lg {
|
||
font-size: 14.5px;
|
||
font-weight: 800;
|
||
margin-bottom: 2px;
|
||
}
|
||
|
||
.bento-desc {
|
||
font-size: 9.5px;
|
||
color: #6B7280;
|
||
font-weight: 500;
|
||
text-align: left;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 15px;
|
||
font-weight: 700;
|
||
color: #1A1A2E;
|
||
margin: 0 0 8px;
|
||
padding-left: 10px;
|
||
border-left: 3px solid #003D6B;
|
||
line-height: 1.3;
|
||
}
|
||
|
||
.match-card {
|
||
position: relative;
|
||
isolation: isolate;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
margin-bottom: 8px;
|
||
padding: 10px 12px;
|
||
min-height: 60px;
|
||
border: 1px solid #E5E7EB;
|
||
border-radius: 8px;
|
||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||
background: #FFFFFF;
|
||
cursor: pointer;
|
||
transition: transform 0.2s, box-shadow 0.2s;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.match-card::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
background: linear-gradient(135deg, rgba(0, 61, 107, 0.02) 0%, transparent 60%);
|
||
z-index: 0;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.match-card:active {
|
||
transform: scale(0.995);
|
||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.match-info,
|
||
.match-flags {
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.match-info {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.match-teams {
|
||
font-weight: 700;
|
||
margin-bottom: 4px;
|
||
font-size: 14px;
|
||
line-height: 1.3;
|
||
color: #1A1A2E;
|
||
}
|
||
|
||
.match-time {
|
||
font-size: 12px;
|
||
color: #6B7280;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.match-flags {
|
||
flex-shrink: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 3px;
|
||
max-width: 46%;
|
||
}
|
||
|
||
.vs-arena {
|
||
position: relative;
|
||
flex-shrink: 0;
|
||
width: 52px;
|
||
height: 42px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.hz-lightning {
|
||
position: absolute;
|
||
inset: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
z-index: 1;
|
||
pointer-events: none;
|
||
overflow: visible;
|
||
}
|
||
|
||
.hz-path {
|
||
fill: none;
|
||
stroke-width: 2.2;
|
||
stroke-linecap: round;
|
||
stroke-linejoin: round;
|
||
filter: drop-shadow(0 0 4px rgba(0, 102, 204, 0.6)) drop-shadow(0 0 8px rgba(0, 91, 159, 0.35));
|
||
opacity: 0;
|
||
}
|
||
|
||
.match-card--live-anim .hz-path-main {
|
||
animation: hz-strike-main 2.6s ease-in-out infinite;
|
||
}
|
||
|
||
.match-card--live-anim .hz-path-sub {
|
||
stroke-width: 1.6;
|
||
animation: hz-strike-sub 2.6s ease-in-out infinite;
|
||
animation-delay: 0.12s;
|
||
}
|
||
|
||
.match-card--live-anim .hz-beam {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
top: 50%;
|
||
height: 2px;
|
||
transform: translateY(-50%);
|
||
pointer-events: none;
|
||
z-index: 1;
|
||
background: linear-gradient(
|
||
90deg,
|
||
rgba(0, 91, 159, 0) 0%,
|
||
rgba(0, 102, 204, 0.7) 28%,
|
||
#0066CC 50%,
|
||
rgba(0, 91, 159, 0.7) 72%,
|
||
rgba(0, 61, 107, 0) 100%
|
||
);
|
||
opacity: 0;
|
||
filter: blur(0.4px);
|
||
animation: hz-beam-flash 2.6s ease-in-out infinite;
|
||
}
|
||
|
||
.hz-beam {
|
||
display: none;
|
||
}
|
||
|
||
.vs-img {
|
||
position: relative;
|
||
z-index: 0;
|
||
width: 40px;
|
||
height: auto;
|
||
object-fit: contain;
|
||
filter: drop-shadow(0 0 3px rgba(0, 61, 107, 0.25));
|
||
}
|
||
|
||
.match-card--live-anim .vs-img {
|
||
animation: vs-glow 2.4s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes hz-strike-main {
|
||
0%,
|
||
72%,
|
||
100% {
|
||
opacity: 0;
|
||
}
|
||
|
||
74% {
|
||
opacity: 1;
|
||
}
|
||
|
||
75% {
|
||
opacity: 0.25;
|
||
}
|
||
|
||
76% {
|
||
opacity: 0.95;
|
||
}
|
||
|
||
78% {
|
||
opacity: 0;
|
||
}
|
||
}
|
||
|
||
@keyframes hz-strike-sub {
|
||
0%,
|
||
74%,
|
||
100% {
|
||
opacity: 0;
|
||
}
|
||
|
||
76% {
|
||
opacity: 0.85;
|
||
}
|
||
|
||
77% {
|
||
opacity: 0.2;
|
||
}
|
||
|
||
78% {
|
||
opacity: 0.7;
|
||
}
|
||
|
||
80% {
|
||
opacity: 0;
|
||
}
|
||
}
|
||
|
||
@keyframes hz-beam-flash {
|
||
0%,
|
||
71%,
|
||
100% {
|
||
opacity: 0;
|
||
transform: translateY(-50%) scaleX(0.6);
|
||
}
|
||
|
||
73% {
|
||
opacity: 0.85;
|
||
transform: translateY(-50%) scaleX(1);
|
||
}
|
||
|
||
75% {
|
||
opacity: 0.15;
|
||
transform: translateY(-50%) scaleX(0.95);
|
||
}
|
||
|
||
76% {
|
||
opacity: 0.75;
|
||
transform: translateY(-50%) scaleX(1);
|
||
}
|
||
|
||
78% {
|
||
opacity: 0;
|
||
transform: translateY(-50%) scaleX(1.05);
|
||
}
|
||
}
|
||
|
||
@keyframes vs-glow {
|
||
0%,
|
||
100% {
|
||
opacity: 0.82;
|
||
filter: drop-shadow(0 0 2px rgba(0, 61, 107, 0.2));
|
||
}
|
||
|
||
50% {
|
||
opacity: 1;
|
||
filter:
|
||
drop-shadow(0 0 3px rgba(0, 102, 204, 0.5))
|
||
drop-shadow(0 0 6px rgba(0, 61, 107, 0.25));
|
||
}
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.vs-img {
|
||
animation: none;
|
||
filter: drop-shadow(0 0 3px rgba(0, 61, 107, 0.25));
|
||
}
|
||
|
||
.hz-path,
|
||
.hz-beam {
|
||
animation: none;
|
||
opacity: 0;
|
||
}
|
||
}
|
||
|
||
.empty {
|
||
text-align: center;
|
||
color: #6B7280;
|
||
padding: 28px 16px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.empty-icon {
|
||
width: 72px;
|
||
height: 72px;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.view-all-container {
|
||
display: flex;
|
||
justify-content: center;
|
||
margin-top: 12px;
|
||
margin-bottom: 24px;
|
||
padding: 0 2px;
|
||
}
|
||
|
||
.view-all-link {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: none;
|
||
border: none;
|
||
font-family: inherit;
|
||
font-size: 13px;
|
||
font-weight: 700;
|
||
color: #003D6B;
|
||
cursor: pointer;
|
||
padding: 6px 12px;
|
||
outline: none;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.view-all-link:hover {
|
||
opacity: 0.85;
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.view-all-link:active {
|
||
transform: scale(0.97);
|
||
opacity: 0.7;
|
||
}
|
||
</style>
|