Add Pinia persistence and scoreboard support (#15)

* Add scoreboard replicant and Pinia persistence

* Fix scoreboard replicant sync (#16)
This commit is contained in:
Pandipipas
2026-02-08 17:00:31 +01:00
committed by GitHub
parent e0323cca3f
commit b4a110fd1e
16 changed files with 712 additions and 64 deletions
+8
View File
@@ -0,0 +1,8 @@
import { createHead } from '@unhead/vue/client';
import { createApp } from 'vue';
import App from './main.vue';
const app = createApp(App);
const head = createHead();
app.use(head);
app.mount('#app');
+135
View File
@@ -0,0 +1,135 @@
<script setup lang="ts">
import { useHead } from '@unhead/vue';
import { computed } from 'vue';
import type { Ref } from 'vue';
import { playersReplicant, scoreboardReplicant } from '../../browser_shared/replicants';
import type { Schemas } from '../../types';
useHead({ title: 'Scoreboard' });
const defaultScoreboard: Schemas.Scoreboard = {
leftPlayerId: '',
rightPlayerId: '',
leftNameOverride: '',
rightNameOverride: '',
leftScore: 0,
rightScore: 0,
round: '',
};
const playersData = playersReplicant?.data as unknown as Ref<Schemas.Players | undefined> | undefined;
const scoreboardData = scoreboardReplicant?.data as unknown as Ref<Schemas.Scoreboard | undefined> | undefined;
const players = computed<Schemas.Players>(() => playersData?.value ?? {});
const scoreboard = computed<Schemas.Scoreboard>(() => scoreboardData?.value ?? defaultScoreboard);
const leftName = computed(() => {
if (scoreboard.value.leftNameOverride) {
return scoreboard.value.leftNameOverride;
}
const player = players.value[scoreboard.value.leftPlayerId];
return player?.gamertag || 'Jugador 1';
});
const rightName = computed(() => {
if (scoreboard.value.rightNameOverride) {
return scoreboard.value.rightNameOverride;
}
const player = players.value[scoreboard.value.rightPlayerId];
return player?.gamertag || 'Jugador 2';
});
</script>
<template>
<div class="scoreboard-root">
<div class="scoreboard-panel">
<div class="scoreboard-round">
{{ scoreboard.round || 'Round' }}
</div>
<div class="scoreboard-row">
<div class="scoreboard-side">
<div class="scoreboard-name">
{{ leftName }}
</div>
<div class="scoreboard-score">
{{ scoreboard.leftScore }}
</div>
</div>
<div class="scoreboard-divider">VS</div>
<div class="scoreboard-side">
<div class="scoreboard-name">
{{ rightName }}
</div>
<div class="scoreboard-score">
{{ scoreboard.rightScore }}
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.scoreboard-root {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 40px;
font-family: 'Roboto', sans-serif;
color: #ffffff;
background: transparent;
}
.scoreboard-panel {
width: min(900px, 100%);
padding: 24px 32px;
border-radius: 16px;
background: rgba(10, 12, 20, 0.85);
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.35);
}
.scoreboard-round {
font-size: 20px;
text-transform: uppercase;
letter-spacing: 0.12em;
opacity: 0.8;
margin-bottom: 20px;
}
.scoreboard-row {
display: grid;
grid-template-columns: 1fr auto 1fr;
align-items: center;
gap: 24px;
}
.scoreboard-side {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
gap: 16px;
}
.scoreboard-divider {
font-size: 18px;
letter-spacing: 0.2em;
opacity: 0.6;
}
.scoreboard-name {
font-size: 28px;
font-weight: 600;
}
.scoreboard-score {
font-size: 36px;
font-weight: 700;
background: rgba(255, 255, 255, 0.12);
padding: 8px 16px;
border-radius: 10px;
min-width: 64px;
text-align: center;
}
</style>