+
+
+
+
(), {
@@ -139,48 +155,55 @@ const props = withDefaults(defineProps
(), {
const highlighted = ref('');
// Define ratio groups for superposed view
-const ratioGroups = [
+const ratioGroups = computed(() => [
{
name: 'Ofertas',
actions: ['p1_propose', 'p1_no_offer'],
- labels: ['Ofrecer', 'No Ofrecer']
+ labels: ['Ofrecer', 'No Ofrecer'],
+ total: props.groupTotals?.offers || 0
},
{
name: 'Respuestas',
actions: ['p2_accept', 'p2_reject', 'p2_snatch'],
- labels: ['Aceptar', 'Rechazar', 'Robar']
+ labels: ['Aceptar', 'Rechazar', 'Robar'],
+ total: props.groupTotals?.responses || 0
},
{
- name: 'Fuerzas',
+ name: 'Forzar',
actions: ['p2_force', 'p2_no_force'],
- labels: ['Forzar', 'No Forzar']
+ labels: ['Forzar', 'No Forzar'],
+ total: props.groupTotals?.force || 0
},
{
- name: 'Vergüenzas',
+ name: 'Avergonzar',
actions: ['p1_shame', 'p1_no_shame'],
- labels: ['Asignar', 'No Asignar']
+ labels: ['Asignar', 'No Asignar'],
+ total: props.groupTotals?.shame || 0
},
{
- name: 'Denuncias',
+ name: 'Denunciar',
actions: ['p1_report', 'p1_no_report'],
- labels: ['Denunciar', 'No Denunciar']
+ labels: ['Denunciar', 'No Denunciar'],
+ total: props.groupTotals?.report || 0
},
{
- name: 'Puntuaciones',
+ name: 'Puntaje Promedio',
actions: ['score_p1', 'score_p2'],
- labels: ['P1', 'P2']
+ labels: ['P1', 'P2'],
+ total: props.groupTotals?.averageScore ? props.groupTotals.averageScore.toFixed(1) : '0.0'
},
{
- name: 'Jugadores',
- actions: ['players_with_shame', 'players_seated'],
+ name: 'Total Jugadores',
+ actions: ['players_with_shame', 'players_without_shame'],
labels: ['Con vergüenza', 'Sin vergüenza'],
+ total: props.groupTotals?.totalPlayers || 0,
isCustomRatio: true // Special handling needed
}
-];
+]);
// Compute ratio data for each group
const ratioData = computed(() => {
- return ratioGroups.map(group => {
+ return ratioGroups.value.map(group => {
const counts = props.selectedPlayerUuid
? props.playerEventCounts
: props.globalEventCounts;
@@ -188,10 +211,9 @@ const ratioData = computed(() => {
let values = group.actions.map(action => counts[action] || 0);
// Special handling for players ratio (shame vs no shame)
- if (group.isCustomRatio && group.name === 'Jugadores') {
+ if (group.isCustomRatio && group.name === 'Total Jugadores') {
const playersWithShame = counts['players_with_shame'] || 0;
- const totalPlayersSeated = counts['players_seated'] || 0;
- const playersWithoutShame = Math.max(0, totalPlayersSeated - playersWithShame);
+ const playersWithoutShame = counts['players_without_shame'] || 0;
values = [playersWithShame, playersWithoutShame];
}
@@ -484,15 +506,14 @@ function friendlyEventName(eventType: string): string {
.ratio-bars {
display: flex;
flex-direction: column;
- gap: 16px;
- flex: 1 1 auto;
- min-height: 0;
+ gap: 8px;
padding: 8px 0;
}
.ratio-group {
- flex: 1 1 0;
- min-height: 60px;
+ flex: 0 0 auto;
+ min-height: 120px;
+ margin-bottom: 8px;
transition: transform .18s ease;
}
@@ -500,9 +521,45 @@ function friendlyEventName(eventType: string): string {
transform: translateX(4px);
}
+/* Group header styles */
+.ratio-group-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-top: 12px;
+ margin-bottom: 12px;
+ padding: 8px 12px;
+ background: rgba(255, 255, 255, 0.6);
+ border: 1px solid rgba(229, 231, 235, 0.4);
+ border-radius: 10px;
+ backdrop-filter: blur(8px);
+ -webkit-backdrop-filter: blur(8px);
+}
+
+.group-title {
+ margin: 0;
+ font-size: 18px;
+ font-weight: 800;
+ color: #1e293b;
+ letter-spacing: -0.025em;
+}
+
+.group-total {
+ font-size: 16px;
+ font-weight: 900;
+ color: #667eea;
+ background: linear-gradient(135deg, rgba(102, 126, 234, 0.15) 0%, rgba(102, 126, 234, 0.08) 100%);
+ padding: 6px 12px;
+ border-radius: 999px;
+ border: 1px solid rgba(102, 126, 234, 0.25);
+ box-shadow: 0 2px 8px rgba(102, 126, 234, 0.15);
+ min-width: 48px;
+ text-align: center;
+}
+
.ratio-bar {
position: relative;
- height: 100%;
+ height: 60px;
background: linear-gradient(135deg, rgba(238,242,255,0.4) 0%, rgba(199,210,254,0.2) 100%);
border-radius: 12px;
overflow: hidden;
diff --git a/client/src/views/Leaderboard.vue b/client/src/views/Leaderboard.vue
index 2f5f372..8d8a149 100644
--- a/client/src/views/Leaderboard.vue
+++ b/client/src/views/Leaderboard.vue
@@ -11,9 +11,6 @@
-
@@ -107,16 +104,18 @@
:player-event-counts="combinedPlayerCounts"
:selected-player-uuid="selectedUuid"
:player-bar-gradient="playerBarGradient"
- :view-mode="viewMode"
+ view-mode="ratio"
:loading="loading"
:filters-collapsed="filtersCollapsed"
- :active-filters="{
- dataSource: eventFilters.dataSource.value,
- round: eventFilters.roundFilter.value.toString(),
- game: eventFilters.gameFilter.value,
- hasFilters: eventFilters.hasActiveFilters.value || !!selectedRoomId,
- selectedPlayer: selectedUuid ? players.find(p => p.uuid === selectedUuid)?.name || 'Jugador' : undefined,
- selectedRoom: selectedRoomId ? availableRooms.find(r => r.roomId === selectedRoomId)?.name || 'Sala' : undefined
+ :active-filters="activeFilters"
+ :group-totals="{
+ offers: offersTotal,
+ responses: responsesTotal,
+ force: forceTotal,
+ shame: shameTotal,
+ report: reportTotal,
+ averageScore: averageScoreTotal,
+ totalPlayers: totalPlayersCount
}"
/>
@@ -136,25 +135,6 @@ const loading = ref(false);
const eventFilters = useEventFilters();
const filtersCollapsed = ref(false);
-// View mode cycling
-type ViewMode = 'count' | 'percent' | 'ratio';
-const viewMode = ref