feat: added filter options dropdown above table

This commit is contained in:
2026-04-13 20:48:09 +02:00
parent 60aba8d549
commit 4a0287ae16
5 changed files with 158 additions and 36 deletions

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 295 B

+101
View File
@@ -0,0 +1,101 @@
<template>
<div class="filters-dropdown">
<div class="wrapper">
<div class="checkboxes">
<label>
<input type="checkbox" v-model="mainStore.filters.nonPassenger" />
{{ $t('options.checkbox-non-passenger') }}
</label>
<label>
<input type="checkbox" v-model="mainStore.filters.terminating" />
{{ $t('options.checkbox-terminating') }}
</label>
<label>
<input type="checkbox" v-model="mainStore.filters.soundsEnabled" />
{{ $t('options.checkbox-sounds') }}
</label>
</div>
<hr />
<div class="selectors">
<label for="station" v-if="apiStore.activeData">
{{ $t('options.station-name') }}
<select id="station" v-model="mainStore.selectedStationName" @change="selectStation">
<option
v-for="scenery in sceneriesOnline"
:value="scenery.stationName"
:key="scenery.stationName"
>
{{ scenery.stationName }}
</option>
</select>
</label>
<label for="checkpoint">
{{ $t('options.checkpoint-name') }}
<select id="checkpoint" v-model="mainStore.selectedCheckpointName">
<option
v-for="checkpointName in mainStore.selectedStation?.stationCheckpoints"
:value="checkpointName"
:key="checkpointName"
>
{{ checkpointName }}
</option>
</select>
</label>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue';
import { useMainStore } from '../stores/mainStore';
import { useApiStore } from '../stores/apiStore';
const mainStore = useMainStore();
const apiStore = useApiStore();
const emits = defineEmits(['stationChanged']);
function selectStation() {
emits('stationChanged');
}
const sceneriesOnline = computed(() => {
if (!apiStore.activeData) return [];
return apiStore.activeData.activeSceneries
.filter((station) => {
return station.region == mainStore.region && station.isOnline;
}, [])
.sort((s1, s2) => s1.stationName.localeCompare(s2.stationName));
});
</script>
<style lang="scss" scoped>
.filters-dropdown {
position: absolute;
top: 100%;
right: 0;
width: 100%;
max-width: 400px;
height: auto;
}
.wrapper {
background-color: rgba(0, 0, 0, 0.95);
padding: 0.5em;
border-radius: 0.5em 0 0.5em 0.5em;
}
.checkboxes label,
.selectors label {
display: block;
text-align: left;
padding: 0.25em;
}
</style>
+3 -2
View File
@@ -12,10 +12,11 @@
"header-5": "DELAYED" "header-5": "DELAYED"
}, },
"options": { "options": {
"header": "Options", "btn-title": "OPTIONS",
"checkbox-non-passenger": "Non-passenger trains", "checkbox-non-passenger": "Non-passenger trains",
"checkbox-terminating": "Terminating trains", "checkbox-terminating": "Terminating trains",
"checkbox-sounds": "Sounds", "checkbox-sounds": "Sounds",
"checkpoint-name": "Checkpoint:" "checkpoint-name": "Checkpoint:",
"station-name": "Scenery:"
} }
} }
+3 -2
View File
@@ -12,10 +12,11 @@
"header-5": "OPÓŹNIONY" "header-5": "OPÓŹNIONY"
}, },
"options": { "options": {
"header": "Opcje", "btn-title": "OPCJE",
"checkbox-non-passenger": "Relacje niepasażerskie", "checkbox-non-passenger": "Relacje niepasażerskie",
"checkbox-terminating": "Relacje kończące bieg", "checkbox-terminating": "Relacje kończące bieg",
"checkbox-sounds": "Dźwięki", "checkbox-sounds": "Dźwięki",
"checkpoint-name": "Posterunek:" "checkpoint-name": "Posterunek:",
"station-name": "Sceneria:"
} }
} }
+51 -32
View File
@@ -2,36 +2,15 @@
<div class="pragotron"> <div class="pragotron">
<div class="pragotron_content"> <div class="pragotron_content">
<div class="pragotron_options"> <div class="pragotron_options">
<div class="options-checkboxes"> <div v-click-outside="() => (isFiltersDropdownOpen = false)">
<label> <button class="options-btn" @click="isFiltersDropdownOpen = !isFiltersDropdownOpen">
<input type="checkbox" v-model="mainStore.filters.nonPassenger" /> <img src="/icon-options.svg" width="20" alt="" />
{{ $t('options.checkbox-non-passenger') }} {{ $t('options.btn-title') }}
</label> </button>
<label> <transition name="filters-anim">
<input type="checkbox" v-model="mainStore.filters.terminating" /> <filters-dropdown @stationChanged="selectStation()" v-if="isFiltersDropdownOpen" />
{{ $t('options.checkbox-terminating') }} </transition>
</label>
<label>
<input type="checkbox" v-model="mainStore.filters.soundsEnabled" />
{{ $t('options.checkbox-sounds') }}
</label>
</div>
<div class="options-checkpoints">
<label for="checkpoint">
{{ $t('options.checkpoint-name') }}
<select id="checkpoint" v-model="mainStore.selectedCheckpointName">
<option
v-for="cp in mainStore.selectedStation?.stationCheckpoints"
:value="cp"
:key="cp"
>
{{ cp }}
</option>
</select>
</label>
</div> </div>
</div> </div>
@@ -122,6 +101,7 @@ import { defineComponent } from 'vue';
import { useMainStore } from '../stores/mainStore'; import { useMainStore } from '../stores/mainStore';
import { useApiStore } from '../stores/apiStore'; import { useApiStore } from '../stores/apiStore';
import { RowIndex, type ITableRow } from '../typings/common'; import { RowIndex, type ITableRow } from '../typings/common';
import FiltersDropdown from '../components/FiltersDropdown.vue';
const departureInfoEmptyObj: ITableRow = { const departureInfoEmptyObj: ITableRow = {
timetableId: -1, timetableId: -1,
@@ -151,6 +131,8 @@ const departureInfoEmptyObj: ITableRow = {
}; };
export default defineComponent({ export default defineComponent({
components: { FiltersDropdown },
props: { props: {
stationName: { stationName: {
type: String, type: String,
@@ -170,6 +152,8 @@ export default defineComponent({
includeNonPassenger: true, includeNonPassenger: true,
includeArrivals: true, includeArrivals: true,
isFiltersDropdownOpen: false,
isAnimationRunning: true, isAnimationRunning: true,
lastRefreshTime: 0, lastRefreshTime: 0,
@@ -362,6 +346,20 @@ export default defineComponent({
this.mainStore.selectedStation?.stationCheckpoints[0] || this.stationName; this.mainStore.selectedStation?.stationCheckpoints[0] || this.stationName;
}, },
selectStation() {
console.log('xd');
this.$router.push({
path: '/board',
query: {
name: this.mainStore.selectedStationName,
region: this.mainStore.region
}
});
this.selectDefaultCheckpoint();
this.shuffleRoutes();
},
abbrevStationName(name: string) { abbrevStationName(name: string) {
return name.toUpperCase(); return name.toUpperCase();
}, },
@@ -466,6 +464,19 @@ export default defineComponent({
} }
} }
.filters-anim {
&-enter-active,
&-leave-active {
transition: all 100ms ease-in-out;
}
&-enter-from,
&-leave-to {
opacity: 0;
transform: translateY(15px);
}
}
/* ************** */ /* ************** */
.pragotron { .pragotron {
@@ -475,11 +486,19 @@ export default defineComponent({
} }
.pragotron_options { .pragotron_options {
position: relative;
display: flex; display: flex;
justify-content: space-between; justify-content: flex-end;
flex-wrap: wrap;
width: 100%; width: 100%;
margin-bottom: 0.5em; }
.options-btn {
display: flex;
align-items: center;
gap: 0.25em;
font-weight: bold;
padding: 0.25em 0.5em;
border-radius: 0.5em 0.5em 0 0;
} }
.pragotron_content { .pragotron_content {