Skip to content

Commit

Permalink
Improve highlighting pending games
Browse files Browse the repository at this point in the history
  • Loading branch information
timoschwarzer committed May 10, 2024
1 parent f150064 commit 3f24c85
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 77 deletions.
156 changes: 107 additions & 49 deletions components/League/GameCard.vue
Original file line number Diff line number Diff line change
@@ -1,49 +1,55 @@
<template>
<v-card
class="game-card"
:class="{ accent: game.isCurrent && game.userMetadata?.canSubmit }"
:to="{ name: 'league-game-gameId', params: { gameId: game.id } }"
>
<div class="gradient-overlay"></div>

<div class="card-content pa-4">
<img class="background-image" src="~/assets/images/ori_running.png" />
<div class="game-number-container">
<div>Game</div>
<div>
<span class="hashtag">#</span><span class="game-number">{{ game.gameNumber }}</span
><template v-if="gameCount"
><span class="game-count"> / {{ gameCount }}</span>
</template>
<div class="card-container">
<div v-if="isPending" class="card-flash accent"></div>

<v-card
class="game-card"
:class="{ accent: isPending }"
:to="{ name: 'league-game-gameId', params: { gameId: game.id } }"
>
<div class="gradient-overlay" :class="{extreme: !!season?.backgroundImageUrl}"></div>

<div class="card-content pa-4">
<img v-if="!!season?.backgroundImageUrl" class="background-image behind" alt="" :src="season.backgroundImageUrl" />
<img v-else class="background-image" alt="" src="~/assets/images/ori_running.png" />

<div class="game-number-container">
<div>{{ season !== null ? season.name : 'Game' }}</div>
<div>
<span class="hashtag">#</span><span class="game-number">{{ game.gameNumber }}</span
><template v-if="gameCount"
><span class="game-count"> / {{ gameCount }}</span>
</template>
</div>
</div>
</div>

<div class="spacer"></div>

<div class="d-flex flex-column align-end">
<div>
{{ game.submissionCount }}
<template v-if="memberCount">/ {{ memberCount }}</template>
<v-icon :color="game.userMetadata?.ownSubmission ? 'green' : ''" small>mdi-flag-checkered</v-icon>
</div>
<div v-if="game.userMetadata?.ownSubmission">
{{ formatTime(game.userMetadata.ownSubmission.rankingData.time) }}
<v-icon small>mdi-timer-outline</v-icon>
<div class="spacer"></div>

<div class="d-flex flex-column align-end">
<div>
{{ game.submissionCount }}
<template v-if="memberCount">/ {{ memberCount }}</template>
<v-icon :color="game.userMetadata?.ownSubmission ? 'green' : ''" small>mdi-flag-checkered</v-icon>
</div>
<div v-if="game.userMetadata?.ownSubmission">
{{ formatTime(game.userMetadata.ownSubmission.rankingData.time) }}
<v-icon small>mdi-timer-outline</v-icon>
</div>
</div>
</div>
</div>

<div v-if="playableUntil !== null && !game.userMetadata?.ownSubbmission" class="timer pa-2">
<template v-if="typeof countdownTimerTextOrSecondsLeft === 'number'">
<span class="font-weight-bold">{{ formatTime(countdownTimerTextOrSecondsLeft, 0, true) }}</span><br />
left to finish this game!
</template>
<template v-else-if="typeof countdownTimerTextOrSecondsLeft === 'string'">
{{ countdownTimerTextOrSecondsLeft }}
</template>
<template v-else> Finish this game until {{ formatDateEpoch(playableUntil, 'P p') }} </template>
</div>
</v-card>

<div v-if="playableUntil !== null && !game.userMetadata?.ownSubmission" class="timer pa-2">
<template v-if="typeof countdownTimerTextOrSecondsLeft === 'number'">
<span class="font-weight-bold">{{ formatTime(countdownTimerTextOrSecondsLeft, 0, true) }}</span><br />
left to finish this game!
</template>
<template v-else-if="typeof countdownTimerTextOrSecondsLeft === 'string'">
{{ countdownTimerTextOrSecondsLeft }}
</template>
<template v-else> Finish this game until {{ formatDateEpoch(playableUntil, 'P p') }} </template>
</div>
</v-card>
</div>
</template>

