(update) ScoreDisplay : Feedback visuel lors des buzzer
- Ajout de l'état 'activeTeam' et flashingTeam' basé sur les messages MQT - Implémentation du grisement (dimming) des équipes inactives - Ajout d'une lueur blanche clignotante (flash-glow) de 2s sur l'équipe active
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="score-grid">
|
<div class="score-grid">
|
||||||
<div class="score-cell cell-blue color-blue">
|
<div class="score-cell cell-blue color-blue" :class="[getDimClass('Blue'), getFlashClass('Blue')]">
|
||||||
<div class="score-content">
|
<div class="score-content">
|
||||||
<div class="score-info info-left">
|
<div class="score-info info-left">
|
||||||
<div class="team-name">Bleue</div>
|
<div class="team-name">Bleue</div>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="score-cell cell-red color-red">
|
<div class="score-cell cell-red color-red" :class="[getDimClass('Red'), getFlashClass('Red')]">
|
||||||
<div class="score-content">
|
<div class="score-content">
|
||||||
<div class="score-main">
|
<div class="score-main">
|
||||||
<Transition name="score-pop" mode="out-in">
|
<Transition name="score-pop" mode="out-in">
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="score-cell cell-green color-green">
|
<div class="score-cell cell-green color-green" :class="[getDimClass('Green'), getFlashClass('Green')]">
|
||||||
<div class="score-content">
|
<div class="score-content">
|
||||||
<div class="score-info info-left">
|
<div class="score-info info-left">
|
||||||
<div class="team-name">Verte</div>
|
<div class="team-name">Verte</div>
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="score-cell cell-yellow color-yellow">
|
<div class="score-cell cell-yellow color-yellow" :class="[getDimClass('Yellow'), getFlashClass('Yellow')]">
|
||||||
<div class="score-content">
|
<div class="score-content">
|
||||||
<div class="score-main">
|
<div class="score-main">
|
||||||
<Transition name="score-pop" mode="out-in">
|
<Transition name="score-pop" mode="out-in">
|
||||||
@@ -142,8 +142,72 @@
|
|||||||
});
|
});
|
||||||
// Request score refresh
|
// Request score refresh
|
||||||
client.publish('game/score/request', '{}');
|
client.publish('game/score/request', '{}');
|
||||||
|
|
||||||
|
subscribeToTopic('vulture/buzzer/status', (topic, message) => {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(message);
|
||||||
|
if (data.status === 'blocked') {
|
||||||
|
const color = data.color || '';
|
||||||
|
const team = identifyTeamByColor(color);
|
||||||
|
activeTeam.value = team;
|
||||||
|
|
||||||
|
// Trigger flash effect
|
||||||
|
if (team) {
|
||||||
|
flashingTeam.value = team;
|
||||||
|
setTimeout(() => {
|
||||||
|
if (flashingTeam.value === team) {
|
||||||
|
flashingTeam.value = null;
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
} else if (data.status === 'unblocked') {
|
||||||
|
activeTeam.value = null;
|
||||||
|
flashingTeam.value = null;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error parsing buzzer status', e);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const activeTeam = ref(null);
|
||||||
|
const flashingTeam = ref(null);
|
||||||
|
|
||||||
|
function identifyTeamByColor(hexColor) {
|
||||||
|
if (!hexColor) return null;
|
||||||
|
const color = hexColor.replace('#', '').toUpperCase();
|
||||||
|
|
||||||
|
// RED
|
||||||
|
if (['FF0000', 'D42828'].includes(color)) return 'Red';
|
||||||
|
// BLUE
|
||||||
|
if (['0000FF', '2867D4'].includes(color)) return 'Blue';
|
||||||
|
// GREEN
|
||||||
|
if (['00FF00', '28D42E'].includes(color)) return 'Green';
|
||||||
|
// YELLOW
|
||||||
|
if (['FFFF00', 'D4D100'].includes(color)) return 'Yellow';
|
||||||
|
|
||||||
|
// Fallback
|
||||||
|
const r = parseInt(color.substr(0, 2), 16);
|
||||||
|
const g = parseInt(color.substr(2, 2), 16);
|
||||||
|
const b = parseInt(color.substr(4, 2), 16);
|
||||||
|
|
||||||
|
if (r > 200 && g > 200 && b < 100) return 'Yellow';
|
||||||
|
if (g > r && g > b) return 'Green';
|
||||||
|
if (b > r && b > g) return 'Blue';
|
||||||
|
if (r > g && r > b) return 'Red';
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDimClass(team) {
|
||||||
|
if (!activeTeam.value) return '';
|
||||||
|
return activeTeam.value !== team ? 'dimmed-score' : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFlashClass(team) {
|
||||||
|
return flashingTeam.value === team ? 'flashing-glow' : '';
|
||||||
|
}
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
if (client) {
|
if (client) {
|
||||||
client.end()
|
client.end()
|
||||||
@@ -339,4 +403,23 @@
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dimmed-score {
|
||||||
|
opacity: 0.3;
|
||||||
|
transform: scale(0.95);
|
||||||
|
filter: grayscale(100%);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes flash-glow {
|
||||||
|
0%, 100% { box-shadow: 0 0 0 rgba(255, 255, 255, 0); }
|
||||||
|
10% { box-shadow: 0 0 60px 20px rgba(255, 255, 255, 0.9); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.flashing-glow {
|
||||||
|
animation: flash-glow 0.5s ease-in-out infinite;
|
||||||
|
z-index: 10;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user