464 lines
13 KiB
Vue
464 lines
13 KiB
Vue
<template>
|
|
<img alt="" class="bg-img" src="">
|
|
|
|
<div class="match-wrapper">
|
|
<div class="head row m-auto text-center">
|
|
<div class="map-score">
|
|
<div v-if="route.fullPath.split('/')[3] !== 'overview'" class="score-team-1">
|
|
<h1 :class="checkWin(1)" :style="data.score[0] < 10 ? 'padding-left: 20px;' : ''">{{ data.score[0] }}</h1>
|
|
<div v-if="data.score[0]" class="team-1">
|
|
<img alt="CT logo" src="../assets/images/icons/ct_logo.svg">
|
|
<img alt="T logo" src="../assets/images/icons/t_logo.svg">
|
|
</div>
|
|
</div>
|
|
<div class="m-auto map">
|
|
<img v-if="data.matchDetails.map" :alt="data.matchDetails.map"
|
|
:src="require('../assets/images/map_icons/map_icon_' + data.matchDetails.map + '.svg')"
|
|
:title="data.matchDetails.map" class="map-icon"
|
|
>
|
|
<img v-if="!data.matchDetails.map" :src="require('../assets/images/map_icons/map_icon_lobby_mapveto.svg')"
|
|
alt="Map icon"
|
|
class="map-icon" title="Map unknown"
|
|
>
|
|
</div>
|
|
<div v-if="route.fullPath.split('/')[3] !== 'overview'" class="score-team-2">
|
|
<h1 :class="checkWin(2)" :style="data.score[1] < 10 ? 'padding-left: 20px;' : ''">{{ data.score[1] }}</h1>
|
|
<div v-if="data.score[1]" class="team-2">
|
|
<img alt="T logo" src="../assets/images/icons/t_logo.svg">
|
|
<img alt="CT logo" src="../assets/images/icons/ct_logo.svg">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="text">
|
|
<p class="text-center text-muted fs-6 mb-1">
|
|
Match lasted for
|
|
<span class="text-white">{{ FormatDuration(data.matchDetails.duration) }}</span>
|
|
</p>
|
|
<p class="text-center text-muted fs-6">
|
|
on
|
|
<span class="text-white">{{ FormatFullDate(data.matchDetails.date) }}</span>
|
|
</p>
|
|
<p class="text-center fs-6">
|
|
<img v-if="data.matchDetails.max_rounds === 16" alt="Match length" class="match-len"
|
|
src="../assets/images/icons/timer_short.svg" title="Short-Match">
|
|
<img v-if="data.matchDetails.max_rounds === 30 || !data.matchDetails.max_rounds" alt="Match length"
|
|
class="match-len"
|
|
src="../assets/images/icons/timer_long.svg" title="Long-Match">
|
|
<span v-if="data.matchDetails.parsed" class="text-muted px-2">—</span>
|
|
<img v-if="data.matchDetails.parsed"
|
|
:alt="DisplayRank(data.avgRank)[1]"
|
|
:src="DisplayRank(data.avgRank)[0]"
|
|
:title="'Average Rank: ' + DisplayRank(data.avgRank)[1]"
|
|
class="rank-icon"/>
|
|
<span v-if="data.matchDetails.replay_url" class="text-muted px-2">—</span>
|
|
<a v-if="data.matchDetails.replay_url" :href="data.matchDetails.replay_url" class="text-white" title="Download Match">
|
|
<i class="fas fa-download"></i>
|
|
</a>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="nav navbar-dark navbar-expand-lg">
|
|
<button aria-controls="matchNav" aria-expanded="false" aria-label="Toggle navigation" class="navbar-toggler"
|
|
data-bs-target="#matchNav" data-bs-toggle="collapse" type="button">
|
|
<span class="navbar-toggler-icon"></span>
|
|
</button>
|
|
<div id="matchNav" class="collapse navbar-collapse justify-content-between">
|
|
<ul class="list-unstyled d-flex m-auto">
|
|
<li :title="!data.matchDetails.parsed ? 'This demo has not been parsed' : ''"
|
|
class="list-item nav-item">
|
|
<router-link :to="'/match/' + data.matchDetails.match_id + '/overview'" class="nav-link"
|
|
replace>Scoreboard
|
|
</router-link>
|
|
</li>
|
|
<li :title="!data.matchDetails.parsed ? 'This demo has not been parsed' : ''"
|
|
class="list-item nav-item">
|
|
<router-link :class="!data.matchDetails.parsed ? 'disabled' : ''" :disabled="!data.matchDetails.parsed"
|
|
:to="'/match/' + data.matchDetails.match_id + '/economy'" class="nav-link"
|
|
replace>Economy
|
|
</router-link>
|
|
</li>
|
|
<li :title="!data.matchDetails.parsed ? 'This demo has not been parsed' : ''"
|
|
class="list-item nav-item">
|
|
<router-link :class="!data.matchDetails.parsed ? 'disabled' : ''" :disabled="!data.matchDetails.parsed"
|
|
:to="'/match/' + data.matchDetails.match_id + '/details'" class="nav-link"
|
|
replace>Details
|
|
</router-link>
|
|
</li>
|
|
<li :title="!data.matchDetails.parsed ? 'This demo has not been parsed' : ''"
|
|
class="list-item nav-item">
|
|
<router-link :class="!data.matchDetails.parsed ? 'disabled' : ''" :disabled="!data.matchDetails.parsed"
|
|
:to="'/match/' + data.matchDetails.match_id + '/flashes'" class="nav-link"
|
|
replace>Flashes
|
|
</router-link>
|
|
</li>
|
|
<!-- <li :class="!data.matchDetails.parsed ? 'disabled' : ''"-->
|
|
<!-- :title="!data.matchDetails.parsed ? 'This demo has not been parsed' : ''"-->
|
|
<!-- class="list-item nav-item">-->
|
|
<!-- <router-link :disabled="!data.matchDetails.parsed" :to="'/match/' + data.matchDetails.match_id + '/utility'" replace :class="!data.matchDetails.parsed ? 'disabled' : ''"-->
|
|
<!-- class="nav-link">Utility-->
|
|
<!-- </router-link>-->
|
|
<!-- </li>-->
|
|
<li :title="!data.matchDetails.parsed ? 'This demo has not been parsed' : ''"
|
|
class="list-item nav-item">
|
|
<router-link :class="!data.matchDetails.parsed ? 'disabled' : ''" :disabled="!data.matchDetails.parsed"
|
|
:to="'/match/' + data.matchDetails.match_id + '/damage'" class="nav-link"
|
|
replace>Damage
|
|
</router-link>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div id="scoreWrapper" class="scoreboard">
|
|
<router-view v-if="data.score.length === 2 && data.stats" name="score"/>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import {onBeforeMount, onBeforeUnmount, onMounted, reactive, watch} from "vue";
|
|
import {
|
|
closeNav,
|
|
CreatePlayersArray,
|
|
DisplayRank,
|
|
FixMapName,
|
|
FormatDuration,
|
|
FormatFullDate,
|
|
GetAvgRank,
|
|
GetMatchDetails,
|
|
GoToLink,
|
|
LoadImage
|
|
} from "../utils";
|
|
import {useStore} from "vuex";
|
|
import {useRoute} from 'vue-router'
|
|
import {FOOTER_HEIGHT, NAV_HEIGHT} from "@/constants";
|
|
|
|
export default {
|
|
name: 'Match',
|
|
props: ['match_id'],
|
|
setup(props) {
|
|
const store = useStore()
|
|
const route = useRoute()
|
|
|
|
const matchIdPattern = /^\d{19}$/
|
|
|
|
// Refs
|
|
const data = reactive({
|
|
player_id: '',
|
|
matchDetails: {},
|
|
stats: [],
|
|
score: [0],
|
|
avgRank: 0,
|
|
})
|
|
|
|
// Functions
|
|
const GetMatch = async () => {
|
|
if (matchIdPattern.test(props.match_id)) {
|
|
const res = await GetMatchDetails(props.match_id)
|
|
|
|
if (res.map)
|
|
document.title = `${FixMapName(res.map)} | csgoWTF`
|
|
else
|
|
document.title = `Match-Details | csgoWTF`
|
|
|
|
store.commit({
|
|
type: 'changeMatchDetails',
|
|
data: res
|
|
})
|
|
|
|
data.matchDetails = store.state.matchDetails
|
|
data.stats = data.matchDetails.stats
|
|
data.score = data.matchDetails.score
|
|
|
|
LoadImage(data.matchDetails.map ? data.matchDetails.map : 'random')
|
|
|
|
store.commit({
|
|
type: 'changePlayesArr',
|
|
data: CreatePlayersArray(data.stats)
|
|
})
|
|
data.avgRank = GetAvgRank(data.stats)
|
|
|
|
console.log(data.matchDetails)
|
|
} else {
|
|
console.log('Match not found')
|
|
// TODO: needs 404
|
|
}
|
|
}
|
|
|
|
const checkRoute = () => {
|
|
if (route.fullPath.split('/')[3]) {
|
|
const sub = route.fullPath.split('/')[3]
|
|
if (matchIdPattern.test(props.match_id))
|
|
GoToLink(`/match/${props.match_id}/${sub}`)
|
|
else {
|
|
console.log('Match not found')
|
|
// TODO: needs 404
|
|
}
|
|
} else if (route.fullPath.split('/')[3] === undefined) {
|
|
if (matchIdPattern.test(props.match_id))
|
|
GoToLink(`/match/${props.match_id}/overview`)
|
|
else {
|
|
console.log('Match not found')
|
|
// TODO: needs 404
|
|
}
|
|
}
|
|
}
|
|
|
|
const checkWin = (team) => {
|
|
team -= 1
|
|
if (data.matchDetails.max_rounds === 16) {
|
|
if (data.score[team] === 9)
|
|
return 'text-success'
|
|
else if (data.score[team] === 8)
|
|
return 'text-warning'
|
|
else if (data.score[team] < 8)
|
|
return 'text-danger'
|
|
} else {
|
|
if (data.score[team] === 16)
|
|
return 'text-success'
|
|
else if (data.score[team] === 15)
|
|
return 'text-warning'
|
|
else if (data.score[team] < 15)
|
|
return 'text-danger'
|
|
}
|
|
}
|
|
|
|
// Watchers
|
|
watch(() => props.match_id, GetMatch)
|
|
|
|
// Run on create
|
|
onBeforeMount(() => {
|
|
GetMatch()
|
|
})
|
|
|
|
onBeforeUnmount(() => {
|
|
store.commit('resetMatchDetails')
|
|
})
|
|
|
|
onMounted(() => {
|
|
checkRoute()
|
|
|
|
const headHeight = 230
|
|
const navHeight = 42
|
|
|
|
const height = window.innerHeight - NAV_HEIGHT - FOOTER_HEIGHT - headHeight - navHeight
|
|
const scoreWrapper = document.getElementById('scoreWrapper')
|
|
scoreWrapper.style.minHeight = height + 'px'
|
|
})
|
|
|
|
document.addEventListener('click', () => {
|
|
closeNav('matchNav')
|
|
})
|
|
|
|
return {
|
|
data, DisplayRank, FormatFullDate, FormatDuration, route, checkWin
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.bg-img {
|
|
z-index: -1;
|
|
position: fixed;
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.head {
|
|
height: 230px;
|
|
background: linear-gradient(90deg,
|
|
rgba(0, 0, 0, 0.7) 0%,
|
|
rgba(0, 0, 0, 0.95) 30%,
|
|
rgba(0, 0, 0, 0.95) 70%,
|
|
rgba(0, 0, 0, .7) 100%
|
|
);
|
|
|
|
.map-score {
|
|
display: flex;
|
|
position: relative;
|
|
|
|
.map img {
|
|
width: auto;
|
|
height: 100px;
|
|
margin: 10px 0;
|
|
}
|
|
|
|
.score-team-1,
|
|
.score-team-2 {
|
|
position: absolute;
|
|
top: 3.5rem;
|
|
|
|
h1 {
|
|
font-size: 4rem;
|
|
}
|
|
|
|
.team-1,
|
|
.team-2 {
|
|
position: relative;
|
|
right: 30%;
|
|
|
|
color: white;
|
|
font-size: 1rem;
|
|
opacity: .8;
|
|
|
|
img {
|
|
position: absolute;
|
|
width: 30px;
|
|
height: 30px;
|
|
|
|
&:first-child {
|
|
z-index: 1;
|
|
}
|
|
|
|
&:last-child {
|
|
margin-left: 20px;
|
|
z-index: 0 !important;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.score-team-1 {
|
|
left: 25%;
|
|
}
|
|
|
|
.score-team-2 {
|
|
right: 25%;
|
|
}
|
|
}
|
|
|
|
.text {
|
|
.rank-icon {
|
|
width: 60px;
|
|
}
|
|
|
|
.match-len {
|
|
width: 20px;
|
|
height: 20px;
|
|
}
|
|
|
|
a {
|
|
font-weight: 600;
|
|
text-decoration: none;
|
|
color: var(--bs-warning) !important;
|
|
transition: all .25s;
|
|
line-height: 1rem;
|
|
|
|
&:hover {
|
|
color: #b98d00 !important;
|
|
text-decoration: underline;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
.nav {
|
|
max-width: 100vw;
|
|
min-height: 42px;
|
|
background: rgba(0, 0, 0, 0.9);
|
|
background: linear-gradient(90deg,
|
|
rgba(0, 0, 0, 0.7) 0%,
|
|
rgba(0, 0, 0, 0.95) 30%,
|
|
rgba(0, 0, 0, 0.95) 70%,
|
|
rgba(0, 0, 0, .7) 100%
|
|
);
|
|
border-top: 1px solid rgba(255, 255, 255, .2);
|
|
border-bottom: 1px solid rgba(255, 255, 255, .2);
|
|
|
|
.nav-link {
|
|
text-decoration: none;
|
|
color: white;
|
|
|
|
&:hover {
|
|
background: var(--bs-info);
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
|
|
.router-link-exact-active {
|
|
background: var(--bs-info)
|
|
}
|
|
|
|
.disabled {
|
|
color: #585858;
|
|
|
|
&:hover {
|
|
background: lime;
|
|
cursor: default;
|
|
}
|
|
}
|
|
}
|
|
|
|
#scoreWrapper {
|
|
display: flex;
|
|
justify-content: center;
|
|
flex-wrap: wrap;
|
|
|
|
z-index: 1;
|
|
width: 100%;
|
|
max-width: 100vw;
|
|
background: linear-gradient(90deg,
|
|
rgba(0, 0, 0, 0.6) 0%,
|
|
rgba(0, 0, 0, 0.85) 30%,
|
|
rgba(0, 0, 0, 0.85) 70%,
|
|
rgba(0, 0, 0, .6) 100%
|
|
);
|
|
}
|
|
|
|
@media (max-width: 991px) {
|
|
.score-team-1,
|
|
.score-team-2 {
|
|
top: 2rem !important;
|
|
|
|
h1 {
|
|
font-size: 3.5rem !important;
|
|
}
|
|
}
|
|
|
|
.score-team-1 {
|
|
left: 10% !important;
|
|
}
|
|
|
|
.score-team-2 {
|
|
right: 10% !important;
|
|
}
|
|
|
|
.nav {
|
|
button {
|
|
outline: 1px solid var(--bs-primary);
|
|
margin-left: auto;
|
|
float: right;
|
|
margin-right: 1rem;
|
|
|
|
&:focus {
|
|
box-shadow: none;
|
|
outline: 1px solid var(--bs-primary);
|
|
}
|
|
}
|
|
|
|
.navbar-collapse {
|
|
border-radius: 5px;
|
|
border: 1px solid var(--bs-primary);
|
|
|
|
ul {
|
|
flex-direction: column;
|
|
|
|
li {
|
|
width: 100%;
|
|
text-align: center;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#scoreWrapper {
|
|
justify-content: flex-start;
|
|
overflow-x: scroll;
|
|
overflow-y: hidden;
|
|
}
|
|
}
|
|
</style>
|