<script>
Expand All @@ -70,11 +76,20 @@
type: Number,
default: null,
},
season: {
type: Object,
default: () => null,
},
},
data: () => ({
countdownTimerTextOrSecondsLeft: null,
updateIntervalId: null,
}),
computed: {
isPending() {
return this.game.isCurrent && this.game.userMetadata?.canSubmit
}
},
mounted() {
this.updateIntervalId = setInterval(() => this.updateTimerText(), 1000)
this.updateTimerText()
Expand Down Expand Up @@ -112,31 +127,70 @@
</script>
<style scoped lang="scss">
.game-card {
position: relative;
overflow: hidden;
transition: transform 300ms;
border: 1px solid rgba(255, 255, 255, 0.4);
.card-container {
will-change: transform;
transition: transform 300ms;
&:hover {
transform: scale(1.02);
}
position: relative;
@keyframes flash {
0% {
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0.8;
}
30% {
opacity: 0.6;
}
100% {
top: -8px;
left: -8px;
right: -8px;
bottom: -8px;
opacity: 0;
}
}
.card-flash {
position: absolute;
opacity: 0.6;
border-radius: 0.4em;
animation: flash 1s forwards infinite;
z-index: -2;
}
}
.game-card {
position: relative;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.4);
z-index: 1;
.gradient-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 100%);
&.extreme {
background: linear-gradient(to right, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0) 100%);
}
}
.card-content {
position: relative;
display: flex;
align-items: center;
height: 100%;
.game-number-container {
display: flex;
Expand Down Expand Up @@ -175,8 +229,12 @@
object-fit: cover;
width: 100%;
height: 100%;
opacity: 0.75;
opacity: 1;
transform: scale(1.8);
&.behind {
z-index: -1;
}
}
}
Expand All @@ -190,7 +248,7 @@
.timer {
text-align: center;
position: relative;
background-color: rgba(0, 0, 0, 0.1);
background-color: rgba(0, 0, 0, 0.4);
line-height: 1.2;
}
}
Expand Down
8 changes: 2 additions & 6 deletions components/League/SeasonCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,12 @@

<div class="card-tags">
<div v-if="mode === MODE_UPCOMING" class="px-2 blue darken-1">Upcoming</div>
<div v-else-if="mode === MODE_ACTIVE" class="px-2 green darken-2">Active</div>
<div v-if="submissionPending?.isPending" class="px-2 card-tag-pending">Pending</div>
<!-- <div v-else-if="mode === MODE_ACTIVE" class="px-2 green darken-2">Active</div>-->
<div v-else-if="joined" class="px-2 accent"><v-icon x-small>mdi-check</v-icon> Joined</div>
</div>

<div class="card-content pa-4">
<h3>
{{ season.name }}
<v-icon class="pending-attention" v-if="submissionPending.attention">mdi-alert-rhombus-outline</v-icon>
</h3>
<h3>{{ season.name }}</h3>
<div>{{ season.shortDescription }}</div>

<div class="spacer"></div>
Expand Down
48 changes: 26 additions & 22 deletions pages/league/seasons/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,22 @@
</v-btn>
</div>

<template v-if="pendingGames.length > 0">
<h2 class="mt-5 mb-2">Your pending games</h2>

<div class="seasons-container">
<league-game-card
v-for="pendingGame in pendingGames"
:key="pendingGame.game.id"
:game="pendingGame.game"
:season="pendingGame.season"
:game-count="pendingGame.season.gameCount"
:playable-until="pendingGame.season.nextContinuationAt"
:member-count="pendingGame.season.memberships?.length"
/>
</div>
</template>

<template v-if="categorizedSeasons.active.length > 0 || categorizedSeasons.upcoming.length > 0">
<h2 class="mt-5 mb-2">Active & Upcoming Seasons</h2>

Expand All @@ -22,15 +38,13 @@
:season="season"
mode="active"
:joined="userIsMemberOfSeason(season)"
:submission-pending="userHasSubmissionPending(season)"
/>
<league-season-card
v-for="season in categorizedSeasons.upcoming"
:key="season.id"
:season="season"
mode="upcoming"
:joined="userIsMemberOfSeason(season)"
:submission-pending="userHasSubmissionPending(season)"
/>
</div>
</template>
Expand Down Expand Up @@ -158,6 +172,7 @@
data: () => ({
seasonsLoading: false,
leagueSeasons: [],
pendingGames: [],
showLeagueInfo: false,
leagueDiscordChannelUrl: 'https://discord.gg/kXuZSAuxZt',
}),
Expand Down Expand Up @@ -199,6 +214,15 @@
try {
this.leagueSeasons = await this.$axios.$get('/league/seasons')
this.pendingGames = this.leagueSeasons.flatMap(season => {
const currentGame = season.games.find(g => g.id === season.currentGameId)
if (currentGame?.userMetadata?.ownSubmission === null) {
return [{game: currentGame, season}]
}
return []
})
} catch (e) {
console.error(e)
}
Expand All @@ -208,26 +232,6 @@
userIsMemberOfSeason(season) {
return season.memberships?.some((m) => m.user.id === this.user?.id)
},
userHasSubmissionPending(season) {
const pending = { isPending: false, attention: false }
if (!this.isLoggedIn || !season.currentGameId) {
return pending
}
// pending if own submission not available
const currentGame = season.games?.find((g) => g.id === season.currentGameId)
pending.isPending = currentGame.userMetadata?.ownSubmission === null
// attention if less than 48h left
if (pending.isPending){
const secondsLeft = (season.nextContinuationAt - Date.now()) / 1000
pending.attention = secondsLeft < 48 * 3600
}
return pending
},
openDiscordLeagueChannel() {
window.electronApi.invoke('launcher.openUrl', { url: this.leagueDiscordChannelUrl })
},
Expand Down

0 comments on commit 3f24c85

Please sign in to comment.