mirror of
https://github.com/Pandipipas/scoreko-dev.git
synced 2026-06-06 03:32:06 +00:00
Add per-game character selection to scoreboard panel
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch, watchEffect, type Ref } from 'vue';
|
||||
import { countryOptions, getCountryLabel } from '../../../shared/countries';
|
||||
import { getCharactersByGame } from '../../../shared/fighting-characters';
|
||||
import type { Schemas } from '../../../types';
|
||||
import { usePlayersStore } from '../stores/players';
|
||||
import { useScoreboardStore } from '../stores/scoreboard';
|
||||
@@ -23,6 +24,9 @@ const rightCountryInput = ref('');
|
||||
const leftCountryOptions = ref(countryOptions);
|
||||
const rightCountryOptions = ref(countryOptions);
|
||||
|
||||
const leftCharacterInput = ref('');
|
||||
const rightCharacterInput = ref('');
|
||||
|
||||
const fightingGameOptions = [
|
||||
'Street Fighter 6',
|
||||
'TEKKEN 8',
|
||||
@@ -36,6 +40,19 @@ const fightingGameOptions = [
|
||||
value: game,
|
||||
}));
|
||||
|
||||
const characterOptions = computed(() => getCharactersByGame(scoreboardStore.scoreboard.game));
|
||||
|
||||
const leftCharacterImage = computed(() => {
|
||||
const match = characterOptions.value.find((option) => option.value === scoreboardStore.scoreboard.leftCharacter);
|
||||
return match?.image ?? '';
|
||||
});
|
||||
|
||||
const rightCharacterImage = computed(() => {
|
||||
const match = characterOptions.value.find((option) => option.value === scoreboardStore.scoreboard.rightCharacter);
|
||||
return match?.image ?? '';
|
||||
});
|
||||
|
||||
|
||||
const normalizeName = (value: string) => value.trim().toLowerCase();
|
||||
|
||||
const filterOptions = (
|
||||
@@ -566,6 +583,43 @@ watchEffect(() => {
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => scoreboardStore.scoreboard.game,
|
||||
() => {
|
||||
const options = getCharactersByGame(scoreboardStore.scoreboard.game);
|
||||
const allowed = new Set(options.map((option) => option.value));
|
||||
|
||||
if (!allowed.has(scoreboardStore.scoreboard.leftCharacter)) {
|
||||
scoreboardStore.scoreboard.leftCharacter = '';
|
||||
leftCharacterInput.value = '';
|
||||
}
|
||||
|
||||
if (!allowed.has(scoreboardStore.scoreboard.rightCharacter)) {
|
||||
scoreboardStore.scoreboard.rightCharacter = '';
|
||||
rightCharacterInput.value = '';
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
watch(
|
||||
() => scoreboardStore.scoreboard.leftCharacter,
|
||||
(value) => {
|
||||
const match = characterOptions.value.find((option) => option.value === value);
|
||||
leftCharacterInput.value = match?.label ?? '';
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
watch(
|
||||
() => scoreboardStore.scoreboard.rightCharacter,
|
||||
(value) => {
|
||||
const match = characterOptions.value.find((option) => option.value === value);
|
||||
rightCharacterInput.value = match?.label ?? '';
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -619,6 +673,34 @@ watchEffect(() => {
|
||||
/>
|
||||
</template>
|
||||
</QSelect>
|
||||
<QSelect
|
||||
v-model="scoreboardStore.scoreboard.leftCharacter"
|
||||
v-model:input-value="leftCharacterInput"
|
||||
:options="characterOptions"
|
||||
option-value="value"
|
||||
option-label="label"
|
||||
emit-value
|
||||
map-options
|
||||
label="Character"
|
||||
dense
|
||||
outlined
|
||||
use-input
|
||||
input-debounce="0"
|
||||
hide-selected
|
||||
fill-input
|
||||
clearable
|
||||
class="q-mt-sm"
|
||||
:disable="!scoreboardStore.scoreboard.game"
|
||||
/>
|
||||
<div
|
||||
v-if="leftCharacterImage"
|
||||
class="character-preview q-mt-sm"
|
||||
>
|
||||
<img
|
||||
:src="leftCharacterImage"
|
||||
alt="Left character preview"
|
||||
>
|
||||
</div>
|
||||
<QInput
|
||||
v-model="scoreboardStore.scoreboard.leftTeamOverride"
|
||||
label="Team"
|
||||
@@ -762,6 +844,34 @@ watchEffect(() => {
|
||||
/>
|
||||
</template>
|
||||
</QSelect>
|
||||
<QSelect
|
||||
v-model="scoreboardStore.scoreboard.rightCharacter"
|
||||
v-model:input-value="rightCharacterInput"
|
||||
:options="characterOptions"
|
||||
option-value="value"
|
||||
option-label="label"
|
||||
emit-value
|
||||
map-options
|
||||
label="Character"
|
||||
dense
|
||||
outlined
|
||||
use-input
|
||||
input-debounce="0"
|
||||
hide-selected
|
||||
fill-input
|
||||
clearable
|
||||
class="q-mt-sm"
|
||||
:disable="!scoreboardStore.scoreboard.game"
|
||||
/>
|
||||
<div
|
||||
v-if="rightCharacterImage"
|
||||
class="character-preview q-mt-sm"
|
||||
>
|
||||
<img
|
||||
:src="rightCharacterImage"
|
||||
alt="Right character preview"
|
||||
>
|
||||
</div>
|
||||
<QInput
|
||||
v-model="scoreboardStore.scoreboard.rightTeamOverride"
|
||||
label="Team"
|
||||
@@ -847,6 +957,21 @@ watchEffect(() => {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.character-preview {
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.character-preview img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 88px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.scoreboard-grid {
|
||||
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
||||
|
||||
Reference in New Issue
Block a user