Filtry scenerii

This commit is contained in:
2022-09-29 19:27:54 +02:00
parent 751cadd218
commit 846d4d0547
14 changed files with 433 additions and 542 deletions
-10
View File
@@ -83,7 +83,6 @@ export default defineComponent({
}, },
async mounted() { async mounted() {
this.updateStorage();
this.setReleaseURL(); this.setReleaseURL();
watch( watch(
@@ -113,15 +112,6 @@ export default defineComponent({
this.releaseURL = releaseURL || ''; this.releaseURL = releaseURL || '';
}, },
updateStorage() {
if (!StorageManager.isRegistered('unavailable-status')) {
StorageManager.setBooleanValue('unavailable-status', true);
StorageManager.setBooleanValue('ending-status', true);
StorageManager.setBooleanValue('no-space-status', true);
StorageManager.setBooleanValue('afk-status', true);
}
},
loadLang() { loadLang() {
const storageLang = StorageManager.getStringValue('lang'); const storageLang = StorageManager.getStringValue('lang');
+30 -70
View File
@@ -1,23 +1,12 @@
<template> <template>
<div class="filter-option option"> <button class="btn--action" :class="option.section" :data-selected="option.value" @click="handleChange">
<label> {{ $t(`filters.${option.id}`) }}
<input </button>
type="checkbox"
:name="option.name"
:defaultValue="option.defaultValue"
:id="option.id"
v-model="option.value"
@change="handleChange"
/>
<span v-if="option.id != 'troll'" :class="option.section + (option.value ? ' checked' : '')"
>{{ option.id != 'troll' ? $t(`filters.${option.id}`) : 'ARKADIA ZDRÓJ' }}
</span>
</label>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { useStationFiltersStore } from '../../store/stationFiltersStore';
interface FilterOption { interface FilterOption {
id: string; id: string;
@@ -34,29 +23,26 @@ export default defineComponent({
required: true, required: true,
}, },
}, },
emits: ['optionChange'],
setup() {
return {
filterStore: useStationFiltersStore(),
};
},
methods: { methods: {
handleChange() { handleChange() {
if (this.option.name == 'troll') { this.option.value = !this.option.value;
location.href = 'https://www.youtube.com/watch?v=HIcSWuKMwOw';
return;
}
this.$emit('optionChange', { this.filterStore.changeFilterValue({
name: this.option.name, name: this.option.name,
value: this.option.value, value: !this.option.value,
}); });
}, },
}, },
setup() {
return {};
},
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '../../styles/option.scss';
$accessCol: #e03b07; $accessCol: #e03b07;
$controlCol: #0085ff; $controlCol: #0085ff;
$signalCol: #bf7c00; $signalCol: #bf7c00;
@@ -64,63 +50,49 @@ $statusCol: #349b32;
$saveCol: #28a826; $saveCol: #28a826;
$routesCol: #9049c0; $routesCol: #9049c0;
.option span { button {
font-size: 0.9em; width: 100%;
&.checked { padding: 0.4em;
border-radius: 0.4em;
&:focus-visible {
outline: 1px solid white;
}
&[data-selected='true'] {
&.access { &.access {
background-color: $accessCol; background-color: $accessCol;
box-shadow: 0 0 6px 1px $accessCol;
&::before {
box-shadow: 0 0 6px 1px $accessCol;
}
} }
&.control { &.control {
background-color: $controlCol; background-color: $controlCol;
box-shadow: 0 0 6px 1px $controlCol;
&::before {
box-shadow: 0 0 6px 1px $controlCol;
}
} }
&.signals { &.signals {
background-color: $signalCol; background-color: $signalCol;
box-shadow: 0 0 6px 1px $signalCol;
&::before {
box-shadow: 0 0 6px 1px $signalCol;
}
} }
&.routes { &.routes {
background-color: $routesCol; background-color: $routesCol;
box-shadow: 0 0 6px 1px $routesCol;
&::before {
box-shadow: 0 0 6px 1px $routesCol;
}
} }
&.status { &.status {
background-color: $statusCol; background-color: $statusCol;
box-shadow: 0 0 6px 1px $statusCol;
&::before {
box-shadow: 0 0 6px 1px $statusCol;
}
} }
&.save { &.save {
background-color: $saveCol; background-color: $saveCol;
box-shadow: 0 0 6px 1px $saveCol;
&::before {
box-shadow: 0 0 6px 1px $saveCol;
}
} }
&.troll { &.troll {
background-color: firebrick; background-color: firebrick;
box-shadow: 0 0 6px 1px firebrick;
&::before {
box-shadow: 0 0 6px 1px firebrick;
}
} }
&.mode { &.mode {
@@ -129,18 +101,6 @@ $routesCol: #9049c0;
font-weight: 500; font-weight: 500;
} }
&::before {
position: absolute;
content: '';
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 0.5em;
}
} }
} }
</style> </style>
@@ -23,13 +23,13 @@
</div> </div>
<transition name="card-anim"> <transition name="card-anim">
<div class="card" v-if="isVisible"> <div class="card" v-if="isVisible" tabindex="0" ref="cardEl">
<div class="card_content"> <div class="card_content">
<div class="card_title flex">{{ $t('filters.title') }}</div> <div class="card_title flex">{{ $t('filters.title') }}</div>
<section class="card_options"> <section class="card_options">
<filter-option <filter-option
v-for="(option, i) in inputs.options" v-for="(option, i) in filterStore.inputs.options"
:option="option" :option="option"
:key="i" :key="i"
@optionChange="handleChange" @optionChange="handleChange"
@@ -38,7 +38,7 @@
<section class="card_timestamp" style="text-align: center"> <section class="card_timestamp" style="text-align: center">
<div>{{ $t('filters.minimum-hours-title') }}</div> <div>{{ $t('filters.minimum-hours-title') }}</div>
<span class="clock"> <span class="clock">
<button @click="subHour">-</button> <button class="btn--action" @click="subHour">-</button>
<span>{{ <span>{{
minimumHours == 0 minimumHours == 0
? $t('filters.now') ? $t('filters.now')
@@ -46,7 +46,7 @@
? minimumHours + $t('filters.hour') ? minimumHours + $t('filters.hour')
: $t('filters.no-limit') : $t('filters.no-limit')
}}</span> }}</span>
<button @click="addHour">+</button> <button class="btn--action" @click="addHour">+</button>
</span> </span>
</section> </section>
@@ -63,7 +63,7 @@
</section> </section>
<section class="card_sliders"> <section class="card_sliders">
<div class="slider" v-for="(slider, i) in inputs.sliders" :key="i"> <div class="slider" v-for="(slider, i) in filterStore.inputs.sliders" :key="i">
<input <input
class="slider-input" class="slider-input"
type="range" type="range"
@@ -82,18 +82,11 @@
</section> </section>
<section class="card_actions"> <section class="card_actions">
<filter-option
@optionChange="saveFilters"
:option="{
id: 'save',
name: 'save',
section: 'mode',
value: saveOptions,
defaultValue: true,
}"
/>
<div class="action-buttons"> <div class="action-buttons">
<button class="btn--action" style="width: 100%" @click="saveFilters" :data-selected="saveOptions">
{{ $t('filters.save') }}
</button>
<button class="btn--action" @click="resetFilters">{{ $t('filters.reset') }}</button> <button class="btn--action" @click="resetFilters">{{ $t('filters.reset') }}</button>
<button class="btn--action" @click="closeCard">{{ $t('filters.close') }}</button> <button class="btn--action" @click="closeCard">{{ $t('filters.close') }}</button>
</div> </div>
@@ -106,11 +99,11 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, inject } from 'vue'; import { defineComponent, inject } from 'vue';
import inputData from '../../data/options.json';
import imageMixin from '../../mixins/imageMixin'; import imageMixin from '../../mixins/imageMixin';
import keyMixin from '../../mixins/keyMixin'; import keyMixin from '../../mixins/keyMixin';
import routerMixin from '../../mixins/routerMixin'; import routerMixin from '../../mixins/routerMixin';
import StorageManager from '../../scripts/managers/storageManager'; import StorageManager from '../../scripts/managers/storageManager';
import { useStationFiltersStore } from '../../store/stationFiltersStore';
import { useStore } from '../../store/store'; import { useStore } from '../../store/store';
import ActionButton from '../Global/ActionButton.vue'; import ActionButton from '../Global/ActionButton.vue';
@@ -118,11 +111,9 @@ import FilterOption from './FilterOption.vue';
export default defineComponent({ export default defineComponent({
components: { ActionButton, FilterOption }, components: { ActionButton, FilterOption },
emits: ['changeFilterValue', 'invertFilters', 'resetFilters'],
mixins: [imageMixin, keyMixin, routerMixin], mixins: [imageMixin, keyMixin, routerMixin],
data: () => ({ data: () => ({
inputs: { ...inputData },
saveOptions: false, saveOptions: false,
STORAGE_KEY: 'options_saved', STORAGE_KEY: 'options_saved',
@@ -138,10 +129,12 @@ export default defineComponent({
setup() { setup() {
const isVisible = inject('isFilterCardVisible'); const isVisible = inject('isFilterCardVisible');
const store = useStore(); const store = useStore();
const filterStore = useStationFiltersStore();
return { return {
isVisible, isVisible,
store, store,
filterStore,
}; };
}, },
@@ -166,6 +159,12 @@ export default defineComponent({
this.chosenSearchScenery = ''; this.chosenSearchScenery = '';
} }
}, },
isVisible(value: boolean) {
this.$nextTick(() => {
if (value) (this.$refs['cardEl'] as HTMLDivElement).focus();
});
},
}, },
methods: { methods: {
@@ -175,7 +174,7 @@ export default defineComponent({
}, },
handleChange(change: { name: string; value: boolean }) { handleChange(change: { name: string; value: boolean }) {
this.$emit('changeFilterValue', { this.filterStore.changeFilterValue({
name: change.name, name: change.name,
value: !change.value, value: !change.value,
}); });
@@ -186,7 +185,7 @@ export default defineComponent({
handleInput(e: Event) { handleInput(e: Event) {
const target = e.target as HTMLInputElement; const target = e.target as HTMLInputElement;
this.$emit('changeFilterValue', { this.filterStore.changeFilterValue({
name: target.name, name: target.name,
value: target.value, value: target.value,
}); });
@@ -203,7 +202,7 @@ export default defineComponent({
}, },
changeNumericFilterValue(name: string, value: number, saveToStorage = false) { changeNumericFilterValue(name: string, value: number, saveToStorage = false) {
this.$emit('changeFilterValue', { this.filterStore.changeFilterValue({
name, name,
value, value,
}); });
@@ -223,17 +222,8 @@ export default defineComponent({
this.changeNumericFilterValue('onlineFromHours', this.minimumHours, true); this.changeNumericFilterValue('onlineFromHours', this.minimumHours, true);
}, },
invertFilters() { saveFilters() {
this.inputs.options.forEach((option) => { this.saveOptions = !this.saveOptions;
option.value = !option.value;
StorageManager.setBooleanValue(option.name, option.value);
});
this.$emit('invertFilters');
},
saveFilters(change: { value: any }) {
this.saveOptions = change.value;
if (!this.saveOptions) { if (!this.saveOptions) {
StorageManager.unregisterStorage(this.STORAGE_KEY); StorageManager.unregisterStorage(this.STORAGE_KEY);
@@ -242,28 +232,16 @@ export default defineComponent({
StorageManager.registerStorage(this.STORAGE_KEY); StorageManager.registerStorage(this.STORAGE_KEY);
this.inputs.options.forEach((option) => StorageManager.setBooleanValue(option.name, option.value)); this.filterStore.inputs.options.forEach((option) => StorageManager.setBooleanValue(option.name, !option.value));
this.filterStore.inputs.sliders.forEach((slider) => StorageManager.setNumericValue(slider.name, slider.value));
this.inputs.sliders.forEach((slider) => StorageManager.setNumericValue(slider.name, slider.value));
}, },
resetFilters() { resetFilters() {
this.inputs.options.forEach((option) => {
option.value = option.defaultValue;
StorageManager.setBooleanValue(option.name, option.value);
});
this.inputs.sliders.forEach((slider) => {
slider.value = slider.defaultValue;
StorageManager.setNumericValue(slider.name, slider.value);
});
this.authorsInputValue = ''; this.authorsInputValue = '';
this.minimumHours = 0; this.minimumHours = 0;
this.changeNumericFilterValue('onlineFromHours', this.minimumHours, true); this.changeNumericFilterValue('onlineFromHours', this.minimumHours, true);
this.filterStore.resetFilters();
this.$emit('resetFilters');
}, },
closeCard() { closeCard() {
@@ -367,32 +345,18 @@ export default defineComponent({
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 1.15em; font-size: 1.2em;
margin-top: 0.5em;
color: $accentCol; span {
font-weight: bold; min-width: 120px;
} font-weight: bold;
span {
min-width: 100px;
}
button {
border: none;
outline: none;
background: none;
padding: 0 0.45em;
cursor: pointer;
color: white;
font-size: 1.35em;
&:focus,
&:hover {
color: $accentCol; color: $accentCol;
} }
button {
padding: 0.2em 0.6em;
}
} }
} }
@@ -435,6 +399,11 @@ export default defineComponent({
width: 50%; width: 50%;
margin: 0 auto; margin: 0 auto;
padding: 0.5em; padding: 0.5em;
&[data-selected='true'] {
background-color: lightgreen;
color: black;
}
} }
} }
} }
@@ -466,6 +435,10 @@ export default defineComponent({
min-width: 25%; min-width: 25%;
max-width: 120px; max-width: 120px;
&:focus-visible ~ * {
color: gold;
}
&::-webkit-slider-thumb { &::-webkit-slider-thumb {
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
+17 -10
View File
@@ -230,6 +230,7 @@ import stationInfoMixin from '../../mixins/stationInfoMixin';
import styleMixin from '../../mixins/styleMixin'; import styleMixin from '../../mixins/styleMixin';
import { DataStatus } from '../../scripts/enums/DataStatus'; import { DataStatus } from '../../scripts/enums/DataStatus';
import Station from '../../scripts/interfaces/Station'; import Station from '../../scripts/interfaces/Station';
import { useStationFiltersStore } from '../../store/stationFiltersStore';
import { useStore } from '../../store/store'; import { useStore } from '../../store/store';
import Loading from '../Global/Loading.vue'; import Loading from '../Global/Loading.vue';
@@ -239,17 +240,9 @@ export default defineComponent({
type: Array as () => Station[], type: Array as () => Station[],
required: true, required: true,
}, },
sorterActive: {
type: Object as () => {
index: number;
dir: number;
},
required: true,
},
setFocusedStation: { type: Function, required: true },
changeSorter: { type: Function, required: true },
}, },
components: { Loading },
mixins: [styleMixin, dateMixin, stationInfoMixin, returnBtnMixin, imageMixin], mixins: [styleMixin, dateMixin, stationInfoMixin, returnBtnMixin, imageMixin],
data: () => ({ data: () => ({
@@ -258,13 +251,22 @@ export default defineComponent({
lastSelectedStationName: '', lastSelectedStationName: '',
}), }),
computed: {
sorterActive() {
return this.stationFiltersStore.sorterActive;
},
},
setup() { setup() {
const store = useStore(); const store = useStore();
const stationFiltersStore = useStationFiltersStore();
const isDataLoaded = computed(() => { const isDataLoaded = computed(() => {
return store.dataStatuses.sceneries != DataStatus.Loading; return store.dataStatuses.sceneries != DataStatus.Loading;
}); });
return { return {
isDataLoaded, isDataLoaded,
stationFiltersStore,
}; };
}, },
@@ -272,19 +274,24 @@ export default defineComponent({
setScenery(name: string) { setScenery(name: string) {
const station = this.stations.find((station) => station.name === name); const station = this.stations.find((station) => station.name === name);
if (!station) return; if (!station) return;
this.lastSelectedStationName = station.name; this.lastSelectedStationName = station.name;
this.$router.push({ this.$router.push({
name: 'SceneryView', name: 'SceneryView',
query: { station: station.name.replaceAll(' ', '_') }, query: { station: station.name.replaceAll(' ', '_') },
}); });
}, },
openForumSite(e: Event, url: string | undefined) { openForumSite(e: Event, url: string | undefined) {
if (!url) return; if (!url) return;
e.preventDefault(); e.preventDefault();
window.open(url, '_blank'); window.open(url, '_blank');
}, },
changeSorter(i: number) {
this.stationFiltersStore.changeSorter(i);
},
}, },
components: { Loading },
}); });
</script> </script>
+2
View File
@@ -12,6 +12,8 @@
<strong v-if="train.timetableData">{{ train.timetableData.category }}&nbsp;</strong> <strong v-if="train.timetableData">{{ train.timetableData.category }}&nbsp;</strong>
<strong>{{ train.trainNo }}</strong> <strong>{{ train.trainNo }}</strong>
<span>&nbsp;| {{ train.driverName }}&nbsp;</span> <span>&nbsp;| {{ train.driverName }}&nbsp;</span>
<span>{{ train.isTimeout }}</span>
</span> </span>
</div> </div>
-9
View File
@@ -198,15 +198,6 @@
"section": "status", "section": "status",
"value": true, "value": true,
"defaultValue": true "defaultValue": true
},
{
"id": "troll",
"name": "troll",
"iconName": "",
"section": "troll",
"value": true,
"defaultValue": true
} }
], ],
"sliders": [ "sliders": [
+1 -1
View File
@@ -164,7 +164,7 @@
"hour": " godz.", "hour": " godz.",
"no-limit": "BEZ LIMITU", "no-limit": "BEZ LIMITU",
"include-selected": "POKAŻ ZAZNACZONE", "include-selected": "POKAŻ ZAZNACZONE",
"save": "ZAPISZ FILTRY", "save": "ZAPISZ FILTRY",
"reset": "RESETUJ FILTRY", "reset": "RESETUJ FILTRY",
"close": "ZAMKNIJ FILTRY" "close": "ZAMKNIJ FILTRY"
}, },
+2 -1
View File
@@ -19,9 +19,10 @@ export default interface Train {
online: boolean; online: boolean;
lastSeen: number; lastSeen: number;
region: string; region: string;
cars: string[]; cars: string[];
isTimeout: boolean;
timetableData?: { timetableData?: {
timetableId: number; timetableId: number;
category: string; category: string;
@@ -21,6 +21,7 @@ export default interface TrainAPIData {
lastSeen: number; lastSeen: number;
region: string; region: string;
isTimeout: boolean;
timetable?: { timetable?: {
timetableId: number; timetableId: number;
+7
View File
@@ -23,6 +23,13 @@ export default class StorageManager {
window.localStorage.setItem(key, val); window.localStorage.setItem(key, val);
} }
static setValue(key: string, val: any) {
if (typeof val == 'boolean') this.setBooleanValue(key, val);
else if (typeof val == 'number') this.setNumericValue(key, val);
else if (typeof val == 'string') this.setStringValue(key, val);
else this.setStringValue(key, val);
}
static removeValue(key: string) { static removeValue(key: string) {
window.localStorage.removeItem(key); window.localStorage.removeItem(key);
} }
@@ -1,295 +1,305 @@
import Filter from '../interfaces/Filter'; import { defineStore } from 'pinia';
import Station from '../interfaces/Station'; import inputData from '../data/options.json';
import StorageManager from './storageManager'; import Filter from '../scripts/interfaces/Filter';
import Station from '../scripts/interfaces/Station';
const sortStations = (a: Station, b: Station, sorter: { index: number; dir: number }) => { import StorageManager from '../scripts/managers/storageManager';
switch (sorter.index) {
case 0: const sortStations = (a: Station, b: Station, sorter: { index: number; dir: number }) => {
return sorter.dir == 1 ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name); switch (sorter.index) {
case 0:
case 1: return sorter.dir == 1 ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name);
if ((a.generalInfo?.reqLevel || 0) > (b.generalInfo?.reqLevel || 0)) return sorter.dir;
if ((a.generalInfo?.reqLevel || 0) < (b.generalInfo?.reqLevel || 0)) return -sorter.dir; case 1:
break; if ((a.generalInfo?.reqLevel || 0) > (b.generalInfo?.reqLevel || 0)) return sorter.dir;
if ((a.generalInfo?.reqLevel || 0) < (b.generalInfo?.reqLevel || 0)) return -sorter.dir;
case 2: break;
if ((a.onlineInfo?.statusTimestamp || 0) > (b.onlineInfo?.statusTimestamp || 0)) return sorter.dir;
if ((a.onlineInfo?.statusTimestamp || 0) < (b.onlineInfo?.statusTimestamp || 0)) return -sorter.dir; case 2:
break; if ((a.onlineInfo?.statusTimestamp || 0) > (b.onlineInfo?.statusTimestamp || 0)) return sorter.dir;
if ((a.onlineInfo?.statusTimestamp || 0) < (b.onlineInfo?.statusTimestamp || 0)) return -sorter.dir;
case 3: break;
if ((a.onlineInfo?.dispatcherName.toLowerCase() || '') > (b.onlineInfo?.dispatcherName.toLowerCase() || ''))
return sorter.dir; case 3:
if ((a.onlineInfo?.dispatcherName.toLowerCase() || '') < (b.onlineInfo?.dispatcherName.toLowerCase() || '')) if ((a.onlineInfo?.dispatcherName.toLowerCase() || '') > (b.onlineInfo?.dispatcherName.toLowerCase() || ''))
return -sorter.dir; return sorter.dir;
break; if ((a.onlineInfo?.dispatcherName.toLowerCase() || '') < (b.onlineInfo?.dispatcherName.toLowerCase() || ''))
return -sorter.dir;
case 4: break;
if ((a.onlineInfo?.dispatcherExp || 0) > (b.onlineInfo?.dispatcherExp || 0)) return sorter.dir;
if ((a.onlineInfo?.dispatcherExp || 0) < (b.onlineInfo?.dispatcherExp || 0)) return -sorter.dir; case 4:
break; if ((a.onlineInfo?.dispatcherExp || 0) > (b.onlineInfo?.dispatcherExp || 0)) return sorter.dir;
if ((a.onlineInfo?.dispatcherExp || 0) < (b.onlineInfo?.dispatcherExp || 0)) return -sorter.dir;
case 7: break;
if ((a.onlineInfo?.currentUsers || 0) > (b.onlineInfo?.currentUsers || 0)) return sorter.dir;
if ((a.onlineInfo?.currentUsers || 0) < (b.onlineInfo?.currentUsers || 0)) return -sorter.dir; case 7:
if ((a.onlineInfo?.currentUsers || 0) > (b.onlineInfo?.currentUsers || 0)) return sorter.dir;
if ((a.onlineInfo?.maxUsers || 0) > (b.onlineInfo?.maxUsers || 0)) return sorter.dir; if ((a.onlineInfo?.currentUsers || 0) < (b.onlineInfo?.currentUsers || 0)) return -sorter.dir;
if ((a.onlineInfo?.maxUsers || 0) < (b.onlineInfo?.maxUsers || 0)) return -sorter.dir;
break; if ((a.onlineInfo?.maxUsers || 0) > (b.onlineInfo?.maxUsers || 0)) return sorter.dir;
if ((a.onlineInfo?.maxUsers || 0) < (b.onlineInfo?.maxUsers || 0)) return -sorter.dir;
case 8: break;
if ((a.onlineInfo?.spawns.length || 0) > (b.onlineInfo?.spawns.length || 0)) return sorter.dir;
if ((a.onlineInfo?.spawns.length || 0) < (b.onlineInfo?.spawns.length || 0)) return -sorter.dir; case 8:
if ((a.onlineInfo?.spawns.length || 0) > (b.onlineInfo?.spawns.length || 0)) return sorter.dir;
break; if ((a.onlineInfo?.spawns.length || 0) < (b.onlineInfo?.spawns.length || 0)) return -sorter.dir;
case 9: break;
if ((a.onlineInfo?.scheduledTrains?.length || 0) > (b.onlineInfo?.scheduledTrains?.length || 0))
return sorter.dir; case 9:
if ((a.onlineInfo?.scheduledTrains?.length || 0) < (b.onlineInfo?.scheduledTrains?.length || 0)) if ((a.onlineInfo?.scheduledTrains?.length || 0) > (b.onlineInfo?.scheduledTrains?.length || 0))
return -sorter.dir; return sorter.dir;
if ((a.onlineInfo?.scheduledTrains?.length || 0) < (b.onlineInfo?.scheduledTrains?.length || 0))
default: return -sorter.dir;
break;
} default:
break;
return a.name.localeCompare(b.name); }
};
return a.name.localeCompare(b.name);
const filterStations = (station: Station, filters: Filter) => { };
const returnMode = false;
const filterStations = (station: Station, filters: Filter) => {
if ((station.generalInfo?.availability == 'nonPublic' || !station.generalInfo) && filters['nonPublic']) const returnMode = false;
return returnMode;
if ((station.generalInfo?.availability == 'nonPublic' || !station.generalInfo) && filters['nonPublic'])
if (station.onlineInfo?.statusID == 'ending' && filters['ending']) return returnMode; return returnMode;
if ( if (station.onlineInfo?.statusID == 'ending' && filters['ending']) return returnMode;
station.onlineInfo &&
station.onlineInfo.statusTimestamp > 0 && if (
filters['onlineFromHours'] < 8 && station.onlineInfo &&
station.onlineInfo.statusTimestamp <= Date.now() + filters['onlineFromHours'] * 3600000 station.onlineInfo.statusTimestamp > 0 &&
) filters['onlineFromHours'] < 8 &&
return returnMode; station.onlineInfo.statusTimestamp <= Date.now() + filters['onlineFromHours'] * 3600000
)
if (filters['onlineFromHours'] > 0 && station.onlineInfo && station.onlineInfo.statusTimestamp <= 0) return returnMode;
return returnMode;
if (filters['onlineFromHours'] == 8 && station.onlineInfo?.statusID != 'no-limit') return returnMode; if (filters['onlineFromHours'] > 0 && station.onlineInfo && station.onlineInfo.statusTimestamp <= 0)
return returnMode;
if (station.onlineInfo?.statusID == 'ending' && filters['endingStatus']) return returnMode; if (filters['onlineFromHours'] == 8 && station.onlineInfo?.statusID != 'no-limit') return returnMode;
if (
(station.onlineInfo?.statusID == 'not-signed' || station.onlineInfo?.statusID == 'unavailable') && if (station.onlineInfo?.statusID == 'ending' && filters['endingStatus']) return returnMode;
filters['unavailableStatus'] if (
) (station.onlineInfo?.statusID == 'not-signed' || station.onlineInfo?.statusID == 'unavailable') &&
return returnMode; filters['unavailableStatus']
if (station.onlineInfo?.statusID == 'brb' && filters['afkStatus']) return returnMode; )
if (station.onlineInfo?.statusID == 'no-space' && filters['noSpaceStatus']) return returnMode; return returnMode;
if (station.onlineInfo?.statusID == 'brb' && filters['afkStatus']) return returnMode;
if (station.onlineInfo && filters['occupied']) return returnMode; if (station.onlineInfo?.statusID == 'no-space' && filters['noSpaceStatus']) return returnMode;
if (!station.onlineInfo && filters['free']) return returnMode;
if (station.generalInfo?.availability == 'unavailable' && filters['unavailable'] && !station.onlineInfo) if (station.onlineInfo && filters['occupied']) return returnMode;
return returnMode; if (!station.onlineInfo && filters['free']) return returnMode;
if (station.generalInfo?.availability == 'unavailable' && filters['unavailable'] && !station.onlineInfo)
if (station.generalInfo) { return returnMode;
const routes = station.generalInfo.routes;
const availability = station.generalInfo.availability; if (station.generalInfo) {
const routes = station.generalInfo.routes;
if (filters['abandoned'] && availability == 'abandoned') return returnMode; const availability = station.generalInfo.availability;
if (availability == 'default' && filters['default']) return returnMode; if (filters['abandoned'] && availability == 'abandoned') return returnMode;
if (
availability != 'default' && if (availability == 'default' && filters['default']) return returnMode;
filters['notDefault'] && if (
!(availability == 'abandoned' || availability == 'unavailable') availability != 'default' &&
) filters['notDefault'] &&
return returnMode; !(availability == 'abandoned' || availability == 'unavailable')
)
if (filters['real'] && station.generalInfo.lines != '') return returnMode; return returnMode;
if (
filters['fictional'] && if (filters['real'] && station.generalInfo.lines != '') return returnMode;
station.generalInfo.lines == '' && if (
availability != 'abandoned' && filters['fictional'] &&
availability != 'unavailable' station.generalInfo.lines == '' &&
) availability != 'abandoned' &&
return returnMode; availability != 'unavailable'
)
if ( return returnMode;
station.generalInfo.reqLevel +
(availability == 'nonPublic' || availability == 'unavailable' || availability == 'abandoned' ? 1 : 0) < if (
filters['minLevel'] station.generalInfo.reqLevel +
) (availability == 'nonPublic' || availability == 'unavailable' || availability == 'abandoned' ? 1 : 0) <
return returnMode; filters['minLevel']
if ( )
station.generalInfo.reqLevel + return returnMode;
(availability == 'nonPublic' || availability == 'unavailable' || availability == 'abandoned' ? 1 : 0) > if (
filters['maxLevel'] station.generalInfo.reqLevel +
) (availability == 'nonPublic' || availability == 'unavailable' || availability == 'abandoned' ? 1 : 0) >
return returnMode; filters['maxLevel']
)
if ( return returnMode;
filters['no-1track'] &&
(routes.oneWayCatenaryRouteNames.length != 0 || routes.oneWayNoCatenaryRouteNames.length != 0) if (
) filters['no-1track'] &&
return returnMode; (routes.oneWayCatenaryRouteNames.length != 0 || routes.oneWayNoCatenaryRouteNames.length != 0)
if ( )
filters['no-2track'] && return returnMode;
(routes.twoWayCatenaryRouteNames.length != 0 || routes.twoWayNoCatenaryRouteNames.length != 0) if (
) filters['no-2track'] &&
return returnMode; (routes.twoWayCatenaryRouteNames.length != 0 || routes.twoWayNoCatenaryRouteNames.length != 0)
)
if (routes.oneWayCatenaryRouteNames.length < filters['minOneWayCatenary']) return returnMode; return returnMode;
if (routes.oneWayNoCatenaryRouteNames.length < filters['minOneWay']) return returnMode;
if (routes.oneWayCatenaryRouteNames.length < filters['minOneWayCatenary']) return returnMode;
if (routes.twoWayCatenaryRouteNames.length < filters['minTwoWayCatenary']) return returnMode; if (routes.oneWayNoCatenaryRouteNames.length < filters['minOneWay']) return returnMode;
if (routes.twoWayNoCatenaryRouteNames.length < filters['minTwoWay']) return returnMode;
if (routes.twoWayCatenaryRouteNames.length < filters['minTwoWayCatenary']) return returnMode;
if (filters[station.generalInfo.controlType]) return returnMode; if (routes.twoWayNoCatenaryRouteNames.length < filters['minTwoWay']) return returnMode;
if (filters[station.generalInfo.signalType]) return returnMode;
if (filters[station.generalInfo.controlType]) return returnMode;
if ( if (filters[station.generalInfo.signalType]) return returnMode;
filters['SPK'] &&
(station.generalInfo.controlType === 'SPK' || station.generalInfo.controlType.includes('+SPK')) if (
) filters['SPK'] &&
return returnMode; (station.generalInfo.controlType === 'SPK' || station.generalInfo.controlType.includes('+SPK'))
if ( )
filters['SCS'] && return returnMode;
(station.generalInfo.controlType === 'SCS' || station.generalInfo.controlType.includes('+SCS')) if (
) filters['SCS'] &&
return returnMode; (station.generalInfo.controlType === 'SCS' || station.generalInfo.controlType.includes('+SCS'))
if ( )
filters['SPE'] && return returnMode;
(station.generalInfo.controlType === 'SPE' || station.generalInfo.controlType.includes('+SPE')) if (
) filters['SPE'] &&
return returnMode; (station.generalInfo.controlType === 'SPE' || station.generalInfo.controlType.includes('+SPE'))
if (filters['SUP'] && station.generalInfo.SUP) return returnMode; )
return returnMode;
if ( if (filters['SUP'] && station.generalInfo.SUP) return returnMode;
filters['SCS'] &&
filters['SPK'] && if (
(station.generalInfo.controlType.includes('SPK') || station.generalInfo.controlType.includes('SCS')) filters['SCS'] &&
) filters['SPK'] &&
return returnMode; (station.generalInfo.controlType.includes('SPK') || station.generalInfo.controlType.includes('SCS'))
)
if (filters['mechaniczne'] && station.generalInfo.controlType.includes('mechaniczne')) return returnMode; return returnMode;
if (filters['czne'] && station.generalInfo.controlType.includes('czne')) return returnMode; if (filters['mechaniczne'] && station.generalInfo.controlType.includes('mechaniczne')) return returnMode;
if (filters['SBL'] && routes.sblRouteNames.length > 0) return returnMode; if (filters['ręczne'] && station.generalInfo.controlType.includes('ręczne')) return returnMode;
if ( if (filters['SBL'] && routes.sblRouteNames.length > 0) return returnMode;
filters['authors'].length > 3 &&
!station.generalInfo.authors?.map((a) => a.toLocaleLowerCase()).includes(filters['authors'].toLocaleLowerCase()) if (
) filters['authors'].length > 3 &&
return returnMode; !station.generalInfo.authors?.map((a) => a.toLocaleLowerCase()).includes(filters['authors'].toLocaleLowerCase())
} )
return returnMode;
return true; }
};
return true;
export default class StationFilterManager { };
private filterInitStates: Filter = {
default: false, const filterInitStates: Filter = {
notDefault: false, default: false,
real: false, notDefault: false,
fictional: false, real: false,
SPK: false, fictional: false,
SCS: false, SPK: false,
SPE: false, SCS: false,
SUP: false, SPE: false,
ręczne: false, SUP: false,
mechaniczne: false, ręczne: false,
współczesna: false, mechaniczne: false,
kształtowa: false, współczesna: false,
historyczna: false, kształtowa: false,
mieszana: false, historyczna: false,
SBL: false, mieszana: false,
minLevel: 0, SBL: false,
maxLevel: 20, minLevel: 0,
minOneWayCatenary: 0, maxLevel: 20,
minOneWay: 0, minOneWayCatenary: 0,
minTwoWayCatenary: 0, minOneWay: 0,
minTwoWay: 0, minTwoWayCatenary: 0,
'include-selected': false, minTwoWay: 0,
'no-1track': false, 'include-selected': false,
'no-2track': false, 'no-1track': false,
free: true, 'no-2track': false,
occupied: false, free: true,
ending: false, occupied: false,
nonPublic: false, ending: false,
unavailable: true, nonPublic: false,
abandoned: true, unavailable: true,
afkStatus: false, abandoned: true,
endingStatus: false, afkStatus: false,
noSpaceStatus: false, endingStatus: false,
unavailableStatus: false, noSpaceStatus: false,
unsignedStatus: false, unavailableStatus: false,
unsignedStatus: false,
authors: '',
authors: '',
onlineFromHours: 0,
}; onlineFromHours: 0,
};
private filters: Filter = { ...this.filterInitStates };
export const useStationFiltersStore = defineStore('stationFiltersStore', {
private sorter: { index: number; dir: number } = { index: 0, dir: 1 }; state() {
return {
checkFilters() { inputs: inputData,
if (!StorageManager.isRegistered('options_saved')) return; filters: { ...filterInitStates },
sorterActive: { index: 0, dir: 1 },
Object.keys(this.filterInitStates).forEach((filterKey) => { };
if (StorageManager.isRegistered(filterKey)) return; },
const filterType = typeof this.filterInitStates[filterKey]; actions: {
getFilteredStationList(stationList: Station[], region: string): Station[] {
if (filterType === 'boolean') return stationList
StorageManager.setBooleanValue(filterKey, !this.filterInitStates[filterKey] as boolean); .map((station) => {
if (station.onlineInfo && station.onlineInfo.region != region) {
if (filterType === 'number') delete station.onlineInfo;
StorageManager.setNumericValue(filterKey, this.filterInitStates[filterKey] as number); }
});
} return station;
})
getFilteredStationList(stationList: Station[], region: string): Station[] { .filter((station) => filterStations(station, this.filters))
return stationList .sort((a, b) => sortStations(a, b, this.sorterActive));
.map((station) => { },
if (station.onlineInfo && station.onlineInfo.region != region) {
delete station.onlineInfo; setupFilters() {
} if (!StorageManager.isRegistered('options_saved')) return;
return station; this.inputs.options.forEach((option) => {
}) if (!StorageManager.isRegistered(option.id)) return;
.filter((station) => filterStations(station, this.filters)) const savedValue = StorageManager.getBooleanValue(option.id);
.sort((a, b) => sortStations(a, b, this.sorter));
} this.filters[option.id] = savedValue;
option.value = !savedValue;
changeFilterValue(filter: { name: string; value: number }) { });
this.filters[filter.name] = filter.value;
this.inputs.sliders.forEach((slider) => {
// if(filter.name == 'authors') if (!StorageManager.isRegistered(slider.name)) return;
} const savedValue = StorageManager.getNumericValue(slider.name);
resetFilters() { this.filters[slider.name] = savedValue;
this.filters = { ...this.filterInitStates }; slider.value = savedValue;
} });
},
invertFilters() {
Object.keys(this.filters).forEach((prop) => { changeFilterValue(filter: { name: string; value: any }) {
if (typeof this.filters[prop] !== 'boolean') return; this.filters[filter.name] = filter.value;
this.filters[prop] = !this.filters[prop]; if (StorageManager.isRegistered('options_saved')) StorageManager.setValue(filter.name, filter.value);
}); },
}
resetFilters() {
changeSorter(index: number) { this.filters = { ...filterInitStates };
if (index > 4 && index < 7) return;
this.inputs.options.forEach((option) => {
if (index == this.sorter.index) this.sorter.dir = -1 * this.sorter.dir; option.value = option.defaultValue;
else this.sorter.dir = 1; StorageManager.setBooleanValue(option.name, !option.defaultValue);
});
this.sorter.index = index;
} this.inputs.sliders.forEach((slider) => {
slider.value = slider.defaultValue;
getSorter() { StorageManager.setNumericValue(slider.name, slider.defaultValue);
return this.sorter; });
} },
}
changeSorter(index: number) {
if (index > 4 && index < 7) return;
if (index == this.sorterActive.index) this.sorterActive.dir = -1 * this.sorterActive.dir;
else this.sorterActive.dir = 1;
this.sorterActive.index = index;
},
},
});
+3
View File
@@ -17,6 +17,7 @@ import {
} from '../scripts/utils/storeUtils'; } from '../scripts/utils/storeUtils';
import { APIData, StationJSONData, StoreState } from './storeTypes'; import { APIData, StationJSONData, StoreState } from './storeTypes';
export const useStore = defineStore('store', { export const useStore = defineStore('store', {
state: () => state: () =>
({ ({
@@ -53,6 +54,7 @@ export const useStore = defineStore('store', {
blockScroll: false, blockScroll: false,
listenerLaunched: false, listenerLaunched: false,
} as StoreState), } as StoreState),
actions: { actions: {
@@ -94,6 +96,7 @@ export const useStore = defineStore('store', {
cars: stock.slice(1), cars: stock.slice(1),
lastSeen: train.lastSeen, lastSeen: train.lastSeen,
isTimeout: train.isTimeout,
timetableData: timetable timetableData: timetable
? { ? {
+2 -3
View File
@@ -1,12 +1,11 @@
import { Socket } from 'socket.io-client'; import { Socket } from 'socket.io-client';
import { DataStatus } from '../scripts/enums/DataStatus'; import { DataStatus } from '../scripts/enums/DataStatus';
import { DispatcherStatsAPIData } from '../scripts/interfaces/api/DispatcherStatsAPIData';
import { DriverStatsAPIData } from '../scripts/interfaces/api/DriverStatsAPIData';
import StationAPIData from '../scripts/interfaces/api/StationAPIData'; import StationAPIData from '../scripts/interfaces/api/StationAPIData';
import TrainAPIData from '../scripts/interfaces/api/TrainAPIData'; import TrainAPIData from '../scripts/interfaces/api/TrainAPIData';
import Station from '../scripts/interfaces/Station'; import Station from '../scripts/interfaces/Station';
import Train from '../scripts/interfaces/Train'; import Train from '../scripts/interfaces/Train';
import { DispatcherStatsAPIData } from '../scripts/interfaces/api/DispatcherStatsAPIData';
import { DriverStatsAPIData } from '../scripts/interfaces/api/DriverStatsAPIData';
export type Availability = 'default' | 'unavailable' | 'nonPublic' | 'abandoned' | 'nonDefault'; export type Availability = 'default' | 'unavailable' | 'nonPublic' | 'abandoned' | 'nonDefault';
+19 -72
View File
@@ -3,37 +3,23 @@
<div class="wrapper"> <div class="wrapper">
<div class="body"> <div class="body">
<div class="options-bar"> <div class="options-bar">
<StationFilterCard <StationFilterCard :showCard="filterCardOpen" :exit="(filterCardOpen = false)" ref="filterCardRef" />
:showCard="filterCardOpen"
:exit="closeCard"
@changeFilterValue="changeFilterValue"
@invertFilters="invertFilters"
@resetFilters="resetFilters"
ref="filterCardRef"
/>
</div> </div>
<StationTable <StationTable :stations="computedStationList" />
:stations="computedStationList"
:sorterActive="filterManager.getSorter()"
:setFocusedStation="setFocusedStation"
:changeSorter="changeSorter"
/>
</div> </div>
</div> </div>
</section> </section>
</template> </template>
<script lang="ts"> <script lang="ts">
import inputData from '../data/options.json'; import { defineComponent } from 'vue';
import { defineComponent, reactive } from 'vue';
import { useStore } from '../store/store';
import StationFilterManager from '../scripts/managers/stationFilterManager';
import StorageManager from '../scripts/managers/storageManager'; import StorageManager from '../scripts/managers/storageManager';
import StationTable from '../components/StationsView/StationTable.vue'; import StationTable from '../components/StationsView/StationTable.vue';
import StationFilterCard from '../components/StationsView/StationFilterCard.vue'; import StationFilterCard from '../components/StationsView/StationFilterCard.vue';
import SelectBox from '../components/Global/SelectBox.vue'; import SelectBox from '../components/Global/SelectBox.vue';
import { useStationFiltersStore } from '../store/stationFiltersStore';
import { useStore } from '../store/store';
export default defineComponent({ export default defineComponent({
components: { components: {
@@ -46,76 +32,37 @@ export default defineComponent({
filterCardOpen: false, filterCardOpen: false,
modalHidden: true, modalHidden: true,
STORAGE_KEY: 'options_saved', STORAGE_KEY: 'options_saved',
inputs: inputData,
focusedStationName: '', focusedStationName: '',
}), }),
setup() { setup() {
const store = useStore();
const filterManager = reactive(new StationFilterManager());
return { return {
filterManager, filterStore: useStationFiltersStore(),
store, store: useStore(),
}; };
}, },
computed: { computed: {
computedStationList() { computedStationList() {
const list = this.filterManager.getFilteredStationList(this.store.stationList, this.store.region.id); const list = this.filterStore.getFilteredStationList(this.store.stationList, this.store.region.id);
return list; return list;
}, },
}, },
mounted() { mounted() {
if (!StorageManager.isRegistered(this.STORAGE_KEY)) return; this.filterStore.setupFilters();
// this.filterStore.inputs.options.forEach((option) => {
// const value = StorageManager.getBooleanValue(option.name);
// option.value = value;
// this.filterStore.changeFilterValue({ name: option.name, value: value });
// });
this.filterManager.checkFilters(); // this.filterStore.inputs.sliders.forEach((slider) => {
// const value = StorageManager.getNumericValue(slider.name);
this.inputs.options.forEach((option) => { // slider.value = value;
const value = StorageManager.getBooleanValue(option.name); // this.filterStore.changeFilterValue({ name: slider.name, value: value });
this.changeFilterValue({ name: option.name, value: value ? 0 : 1 }); // });
option.value = value;
});
this.inputs.sliders.forEach((slider) => {
const value = StorageManager.getNumericValue(slider.name);
this.changeFilterValue({ name: slider.name, value });
slider.value = value;
});
},
methods: {
toggleCardsState(name: string): void {
if (name == 'filter') {
this.filterCardOpen = !this.filterCardOpen;
}
},
changeSorter(index: number) {
this.filterManager.changeSorter(index);
},
changeFilterValue(filter: { name: string; value: number }) {
this.filterManager.changeFilterValue(filter);
},
resetFilters() {
this.filterManager.resetFilters();
},
invertFilters() {
this.filterManager.invertFilters();
},
closeCard() {
this.filterCardOpen = false;
},
setFocusedStation(name: string) {
this.focusedStationName = this.focusedStationName == name ? '' : name;
},
}, },
}); });
</script> </script>