feat(player): 优化桌面端优胜冠军相关组件与侧边栏布局,适配主题变量
This commit is contained in:
@@ -24,10 +24,10 @@ const { visible, message } = useAppToast();
|
|||||||
max-width: min(90vw, 360px);
|
max-width: min(90vw, 360px);
|
||||||
padding: 10px 18px;
|
padding: 10px 18px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 1px solid var(--border-gold-soft);
|
border: 1px solid var(--primary);
|
||||||
background: rgba(22, 22, 22, 0.96);
|
background: var(--bg-card);
|
||||||
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
|
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.15);
|
||||||
color: var(--primary-light);
|
color: var(--primary);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -3,9 +3,6 @@ import { computed } from 'vue';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import MatchBetCard from './MatchBetCard.vue';
|
import MatchBetCard from './MatchBetCard.vue';
|
||||||
import saishiImg from '../assets/images/saishi.webp';
|
import saishiImg from '../assets/images/saishi.webp';
|
||||||
import cardBg from '../assets/images/card-bg.webp';
|
|
||||||
|
|
||||||
const matchCardBg = `url(${cardBg})`;
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
leagueId: string;
|
leagueId: string;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import DesktopOddsBetPopover from './DesktopOddsBetPopover.vue';
|
|||||||
import SportsCategoryBar from './SportsCategoryBar.vue';
|
import SportsCategoryBar from './SportsCategoryBar.vue';
|
||||||
import LeagueSidebar from './LeagueSidebar.vue';
|
import LeagueSidebar from './LeagueSidebar.vue';
|
||||||
import MatchSidebar from './MatchSidebar.vue';
|
import MatchSidebar from './MatchSidebar.vue';
|
||||||
|
import OutrightSidebar from './OutrightSidebar.vue';
|
||||||
import DesktopBetSlipRail from './DesktopBetSlipRail.vue';
|
import DesktopBetSlipRail from './DesktopBetSlipRail.vue';
|
||||||
import FloatingMailbox from '../FloatingMailbox.vue';
|
import FloatingMailbox from '../FloatingMailbox.vue';
|
||||||
import AnnouncementMarquee from '../AnnouncementMarquee.vue';
|
import AnnouncementMarquee from '../AnnouncementMarquee.vue';
|
||||||
@@ -43,6 +44,9 @@ const layoutMode = computed<'betting' | 'account' | 'hub' | 'marketing'>(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const isMatchDetail = computed(() => route.path.startsWith('/match/'));
|
const isMatchDetail = computed(() => route.path.startsWith('/match/'));
|
||||||
|
const isDetailPage = computed(
|
||||||
|
() => route.path.startsWith('/match/') || route.path.startsWith('/outright/'),
|
||||||
|
);
|
||||||
const isBettingDetail = computed(
|
const isBettingDetail = computed(
|
||||||
() => route.path.startsWith('/match/') || route.path.startsWith('/outright/'),
|
() => route.path.startsWith('/match/') || route.path.startsWith('/outright/'),
|
||||||
);
|
);
|
||||||
@@ -98,8 +102,9 @@ watch(
|
|||||||
</div>
|
</div>
|
||||||
<div class="desktop-layout-betting">
|
<div class="desktop-layout-betting">
|
||||||
<aside class="desktop-betting-left">
|
<aside class="desktop-betting-left">
|
||||||
<LeagueSidebar v-if="!isMatchDetail" />
|
<LeagueSidebar v-if="!isDetailPage" />
|
||||||
<MatchSidebar v-else />
|
<MatchSidebar v-else-if="isMatchDetail" />
|
||||||
|
<OutrightSidebar v-else />
|
||||||
</aside>
|
</aside>
|
||||||
<main class="desktop-betting-center" :class="{ 'is-betting-detail': isBettingDetail }">
|
<main class="desktop-betting-center" :class="{ 'is-betting-detail': isBettingDetail }">
|
||||||
<RouterView v-slot="{ Component, route: viewRoute }">
|
<RouterView v-slot="{ Component, route: viewRoute }">
|
||||||
|
|||||||
@@ -1,21 +1,37 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted } from 'vue';
|
import { computed, onMounted, watch } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useMatchFilters } from '../../composables/useMatchFilters';
|
import { useMatchFilters } from '../../composables/useMatchFilters';
|
||||||
import { useDesktopParlayMatches } from '../../composables/useDesktopParlayMatches';
|
import { useDesktopParlayMatches } from '../../composables/useDesktopParlayMatches';
|
||||||
|
import { useOutrightEvents } from '../../composables/useOutrightEvents';
|
||||||
import {
|
import {
|
||||||
isAfterLocalTodayMatchWindow as isAfterTodayMatchWindow,
|
isAfterLocalTodayMatchWindow as isAfterTodayMatchWindow,
|
||||||
isInLocalTodayMatchWindow as isInTodayMatchWindow,
|
isInLocalTodayMatchWindow as isInTodayMatchWindow,
|
||||||
} from '@thebet365/shared';
|
} from '@thebet365/shared';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
const { parlayMatches, loadParlayMatches } = useDesktopParlayMatches();
|
const { parlayMatches, loadParlayMatches } = useDesktopParlayMatches();
|
||||||
const { searchQuery, filterState, toggleLeague, clearFilters, isLeagueSelected } = useMatchFilters();
|
const { searchQuery, filterState, toggleLeague, clearFilters, isLeagueSelected } = useMatchFilters();
|
||||||
|
const { events: outrightEvents, load: loadOutrightEvents } = useOutrightEvents();
|
||||||
|
|
||||||
onMounted(() => {
|
const isOutrightMode = computed(() => {
|
||||||
void loadParlayMatches();
|
return route.query.tab === 'outright';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
isOutrightMode,
|
||||||
|
(outright) => {
|
||||||
|
if (outright) {
|
||||||
|
void loadOutrightEvents({ silent: outrightEvents.value.length > 0 });
|
||||||
|
} else {
|
||||||
|
void loadParlayMatches();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
|
||||||
function normalizeLeagueName(name: string): string {
|
function normalizeLeagueName(name: string): string {
|
||||||
return name
|
return name
|
||||||
.replace(/\.unit$/i, '')
|
.replace(/\.unit$/i, '')
|
||||||
@@ -26,36 +42,57 @@ function normalizeLeagueName(name: string): string {
|
|||||||
|
|
||||||
const availableLeagues = computed(() => {
|
const availableLeagues = computed(() => {
|
||||||
const map = new Map<string, { id: string; name: string; count: number }>();
|
const map = new Map<string, { id: string; name: string; count: number }>();
|
||||||
const now = new Date();
|
|
||||||
const keyword = searchQuery.value.trim().toLowerCase();
|
const keyword = searchQuery.value.trim().toLowerCase();
|
||||||
|
|
||||||
for (const m of parlayMatches.value) {
|
if (isOutrightMode.value) {
|
||||||
if (keyword) {
|
for (const e of outrightEvents.value) {
|
||||||
const haystack = `${m.homeTeamName} ${m.awayTeamName} ${m.leagueName}`.toLowerCase();
|
if (keyword) {
|
||||||
if (!haystack.includes(keyword)) continue;
|
const haystack = `${e.title} ${e.leagueName || ''}`.toLowerCase();
|
||||||
|
if (!haystack.includes(keyword)) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = e.leagueId ?? e.leagueName ?? 'unknown';
|
||||||
|
const existing = map.get(id);
|
||||||
|
if (existing) {
|
||||||
|
existing.count += 1;
|
||||||
|
} else {
|
||||||
|
map.set(id, {
|
||||||
|
id,
|
||||||
|
name: normalizeLeagueName(e.leagueName || e.title),
|
||||||
|
count: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
const now = new Date();
|
||||||
|
for (const m of parlayMatches.value) {
|
||||||
|
if (keyword) {
|
||||||
|
const haystack = `${m.homeTeamName} ${m.awayTeamName} ${m.leagueName}`.toLowerCase();
|
||||||
|
if (!haystack.includes(keyword)) continue;
|
||||||
|
}
|
||||||
|
|
||||||
let timeMatch = true;
|
let timeMatch = true;
|
||||||
if (filterState.value.time === 'today') {
|
if (filterState.value.time === 'today') {
|
||||||
timeMatch = isInTodayMatchWindow(m.startTime, now);
|
timeMatch = isInTodayMatchWindow(m.startTime, now);
|
||||||
} else if (filterState.value.time === 'early') {
|
} else if (filterState.value.time === 'early') {
|
||||||
timeMatch = isAfterTodayMatchWindow(m.startTime, now);
|
timeMatch = isAfterTodayMatchWindow(m.startTime, now);
|
||||||
}
|
}
|
||||||
if (!timeMatch) continue;
|
if (!timeMatch) continue;
|
||||||
|
|
||||||
if (filterState.value.status === 'open' && m.matchPhase !== 'open' && m.matchPhase !== undefined) continue;
|
if (filterState.value.status === 'open' && m.matchPhase !== 'open' && m.matchPhase !== undefined) continue;
|
||||||
if (filterState.value.status === 'settled' && m.matchPhase !== 'settled') continue;
|
if (filterState.value.status === 'settled' && m.matchPhase !== 'settled') continue;
|
||||||
|
|
||||||
const id = m.leagueId ?? m.leagueName;
|
const id = m.leagueId ?? m.leagueName;
|
||||||
const existing = map.get(id);
|
const existing = map.get(id);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
existing.count += 1;
|
existing.count += 1;
|
||||||
} else {
|
} else {
|
||||||
map.set(id, {
|
map.set(id, {
|
||||||
id,
|
id,
|
||||||
name: normalizeLeagueName(m.leagueName),
|
name: normalizeLeagueName(m.leagueName),
|
||||||
count: 1,
|
count: 1,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +118,7 @@ function onToggleLeague(leagueId: string) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sidebar-section">
|
<div v-if="!isOutrightMode" class="sidebar-section">
|
||||||
<div class="section-hdr">{{ t('bet.filter_time') }}</div>
|
<div class="section-hdr">{{ t('bet.filter_time') }}</div>
|
||||||
<div class="time-filters">
|
<div class="time-filters">
|
||||||
<button
|
<button
|
||||||
@@ -136,7 +173,7 @@ function onToggleLeague(leagueId: string) {
|
|||||||
<span class="league-count">{{ lg.count }}</span>
|
<span class="league-count">{{ lg.count }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="availableLeagues.length === 0" class="empty-leagues">
|
<div v-if="availableLeagues.length === 0" class="empty-leagues">
|
||||||
{{ t('bet.no_matches') }}
|
{{ isOutrightMode ? t('bet.no_outright') : t('bet.no_matches') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
265
apps/player/src/components/desktop/OutrightSidebar.vue
Normal file
265
apps/player/src/components/desktop/OutrightSidebar.vue
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, ref, watch, nextTick } from 'vue';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useMatchFilters } from '../../composables/useMatchFilters';
|
||||||
|
import { useOutrightEvents } from '../../composables/useOutrightEvents';
|
||||||
|
import GoldSpinner from '../GoldSpinner.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const { searchQuery } = useMatchFilters();
|
||||||
|
const { events: outrightEvents, loading, load: loadOutrightEvents } = useOutrightEvents();
|
||||||
|
|
||||||
|
const listRef = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
void loadOutrightEvents({ silent: outrightEvents.value.length > 0 }).then(() => {
|
||||||
|
scrollToActive();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const currentOutrightId = computed(() => {
|
||||||
|
const id = route.params.id;
|
||||||
|
return Array.isArray(id) ? id[0] : id;
|
||||||
|
});
|
||||||
|
|
||||||
|
function normalizeLeagueName(name: string): string {
|
||||||
|
return name
|
||||||
|
.replace(/\.unit$/i, '')
|
||||||
|
.replace(/[-_]+/g, ' ')
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredEvents = computed(() => {
|
||||||
|
const keyword = searchQuery.value.trim().toLowerCase();
|
||||||
|
return outrightEvents.value.filter((e) => {
|
||||||
|
// If it's the active event, always show it
|
||||||
|
const isCurrent = String(e.id) === String(currentOutrightId.value);
|
||||||
|
if (isCurrent) return true;
|
||||||
|
|
||||||
|
if (keyword) {
|
||||||
|
const haystack = `${e.title} ${e.leagueName || ''}`.toLowerCase();
|
||||||
|
if (!haystack.includes(keyword)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function goOutright(id: string) {
|
||||||
|
router.replace(`/outright/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scrollToActive() {
|
||||||
|
nextTick(() => {
|
||||||
|
if (!listRef.value) return;
|
||||||
|
const activeEl = listRef.value.querySelector('.active') as HTMLElement;
|
||||||
|
if (activeEl) {
|
||||||
|
activeEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(currentOutrightId, scrollToActive);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="outright-sidebar">
|
||||||
|
<div class="search-box">
|
||||||
|
<input
|
||||||
|
v-model="searchQuery"
|
||||||
|
type="text"
|
||||||
|
:placeholder="t('nav.search')"
|
||||||
|
class="sidebar-search-input"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-section outrights-section">
|
||||||
|
<div class="section-hdr">
|
||||||
|
<span>{{ t('bet.tab_outright') || '优胜冠军' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="outrights-list" ref="listRef">
|
||||||
|
<div v-if="loading && !filteredEvents.length" class="sidebar-loading">
|
||||||
|
<GoldSpinner :size="24" />
|
||||||
|
</div>
|
||||||
|
<template v-else>
|
||||||
|
<div
|
||||||
|
v-for="e in filteredEvents"
|
||||||
|
:key="e.id"
|
||||||
|
class="outright-card"
|
||||||
|
:class="{ active: String(e.id) === String(currentOutrightId) }"
|
||||||
|
@click="goOutright(e.id)"
|
||||||
|
>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="league-tag" :title="e.leagueName">{{ normalizeLeagueName(e.leagueName || e.title) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="event-title" :title="e.title">{{ e.title }}</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<span class="selections-badge">
|
||||||
|
{{ e.selections?.length || 0 }} {{ t('bet.selections') || '项' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="filteredEvents.length === 0 && !loading" class="empty-outrights">
|
||||||
|
{{ t('bet.no_outright') }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.outright-sidebar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
padding: 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
padding: 0 12px 10px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-search-input {
|
||||||
|
width: 100%;
|
||||||
|
background: var(--bg-card) !important;
|
||||||
|
border: 1px solid var(--border) !important;
|
||||||
|
color: var(--text);
|
||||||
|
padding: 6px 10px;
|
||||||
|
font-size: 11px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-search-input:focus {
|
||||||
|
border-color: var(--border-active) !important;
|
||||||
|
box-shadow: 0 0 0 2px rgba(0, 102, 204, 0.1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-section {
|
||||||
|
padding: 10px 12px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-hdr {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 800;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--text-muted);
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outrights-section {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 0;
|
||||||
|
border-bottom: none;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outrights-list {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin-right: -4px;
|
||||||
|
padding-right: 4px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-loading {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 30px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-outrights {
|
||||||
|
padding: 16px 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.outright-card {
|
||||||
|
padding: 12px 10px;
|
||||||
|
background: var(--bg-body);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outright-card:hover {
|
||||||
|
border-color: var(--border-active);
|
||||||
|
background: var(--bg-hover) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outright-card.active {
|
||||||
|
border-color: var(--primary) !important;
|
||||||
|
background: rgba(0, 102, 204, 0.08) !important;
|
||||||
|
box-shadow: 0 0 8px rgba(0, 102, 204, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.league-tag {
|
||||||
|
font-size: 9px;
|
||||||
|
color: var(--primary-light);
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-title {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text);
|
||||||
|
line-height: 1.3;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outright-card.active .event-title {
|
||||||
|
color: var(--primary-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selections-badge {
|
||||||
|
font-size: 9px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-weight: 700;
|
||||||
|
background: var(--bg-card);
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
.outright-card.active .selections-badge {
|
||||||
|
background: rgba(0, 102, 204, 0.15);
|
||||||
|
color: var(--primary-light);
|
||||||
|
border-color: rgba(0, 102, 204, 0.3);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -545,7 +545,7 @@ function formatOdds(odds: string) {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
background: rgba(0, 0, 0, 0.35);
|
background: var(--bg-hover);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
@@ -646,7 +646,7 @@ function formatOdds(odds: string) {
|
|||||||
.btn-cancel {
|
.btn-cancel {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background: #1a1a1a;
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@@ -687,7 +687,7 @@ function formatOdds(odds: string) {
|
|||||||
.summary {
|
.summary {
|
||||||
margin: 12px 0 14px;
|
margin: 12px 0 14px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background: rgba(0, 0, 0, 0.35);
|
background: var(--bg-hover);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,6 @@ import { computed } from 'vue';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import OutrightOptionCard from './OutrightOptionCard.vue';
|
import OutrightOptionCard from './OutrightOptionCard.vue';
|
||||||
import saishiImg from '../../assets/images/saishi.webp';
|
import saishiImg from '../../assets/images/saishi.webp';
|
||||||
import cardBg from '../../assets/images/card-bg.webp';
|
|
||||||
|
|
||||||
const matchCardBg = `url(${cardBg})`;
|
|
||||||
|
|
||||||
export interface OutrightSelection {
|
export interface OutrightSelection {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -117,16 +114,6 @@ const isSettled = computed(() => props.event.bettingOpen === false || props.even
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.event-head::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
background: v-bind(matchCardBg) center / 100% 100% no-repeat;
|
|
||||||
opacity: 0.25;
|
|
||||||
z-index: -1;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle-icon {
|
.toggle-icon {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
width: 26px;
|
width: 26px;
|
||||||
|
|||||||
@@ -86,42 +86,37 @@ onUnmounted(() => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding: 8px 4px 6px;
|
padding: 10px 4px 8px;
|
||||||
border-radius: 6px;
|
border-radius: 8px;
|
||||||
background: linear-gradient(180deg, #1a1a1a 0%, #0d0d0d 100%);
|
background: var(--bg-card);
|
||||||
border: 1px solid rgba(140, 140, 140, 0.35);
|
border: 1px solid var(--border);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 6px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.option-card::before {
|
.option-card:hover:not(.option-card--disabled) {
|
||||||
content: '';
|
border-color: var(--border-active);
|
||||||
position: absolute;
|
background: var(--bg-hover) !important;
|
||||||
inset: 0;
|
|
||||||
background: linear-gradient(135deg, rgba(100, 100, 100, 0.08) 0%, transparent 50%, rgba(80, 80, 80, 0.05) 100%);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.option-card:active {
|
.option-card:active:not(.option-card--disabled) {
|
||||||
border-color: var(--border-gold-soft);
|
border-color: var(--primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.option-card--disabled {
|
.option-card--disabled {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
opacity: 0.72;
|
opacity: 0.6;
|
||||||
}
|
|
||||||
|
|
||||||
.option-card--disabled:active {
|
|
||||||
border-color: rgba(140, 140, 140, 0.35);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.option-card--winner {
|
.option-card--winner {
|
||||||
border-color: rgba(201, 162, 39, 0.75);
|
border-color: var(--primary);
|
||||||
box-shadow: 0 0 0 1px rgba(201, 162, 39, 0.25);
|
box-shadow: 0 0 0 1px var(--primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.flag {
|
.flag {
|
||||||
@@ -143,8 +138,8 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.name {
|
.name {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-weight: 800;
|
font-weight: 700;
|
||||||
color: var(--primary-light);
|
color: var(--text);
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -153,8 +148,8 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.odds {
|
.odds {
|
||||||
font-size: 11px;
|
font-size: 12px;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
color: var(--primary-light);
|
color: var(--odds-accent);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -797,12 +797,14 @@ function setFeaturedIndex(index: number) {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-meta {
|
.top-meta {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.league-tag {
|
.league-tag {
|
||||||
@@ -816,6 +818,8 @@ function setFeaturedIndex(index: number) {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.live-indicator {
|
.live-indicator {
|
||||||
@@ -839,6 +843,7 @@ function setFeaturedIndex(index: number) {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vs-text {
|
.vs-text {
|
||||||
@@ -855,6 +860,7 @@ function setFeaturedIndex(index: number) {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.team-name {
|
.team-name {
|
||||||
|
|||||||
@@ -9,10 +9,8 @@ import OutrightBetModal, { type OutrightPick } from '../../components/outright/O
|
|||||||
import { useAuthStore } from '../../stores/auth';
|
import { useAuthStore } from '../../stores/auth';
|
||||||
import GoldSpinner from '../../components/GoldSpinner.vue';
|
import GoldSpinner from '../../components/GoldSpinner.vue';
|
||||||
import saishiImg from '../../assets/images/saishi.webp';
|
import saishiImg from '../../assets/images/saishi.webp';
|
||||||
import cardBg from '../../assets/images/card-bg.webp';
|
|
||||||
import { useDesktopBetLocate, scrollToBetSelection } from '../../composables/useDesktopBetLocate';
|
import { useDesktopBetLocate, scrollToBetSelection } from '../../composables/useDesktopBetLocate';
|
||||||
|
|
||||||
const matchCardBg = `url(${cardBg})`;
|
|
||||||
const ODDS_POLL_MS = 15000;
|
const ODDS_POLL_MS = 15000;
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@@ -241,15 +239,6 @@ onUnmounted(stopPolling);
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.event-hero::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
background: v-bind(matchCardBg) center / 100% 100% no-repeat;
|
|
||||||
opacity: 0.22;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero-text {
|
.hero-text {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user