Add player filtering to scoreboard selects (#25)

* Add player filtering to scoreboard selects

* Hide selected player while typing

* Avoid duplicated text in player selects

* Show selected player only when not typing
This commit is contained in:
Pandipipas
2026-02-09 01:12:48 +01:00
committed by GitHub
parent 56a83e8301
commit e045331a95
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed } from 'vue';
import { computed, ref, watchEffect } from 'vue';
import type { Schemas } from '../../../types';
import { usePlayersStore } from '../stores/players';
import { useScoreboardStore } from '../stores/scoreboard';
@@ -7,6 +7,24 @@ import { useScoreboardStore } from '../stores/scoreboard';
const playersStore = usePlayersStore();
const scoreboardStore = useScoreboardStore();
const leftFilter = ref('');
const rightFilter = ref('');
const leftInput = ref('');
const rightInput = ref('');
const leftFocused = ref(false);
const rightFocused = ref(false);
const filterOptions = (
options: { label: string; value: string }[],
needle: string,
) => {
if (!needle) {
return options;
}
const lowerNeedle = needle.toLowerCase();
return options.filter((option) => option.label.toLowerCase().includes(lowerNeedle));
};
const playerOptions = computed(() => {
const base = [{ label: '(Sin asignar)', value: '' }];
const entries = Object.entries(playersStore.players) as [string, Schemas.Players[string]][];
@@ -16,6 +34,73 @@ const playerOptions = computed(() => {
}));
return base.concat(options);
});
const getPlayerLabel = (playerId: string) => {
const match = playerOptions.value.find((option) => option.value === playerId);
return match ? match.label : '';
};
const leftPlayerOptions = computed(() => filterOptions(playerOptions.value, leftFilter.value));
const rightPlayerOptions = computed(() => filterOptions(playerOptions.value, rightFilter.value));
const onLeftFilter = (val: string, update: (fn: () => void) => void) => {
update(() => {
leftFilter.value = val;
leftInput.value = val;
});
};
const onRightFilter = (val: string, update: (fn: () => void) => void) => {
update(() => {
rightFilter.value = val;
rightInput.value = val;
});
};
const onLeftFocus = () => {
leftFocused.value = true;
leftInput.value = '';
};
const onLeftBlur = () => {
leftFocused.value = false;
leftFilter.value = '';
leftInput.value = getPlayerLabel(scoreboardStore.scoreboard.leftPlayerId);
};
const onRightFocus = () => {
rightFocused.value = true;
rightInput.value = '';
};
const onRightBlur = () => {
rightFocused.value = false;
rightFilter.value = '';
rightInput.value = getPlayerLabel(scoreboardStore.scoreboard.rightPlayerId);
};
const onLeftSelect = () => {
leftFilter.value = '';
leftInput.value = getPlayerLabel(scoreboardStore.scoreboard.leftPlayerId);
};
const onRightSelect = () => {
rightFilter.value = '';
rightInput.value = getPlayerLabel(scoreboardStore.scoreboard.rightPlayerId);
};
watchEffect(() => {
if (!leftFocused.value) {
leftInput.value = getPlayerLabel(scoreboardStore.scoreboard.leftPlayerId);
}
});
watchEffect(() => {
if (!rightFocused.value) {
rightInput.value = getPlayerLabel(scoreboardStore.scoreboard.rightPlayerId);
}
});
</script>
<template>
@@ -50,12 +135,21 @@ const playerOptions = computed(() => {
<QCardSection>
<QSelect
v-model="scoreboardStore.scoreboard.leftPlayerId"
:options="playerOptions"
:options="leftPlayerOptions"
label="Jugador"
dense
outlined
emit-value
map-options
use-input
input-debounce="0"
hide-selected
fill-input
v-model:input-value="leftInput"
@filter="onLeftFilter"
@focus="onLeftFocus"
@blur="onLeftBlur"
@update:model-value="onLeftSelect"
/>
<QInput
v-model="scoreboardStore.scoreboard.leftNameOverride"
@@ -86,12 +180,21 @@ const playerOptions = computed(() => {
<QCardSection>
<QSelect
v-model="scoreboardStore.scoreboard.rightPlayerId"
:options="playerOptions"
:options="rightPlayerOptions"
label="Jugador"
dense
outlined
emit-value
map-options
use-input
input-debounce="0"
hide-selected
fill-input
v-model:input-value="rightInput"
@filter="onRightFilter"
@focus="onRightFocus"
@blur="onRightBlur"
@update:model-value="onRightSelect"
/>
<QInput
v-model="scoreboardStore.scoreboard.rightNameOverride"