chore(filters): added filtering stations by external and internal route groups; changed sliders to min & max range

This commit is contained in:
2026-03-11 18:17:12 +01:00
parent 7073c0687c
commit 1a39c9054b
4 changed files with 310 additions and 129 deletions
@@ -0,0 +1,140 @@
<template>
<div class="filter-slider">
<input
v-for="slider in sliderOptionsList[sliderGroup]"
type="range"
:name="slider.id"
:id="slider.id"
:min="slider.minRange"
:max="slider.maxRange"
:step="slider.step"
v-model="filters[slider.id]"
/>
</div>
</template>
<script lang="ts" setup>
import { inject, PropType } from 'vue';
import { SliderGroup, sliderOptionsList } from '../../managers/stationFilterManager';
const filters = inject('StationsView_filters') as Record<string, any>;
const props = defineProps({
sliderGroup: {
type: Object as PropType<SliderGroup>,
required: true
}
});
</script>
<style lang="scss" scoped>
@use '../../styles/responsive';
.filter-slider {
position: relative;
padding: 0.5em;
}
.filter-slider > input {
position: absolute;
width: 100%;
top: 50%;
transform: translateY(-50%);
-webkit-appearance: none;
appearance: none;
background: none;
border: none;
outline: none;
pointer-events: none;
&:focus-visible ~ * {
color: gold;
}
&::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
pointer-events: all;
z-index: 100;
height: 20px;
width: 20px;
margin-top: -7px;
border-radius: 50%;
background-color: var(--clr-primary);
@include responsive.smallScreen {
width: 15px;
height: 15px;
margin-top: -5px;
}
}
&::-moz-range-thumb {
pointer-events: all;
position: relative;
z-index: 10;
height: 1em;
width: 1em;
border-radius: 50%;
background-color: #333;
border: 3px solid var(--clr-primary);
cursor: pointer;
@include responsive.smallScreen {
width: 1em;
height: 1em;
}
}
&::-webkit-slider-runnable-track {
position: relative;
z-index: 1;
width: 100%;
height: 5px;
cursor: pointer;
border-radius: 1em;
}
&:first-child::-webkit-slider-runnable-track {
background: var(--clr-primary);
}
&::-moz-range-track {
position: relative;
z-index: -1;
width: 100%;
height: 5px;
cursor: pointer;
background: none;
border-radius: 1em;
}
&:first-child::-moz-range-track {
background: var(--clr-primary);
}
&::-ms-track {
width: 100%;
height: 5px;
cursor: pointer;
background: none;
border-radius: 1em;
}
&:first-child::-ms-track {
background: white;
}
}
</style>
+31 -100
View File
@@ -137,20 +137,16 @@
</section>
<section class="card_sliders">
<div class="slider" v-for="(slider, i) in sliderStates" :key="i">
<input
class="slider-input"
type="range"
:name="slider.id"
:id="slider.id"
:min="slider.minRange"
:max="slider.maxRange"
:step="slider.step"
v-model.number="filters[slider.id]"
/>
<span class="slider-value">{{ filters[slider.id] }}</span>
<div class="slider-box" v-for="(sliderGroup, i) in sliderGroups" :key="i">
<FilterSlider :sliderGroup="sliderGroup" />
<span class="slider-value">
{{ filters[sliderOptionsList[sliderGroup][0].id] }} -
{{ filters[sliderOptionsList[sliderGroup][1].id] }}
</span>
<div class="slider-content">
{{ $t(`filters.sliders.${slider.id}`) }}
{{ $t(`filters.sliders.${sliderGroups[i]}`) }}
</div>
</div>
</section>
@@ -190,13 +186,15 @@ import routerMixin from '../../mixins/routerMixin';
import { useMainStore } from '../../store/mainStore';
import FilterOption from './FilterOption.vue';
import FilterSlider from './FilterSlider.vue';
import StorageManager from '../../managers/storageManager';
import {
filtersSections,
sliderStates,
initFilters,
getChangedFilters
sliderGroups,
getChangedFilters,
sliderOptionsList
} from '../../managers/stationFilterManager';
import { StationFilterSection } from '../../managers/stationFilterManager';
@@ -206,14 +204,15 @@ import { watch } from 'vue';
const STORAGE_KEY = 'options_saved';
export default defineComponent({
components: { FilterOption },
components: { FilterOption, FilterSlider },
mixins: [keyMixin, routerMixin],
data: () => ({
saveOptions: false,
filtersSections,
sliderStates,
sliderGroups,
sliderOptionsList,
minimumHours: 0,
@@ -516,7 +515,7 @@ h3.hours-section-header {
.section-filters {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
gap: 0.5em;
margin: 1em 0;
}
@@ -528,9 +527,11 @@ h3.hours-section-header {
-moz-user-select: none;
span {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
cursor: pointer;
display: inline-block;
width: 100%;
text-align: center;
padding: 0.25em;
font-weight: bold;
@@ -588,10 +589,14 @@ h3.hours-section-header {
}
}
.slider {
.card_sliders {
margin-top: 1em;
}
.slider-box {
display: grid;
grid-template-columns: 1fr 50px 1fr;
align-items: center;
grid-template-columns: 250px 100px 1fr;
gap: 0.25em;
margin-bottom: 1em;
@@ -601,88 +606,14 @@ h3.hours-section-header {
padding: 0.1em 0.2em;
text-align: center;
}
}
&-input {
-webkit-appearance: none;
appearance: none;
background: none;
border: none;
outline: none;
min-width: 25%;
&:focus-visible ~ * {
color: gold;
}
&::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
height: 20px;
width: 20px;
margin-top: -7px;
border-radius: 50%;
background: white;
border: 3px solid var(--clr-primary);
background-color: #333;
@include responsive.smallScreen {
width: 15px;
height: 15px;
margin-top: -5px;
border: 3px solid var(--clr-primary);
}
}
&::-moz-range-thumb {
height: 1em;
width: 1em;
border-radius: 50%;
background: white;
border: 4px solid var(--clr-primary);
cursor: pointer;
@include responsive.smallScreen {
width: 1em;
height: 1em;
border: 3px solid var(--clr-primary);
}
}
&::-webkit-slider-runnable-track {
width: 100%;
height: 5px;
cursor: pointer;
background: #ffffff;
border-radius: 1em;
}
&::-moz-range-track {
width: 100%;
height: 5px;
cursor: pointer;
background: #ffffff;
border-radius: 1em;
}
&::-ms-track {
width: 100%;
height: 5px;
cursor: pointer;
background: #ffffff;
border-radius: 1em;
}
}
.slider-value {
text-align: center;
}
@include responsive.smallScreen {
.slider {
.slider-box {
display: flex;
flex-wrap: wrap;
justify-content: center;
+23 -13
View File
@@ -247,7 +247,9 @@
"blockades": "BLOKADY LINIOWE",
"status": "STATUS ONLINE",
"timetables": "AKTYWNE ROZKŁADY JAZDY",
"spawns": "OTWARTE SPAWNY"
"spawns": "OTWARTE SPAWNY",
"externalRoutes": "SZLAKI ZEWNĘTRZNE",
"internalRoutes": "SZLAKI WEWNĘTRZNE"
},
"changed-filters-count": "Zmienione filtry:",
"no-changed-filters": "Brak zmienionych filtrów",
@@ -291,19 +293,27 @@
"withoutActiveTimetables": "BEZ AKTYWNYCH",
"junction": "WĘZŁOWE",
"nonJunction": "INNE",
"oneWay": "JEDNOTOROWE NIEZELEKTRYFIKOWANE",
"oneWayCatenary": "JEDNOTOROWE ZELEKTRYFIKOWANE",
"twoWayCatenary": "DWUTOROWE ZELEKTRYFIKOWANE",
"twoWay": "DWUTOROWE NIEZELEKTRYFIKOWANE",
"oneWayCatenaryInt": "JEDNOTOROWE ZELEKTRYFIKOWANE",
"oneWayInt": "JEDNOTOROWE NIEZELEKTRYFIKOWANE",
"twoWayCatenaryInt": "DWUTOROWE ZELEKTRYFIKOWANE",
"twoWayInt": "DWUTOROWE NIEZELEKTRYFIKOWANE",
"sliders": {
"minLevel": "MIN. WYMAGANY POZIOM DYŻURNEGO",
"maxLevel": "MAKS. WYMAGANY POZIOM DYŻURNEGO",
"minVmax": "MIN. PRĘDKOŚĆ SZLAKOWA",
"maxVmax": "MAKS. PRĘDKOŚĆ SZLAKOWA",
"minOneWayCatenary": "SZLAKI JEDNOTOROWE ZELEKTR. (MINIMUM)",
"minOneWay": "SZLAKI JEDNOTOROWE NIEZELEKTR. (MINIMUM)",
"minTwoWayCatenary": "SZLAKI DWUTOROWE ZELEKTR. (MINIMUM)",
"minTwoWay": "SZLAKI DWUTOROWE NIEZELEKTR. (MINIMUM)",
"minOneWayCatenaryInt": "SZLAKI JEDNOTOROWE ZELEKTR. WEWNĘTRZNE (MINIMUM)",
"minOneWayInt": "SZLAKI JEDNOTOROWE NIEZELEKTR. WEWNĘTRZNE (MINIMUM)",
"minTwoWayCatenaryInt": "SZLAKI DWUTOROWE ZELEKTR. WEWNĘTRZNE (MINIMUM)",
"minTwoWayInt": "SZLAKI DWUTOROWE NIEZELEKTR. WEWNĘTRZNE (MINIMUM)"
"vMax": "PRĘDKOŚĆ SZLAKOWA",
"level": "WYMAGANY POZIOM DYŻURNEGO",
"routeOneWay": "SZLAKI JEDNOTOROWE NIEZELEKTR.",
"routeOneWayCatenary": "SZLAKI JEDNOTOROWE ZELEKTR.",
"routeTwoWayCatenary": "SZLAKI DWUTOROWE ZELEKTR.",
"routeTwoWay": "SZLAKI DWUTOROWE NIEZELEKTR.",
"routeOneWayInternalCatenary": "SZLAKI JEDNOTOROWE ZELEKTR. WEWNĘTRZNE",
"routeOneWayInternal": "SZLAKI JEDNOTOROWE NIEZELEKTR. WEWNĘTRZNE",
"routeTwoWayInternalCatenary": "SZLAKI DWUTOROWE ZELEKTR. WEWNĘTRZNE",
"routeTwoWayInternal": "SZLAKI DWUTOROWE NIEZELEKTR. WEWNĘTRZNE"
},
"sceneries-placeholder": "Wyszukaj scenerię",
"line-numbers-placeholder": "Numery linii (oddzielone przecinkami)",
+116 -16
View File
@@ -1,5 +1,24 @@
import StorageManager from './storageManager';
export type SliderGroup =
| 'vMax'
| 'level'
| 'routeOneWay'
| 'routeOneWayCatenary'
| 'routeOneWayInternal'
| 'routeOneWayInternalCatenary'
| 'routeTwoWay'
| 'routeTwoWayCatenary'
| 'routeTwoWayInternal'
| 'routeTwoWayInternalCatenary';
export interface SliderOptions {
id: string;
minRange: number;
maxRange: number;
step: number;
}
export const sections = [
'status',
'timetables',
@@ -10,7 +29,9 @@ export const sections = [
'control',
'blockades',
'signals',
'addons'
'addons',
'externalRoutes',
'internalRoutes'
] as const;
export const initFilters = {
@@ -60,34 +81,111 @@ export const initFilters = {
onlineFromHours: 0,
minLevel: 0,
maxLevel: 20,
oneWay: false,
oneWayCatenary: false,
twoWay: false,
twoWayCatenary: false,
oneWayCatenaryInt: false,
oneWayInt: false,
twoWayInt: false,
twoWayCatenaryInt: false,
minOneWay: 0,
minOneWayCatenary: 0,
minOneWayInt: 0,
minOneWayCatenaryInt: 0,
minOneWayInt: 0,
minTwoWay: 0,
minTwoWayCatenary: 0,
minTwoWayInt: 0,
minTwoWayCatenaryInt: 0,
maxOneWay: 5,
maxOneWayCatenary: 5,
maxOneWayInt: 5,
maxOneWayCatenaryInt: 5,
maxTwoWay: 5,
maxTwoWayCatenary: 5,
maxTwoWayInt: 5,
maxTwoWayCatenaryInt: 5,
authors: '',
projects: '',
lines: ''
};
export const sliderStates = [
{ id: 'maxVmax', minRange: 0, maxRange: 200, step: 10 },
{ id: 'minVmax', minRange: 0, maxRange: 200, step: 10 },
{ id: 'minLevel', minRange: 0, maxRange: 20, step: 1 },
{ id: 'maxLevel', minRange: 0, maxRange: 20, step: 1 },
{ id: 'minOneWay', minRange: 0, maxRange: 5, step: 1 },
{ id: 'minOneWayCatenary', minRange: 0, maxRange: 5, step: 1 },
{ id: 'minOneWayInt', minRange: 0, maxRange: 5, step: 1 },
{ id: 'minOneWayCatenaryInt', minRange: 0, maxRange: 5, step: 1 },
{ id: 'minTwoWay', minRange: 0, maxRange: 5, step: 1 },
{ id: 'minTwoWayCatenary', minRange: 0, maxRange: 5, step: 1 },
{ id: 'minTwoWayInt', minRange: 0, maxRange: 5, step: 1 },
{ id: 'minTwoWayCatenaryInt', minRange: 0, maxRange: 5, step: 1 }
export const sliderGroups: SliderGroup[] = [
'vMax',
'level',
'routeOneWay',
'routeOneWayCatenary',
'routeOneWayInternal',
'routeOneWayInternalCatenary',
'routeTwoWay',
'routeTwoWayCatenary',
'routeTwoWayInternal',
'routeTwoWayInternalCatenary'
];
export const sliderOptionsList: Record<SliderGroup, SliderOptions[]> = {
vMax: [
{ id: 'minVmax', minRange: 0, maxRange: 200, step: 10 },
{ id: 'maxVmax', minRange: 0, maxRange: 200, step: 10 }
],
level: [
{ id: 'minLevel', minRange: 0, maxRange: 20, step: 1 },
{ id: 'maxLevel', minRange: 0, maxRange: 20, step: 1 }
],
routeOneWay: [
{ id: 'minOneWay', minRange: 0, maxRange: 5, step: 1 },
{ id: 'maxOneWay', minRange: 0, maxRange: 5, step: 1 }
],
routeOneWayCatenary: [
{ id: 'minOneWayCatenary', minRange: 0, maxRange: 5, step: 1 },
{ id: 'maxOneWayCatenary', minRange: 0, maxRange: 5, step: 1 }
],
routeOneWayInternal: [
{ id: 'minOneWayInt', minRange: 0, maxRange: 5, step: 1 },
{ id: 'maxOneWayInt', minRange: 0, maxRange: 5, step: 1 }
],
routeOneWayInternalCatenary: [
{
id: 'minOneWayCatenaryInt',
minRange: 0,
maxRange: 5,
step: 1
},
{
id: 'maxOneWayCatenaryInt',
minRange: 0,
maxRange: 5,
step: 1
}
],
routeTwoWay: [
{ id: 'minTwoWay', minRange: 0, maxRange: 5, step: 1 },
{ id: 'maxTwoWay', minRange: 0, maxRange: 5, step: 1 }
],
routeTwoWayCatenary: [
{ id: 'minTwoWayCatenary', minRange: 0, maxRange: 5, step: 1 },
{ id: 'maxTwoWayCatenary', minRange: 0, maxRange: 5, step: 1 }
],
routeTwoWayInternal: [
{ id: 'minTwoWayInt', minRange: 0, maxRange: 5, step: 1 },
{ id: 'maxTwoWayInt', minRange: 0, maxRange: 5, step: 1 }
],
routeTwoWayInternalCatenary: [
{
id: 'minTwoWayCatenaryInt',
minRange: 0,
maxRange: 5,
step: 1
},
{
id: 'maxTwoWayCatenaryInt',
minRange: 0,
maxRange: 5,
step: 1
}
]
};
export type StationFilter = keyof typeof initFilters;
export type StationFilterSection = (typeof sections)[number];
@@ -112,7 +210,9 @@ export const filtersSections: Record<StationFilterSection, StationFilter[]> = {
'manual'
],
blockades: ['SBL', 'PBL'],
signals: ['modern', 'semaphores', 'mixed', 'historical']
signals: ['modern', 'semaphores', 'mixed', 'historical'],
externalRoutes: ['oneWay', 'oneWayCatenary', 'twoWay', 'twoWayCatenary'],
internalRoutes: ['oneWayInt', 'oneWayCatenaryInt', 'twoWayInt', 'twoWayCatenaryInt']
};
export function setupFilters(currentFilters: Record<string, any>) {