Add gray-scaling when guessing
All checks were successful
Deploy Feature / deploy-feature (push) Successful in 25s
All checks were successful
Deploy Feature / deploy-feature (push) Successful in 25s
This commit is contained in:
63
src/App.vue
63
src/App.vue
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app">
|
<div class="app" :class="{ suspended: isGuessSuspended }">
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">Music Jeopardy</p>
|
<p class="eyebrow">Music Jeopardy</p>
|
||||||
@@ -263,12 +263,14 @@
|
|||||||
@pause="handlePlayerPause"
|
@pause="handlePlayerPause"
|
||||||
@ended="handlePlayerPause"
|
@ended="handlePlayerPause"
|
||||||
></audio>
|
></audio>
|
||||||
|
<div v-if="viewerGuessVisible || showEnableAudio" class="viewer-actions">
|
||||||
<button v-if="showEnableAudio" class="primary enable-audio" @click="enableViewerAudio">
|
<button v-if="showEnableAudio" class="primary enable-audio" @click="enableViewerAudio">
|
||||||
Tap To Enable Audio
|
Tap To Enable Audio
|
||||||
</button>
|
</button>
|
||||||
<button v-if="canViewerGuess" class="primary viewer-guess" @click="requestGuessStop">
|
<button class="primary viewer-guess" :disabled="!canViewerGuess" @click="requestGuessStop">
|
||||||
Guess Now
|
Stop Song And Guess
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
<div v-if="!currentClipUrl" class="player-empty"></div>
|
<div v-if="!currentClipUrl" class="player-empty"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -300,6 +302,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
<div v-if="isGuessSuspended" class="guess-overlay">
|
||||||
|
<p>{{ guessingTeamLabel }} is guessing</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -334,6 +339,7 @@ type RealtimeState = {
|
|||||||
currentSelectorId: string | null
|
currentSelectorId: string | null
|
||||||
lastAwardedTeamId: string | null
|
lastAwardedTeamId: string | null
|
||||||
isAnswerClip: boolean
|
isAnswerClip: boolean
|
||||||
|
guessingTeamId: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
type RealtimeMessage = {
|
type RealtimeMessage = {
|
||||||
@@ -399,7 +405,8 @@ export default {
|
|||||||
syncTimer: 0,
|
syncTimer: 0,
|
||||||
audioUnlocked: true,
|
audioUnlocked: true,
|
||||||
latestRemoteState: null as RealtimeState | null,
|
latestRemoteState: null as RealtimeState | null,
|
||||||
viewerTeamId: ''
|
viewerTeamId: '',
|
||||||
|
guessingTeamId: null as string | null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
@@ -437,14 +444,26 @@ export default {
|
|||||||
canViewerGuess() {
|
canViewerGuess() {
|
||||||
return (
|
return (
|
||||||
!this.canControlGame &&
|
!this.canControlGame &&
|
||||||
this.audioUnlocked &&
|
|
||||||
!!this.viewerTeamId &&
|
!!this.viewerTeamId &&
|
||||||
this.getCurrentTileStatus() === 'playing'
|
this.getCurrentTileStatus() === 'playing'
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
viewerGuessVisible() {
|
||||||
|
return !this.canControlGame && this.getCurrentTileStatus() === 'playing'
|
||||||
|
},
|
||||||
canControlGame() {
|
canControlGame() {
|
||||||
return !this.gameId || this.isHost
|
return !this.gameId || this.isHost
|
||||||
},
|
},
|
||||||
|
isGuessSuspended() {
|
||||||
|
return this.step === 'game' && this.getCurrentTileStatus() === 'paused'
|
||||||
|
},
|
||||||
|
guessingTeamLabel() {
|
||||||
|
if (this.guessingTeamId) {
|
||||||
|
const team = this.teams.find((candidate) => candidate.id === this.guessingTeamId)
|
||||||
|
if (team?.name?.trim()) return team.name.trim()
|
||||||
|
}
|
||||||
|
return 'A team'
|
||||||
|
},
|
||||||
currentSelector() {
|
currentSelector() {
|
||||||
return this.teams.find((team) => team.id === this.currentSelectorId) || null
|
return this.teams.find((team) => team.id === this.currentSelectorId) || null
|
||||||
},
|
},
|
||||||
@@ -571,6 +590,7 @@ export default {
|
|||||||
this.audioUnlocked = true
|
this.audioUnlocked = true
|
||||||
this.latestRemoteState = null
|
this.latestRemoteState = null
|
||||||
this.viewerTeamId = ''
|
this.viewerTeamId = ''
|
||||||
|
this.guessingTeamId = null
|
||||||
this.setGameInUrl('')
|
this.setGameInUrl('')
|
||||||
},
|
},
|
||||||
async connectSession() {
|
async connectSession() {
|
||||||
@@ -632,7 +652,8 @@ export default {
|
|||||||
currentClipUrl: this.currentClipUrl,
|
currentClipUrl: this.currentClipUrl,
|
||||||
currentSelectorId: this.currentSelectorId,
|
currentSelectorId: this.currentSelectorId,
|
||||||
lastAwardedTeamId: this.lastAwardedTeamId,
|
lastAwardedTeamId: this.lastAwardedTeamId,
|
||||||
isAnswerClip: this.isAnswerClip
|
isAnswerClip: this.isAnswerClip,
|
||||||
|
guessingTeamId: this.guessingTeamId
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
publishState() {
|
publishState() {
|
||||||
@@ -675,6 +696,7 @@ export default {
|
|||||||
this.currentSelectorId = state.currentSelectorId
|
this.currentSelectorId = state.currentSelectorId
|
||||||
this.lastAwardedTeamId = state.lastAwardedTeamId
|
this.lastAwardedTeamId = state.lastAwardedTeamId
|
||||||
this.isAnswerClip = state.isAnswerClip
|
this.isAnswerClip = state.isAnswerClip
|
||||||
|
this.guessingTeamId = state.guessingTeamId || null
|
||||||
if (this.viewerTeamId && !this.teams.some((team) => team.id === this.viewerTeamId)) {
|
if (this.viewerTeamId && !this.teams.some((team) => team.id === this.viewerTeamId)) {
|
||||||
this.viewerTeamId = ''
|
this.viewerTeamId = ''
|
||||||
}
|
}
|
||||||
@@ -710,27 +732,12 @@ export default {
|
|||||||
const status = this.getCurrentTileStatus()
|
const status = this.getCurrentTileStatus()
|
||||||
if (status !== 'playing') return
|
if (status !== 'playing') return
|
||||||
const key = this.currentTileKey
|
const key = this.currentTileKey
|
||||||
const [cIndex, qIndex] = key.split('-').map(Number)
|
this.tiles[key].status = 'paused'
|
||||||
const clue = this.selectedGame.categories[cIndex].clues[qIndex]
|
|
||||||
this.tiles[key].status = 'guessed'
|
|
||||||
this.lastAwardedTeamId = null
|
this.lastAwardedTeamId = null
|
||||||
if (clue.answer) {
|
this.guessingTeamId = teamId
|
||||||
this.currentClipUrl = encodeURI(clue.answer)
|
this.isAnswerClip = false
|
||||||
this.isAnswerClip = true
|
|
||||||
await nextTick()
|
|
||||||
const player = this.getPlayer()
|
|
||||||
if (player) {
|
|
||||||
this.ensureAudioContext()
|
|
||||||
player.currentTime = 0
|
|
||||||
player.load()
|
|
||||||
player.play().catch(() => {})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const player = this.getPlayer()
|
const player = this.getPlayer()
|
||||||
player?.pause()
|
player?.pause()
|
||||||
this.currentClipUrl = ''
|
|
||||||
this.isAnswerClip = false
|
|
||||||
}
|
|
||||||
this.queueStateSync()
|
this.queueStateSync()
|
||||||
},
|
},
|
||||||
getCurrentTileStatus() {
|
getCurrentTileStatus() {
|
||||||
@@ -956,6 +963,7 @@ export default {
|
|||||||
this.currentTileKey = null
|
this.currentTileKey = null
|
||||||
this.currentClipUrl = ''
|
this.currentClipUrl = ''
|
||||||
this.lastAwardedTeamId = null
|
this.lastAwardedTeamId = null
|
||||||
|
this.guessingTeamId = null
|
||||||
this.teams = this.teams.map((team) => ({ ...team, score: 0 }))
|
this.teams = this.teams.map((team) => ({ ...team, score: 0 }))
|
||||||
const randomTeam = this.teams[Math.floor(Math.random() * this.teams.length)]
|
const randomTeam = this.teams[Math.floor(Math.random() * this.teams.length)]
|
||||||
this.currentSelectorId = randomTeam?.id || null
|
this.currentSelectorId = randomTeam?.id || null
|
||||||
@@ -971,6 +979,7 @@ export default {
|
|||||||
this.currentClipUrl = ''
|
this.currentClipUrl = ''
|
||||||
this.lastAwardedTeamId = null
|
this.lastAwardedTeamId = null
|
||||||
this.isAnswerClip = false
|
this.isAnswerClip = false
|
||||||
|
this.guessingTeamId = null
|
||||||
this.teardownAudio()
|
this.teardownAudio()
|
||||||
this.queueStateSync()
|
this.queueStateSync()
|
||||||
},
|
},
|
||||||
@@ -1018,6 +1027,7 @@ export default {
|
|||||||
this.currentTileKey = key
|
this.currentTileKey = key
|
||||||
this.currentClipUrl = encodeURI(clue.song)
|
this.currentClipUrl = encodeURI(clue.song)
|
||||||
this.isAnswerClip = false
|
this.isAnswerClip = false
|
||||||
|
this.guessingTeamId = null
|
||||||
await nextTick()
|
await nextTick()
|
||||||
const player = this.getPlayer()
|
const player = this.getPlayer()
|
||||||
if (player) {
|
if (player) {
|
||||||
@@ -1032,6 +1042,7 @@ export default {
|
|||||||
|
|
||||||
if (status === 'playing') {
|
if (status === 'playing') {
|
||||||
this.tiles[key].status = 'paused'
|
this.tiles[key].status = 'paused'
|
||||||
|
this.guessingTeamId = this.currentSelectorId
|
||||||
const player = this.getPlayer()
|
const player = this.getPlayer()
|
||||||
player?.pause()
|
player?.pause()
|
||||||
this.queueStateSync()
|
this.queueStateSync()
|
||||||
@@ -1065,6 +1076,7 @@ export default {
|
|||||||
this.currentTileKey = null
|
this.currentTileKey = null
|
||||||
this.currentClipUrl = ''
|
this.currentClipUrl = ''
|
||||||
this.lastAwardedTeamId = null
|
this.lastAwardedTeamId = null
|
||||||
|
this.guessingTeamId = null
|
||||||
this.checkEnd()
|
this.checkEnd()
|
||||||
this.queueStateSync()
|
this.queueStateSync()
|
||||||
}
|
}
|
||||||
@@ -1077,6 +1089,7 @@ export default {
|
|||||||
|
|
||||||
if (status === 'paused') {
|
if (status === 'paused') {
|
||||||
this.tiles[key].status = 'playing'
|
this.tiles[key].status = 'playing'
|
||||||
|
this.guessingTeamId = null
|
||||||
const player = this.getPlayer()
|
const player = this.getPlayer()
|
||||||
player?.play().catch(() => {})
|
player?.play().catch(() => {})
|
||||||
this.queueStateSync()
|
this.queueStateSync()
|
||||||
@@ -1088,6 +1101,7 @@ export default {
|
|||||||
this.currentTileKey = null
|
this.currentTileKey = null
|
||||||
this.currentClipUrl = ''
|
this.currentClipUrl = ''
|
||||||
this.isAnswerClip = false
|
this.isAnswerClip = false
|
||||||
|
this.guessingTeamId = null
|
||||||
const player = this.getPlayer()
|
const player = this.getPlayer()
|
||||||
player?.pause()
|
player?.pause()
|
||||||
this.teardownAudio()
|
this.teardownAudio()
|
||||||
@@ -1122,6 +1136,7 @@ export default {
|
|||||||
const finished = allTiles.every((status) => status === 'won' || status === 'void')
|
const finished = allTiles.every((status) => status === 'won' || status === 'void')
|
||||||
if (finished) {
|
if (finished) {
|
||||||
this.step = 'end'
|
this.step = 'end'
|
||||||
|
this.guessingTeamId = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -29,6 +29,42 @@ code {
|
|||||||
gap: 24px;
|
gap: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-header,
|
||||||
|
.app-main {
|
||||||
|
transition: filter 0.25s ease, opacity 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app.suspended .app-header,
|
||||||
|
.app.suspended .app-main {
|
||||||
|
filter: grayscale(1) brightness(0.55);
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guess-overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
background: rgba(8, 12, 26, 0.35);
|
||||||
|
backdrop-filter: blur(2px) grayscale(0.15);
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guess-overlay p {
|
||||||
|
margin: 0;
|
||||||
|
padding: 16px 24px;
|
||||||
|
border-radius: 14px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
background: rgba(13, 17, 35, 0.88);
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: 'Bebas Neue', sans-serif;
|
||||||
|
font-size: clamp(2.1rem, 4vw, 3.3rem);
|
||||||
|
letter-spacing: 0.07em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.app-header {
|
.app-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@@ -554,16 +590,33 @@ audio.hidden-audio {
|
|||||||
color: rgba(255, 255, 255, 0.6);
|
color: rgba(255, 255, 255, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.enable-audio {
|
.viewer-actions {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
z-index: 3;
|
transform: translateX(-50%);
|
||||||
|
z-index: 4;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enable-audio {
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.viewer-guess {
|
.viewer-guess {
|
||||||
position: absolute;
|
font-size: 1rem;
|
||||||
bottom: 20px;
|
font-weight: 800;
|
||||||
z-index: 3;
|
letter-spacing: 0.03em;
|
||||||
|
padding: 14px 28px;
|
||||||
|
background: linear-gradient(135deg, #ffce3a, #ff6a3a);
|
||||||
|
box-shadow: 0 12px 30px rgba(255, 106, 58, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewer-guess:disabled {
|
||||||
|
background: linear-gradient(135deg, #8f8f8f, #666666);
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.end-panel {
|
.end-panel {
|
||||||
@@ -606,4 +659,13 @@ audio.hidden-audio {
|
|||||||
.session-row {
|
.session-row {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.viewer-actions {
|
||||||
|
flex-direction: column;
|
||||||
|
width: calc(100% - 24px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewer-actions .primary {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user