From 05ccb4c74ca56139b049ecf68a583eb762f23e2c Mon Sep 17 00:00:00 2001 From: Spythere Date: Tue, 7 Jul 2020 13:32:22 +0200 Subject: [PATCH] =?UTF-8?q?Zmiana=20wygl=C4=85du=20filtr=C3=B3w,=20doko?= =?UTF-8?q?=C5=84czenie=20pozosta=C5=82ych=20z=20nich?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 6 + package.json | 1 + src/App.vue | 46 +++++- src/assets/icon-filter2.svg | 1 + src/components/ui/List.vue | 2 - src/components/ui/Options.vue | 53 ++++--- src/components/utils/ListFilter.vue | 185 ++++++++++++++++++++---- src/store/backup.ts | 134 +++++++++++++++++ src/store/index.ts | 134 +---------------- src/store/modules/store.ts | 215 ++++++++++++++++++++++++++++ src/styles/responsive.scss | 2 +- src/styles/variables.scss | 2 +- src/views/Home.vue | 5 +- 13 files changed, 587 insertions(+), 199 deletions(-) create mode 100644 src/assets/icon-filter2.svg create mode 100644 src/store/backup.ts create mode 100644 src/store/modules/store.ts diff --git a/package-lock.json b/package-lock.json index 253db63..b02dc2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10157,6 +10157,12 @@ "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.5.1.tgz", "integrity": "sha512-w7oJzmHQs0FM9LXodfskhw9wgKBiaB+totOdb8sNzbTB2KDCEEwEs29NzBZFh/lmEK1t5tDmM1vtsO7ubG1DFw==" }, + "vuex-class": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/vuex-class/-/vuex-class-0.3.2.tgz", + "integrity": "sha512-m0w7/FMsNcwJgunJeM+wcNaHzK2KX1K1rw2WUQf7Q16ndXHo7pflRyOV/E8795JO/7fstyjH3EgqBI4h4n4qXQ==", + "dev": true + }, "vuex-module-decorators": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/vuex-module-decorators/-/vuex-module-decorators-0.17.0.tgz", diff --git a/package.json b/package.json index 649f437..e434b8d 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "sass-loader": "^8.0.2", "typescript": "~3.9.3", "vue-template-compiler": "^2.6.11", + "vuex-class": "^0.3.2", "vuex-module-decorators": "^0.17.0" }, "browserslist": [ diff --git a/src/App.vue b/src/App.vue index d9f9ad2..f2878d8 100644 --- a/src/App.vue +++ b/src/App.vue @@ -7,10 +7,17 @@ trainlogo wnik + Scenerie online: {{stationCount}} | Maszyniści online: {{ trainCount }} -
- Scenerie online: {{stationCount}} | Maszyniści online: {{ trainCount }} +
+
+ +
+ +
+ +
@@ -31,11 +38,12 @@ import { mapGetters, mapActions } from "vuex"; import Error from "@/components/states/Error.vue"; import Loading from "@/components/states/Loading.vue"; +import Options from "@/components/ui/Options.vue"; // import ListFilter from "@/components/utils/ListFilter.vue"; export default Vue.extend({ name: "App", - components: { Error, Loading }, + components: { Error, Loading, Options }, computed: mapGetters({ stations: "getStations", trainCount: "getTrainCount", @@ -87,6 +95,22 @@ input { font-family: "Lato", sans-serif; } +input { + border: 1px solid white; + background: none; + color: white; + font-size: 1em; + + padding: 0.15em; + margin: 0.2em; + + max-width: 55px; + + &::placeholder { + color: #bebebe; + } +} + *, *::before, *::after { @@ -111,6 +135,11 @@ a { } } +ul { + padding: 0; + list-style: none; +} + .app { color: white; overflow: hidden; @@ -131,6 +160,7 @@ a { flex-direction: column; background: #333; + padding: 0.4rem; & > .brand-name { font-size: calc(1rem + 3.5vw); @@ -139,18 +169,20 @@ a { width: calc(1rem + 2.3vw); } } + + .online { + font-size: calc(0.6rem + 0.4vw); + } } - &-info { + &-bar { display: flex; - justify-content: center; align-items: center; + justify-content: space-between; font-size: calc(0.8rem + 0.2vw); background: #222; - - padding: 0.3rem; } } diff --git a/src/assets/icon-filter2.svg b/src/assets/icon-filter2.svg new file mode 100644 index 0000000..407e690 --- /dev/null +++ b/src/assets/icon-filter2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/ui/List.vue b/src/components/ui/List.vue index c16469a..4c20c20 100644 --- a/src/components/ui/List.vue +++ b/src/components/ui/List.vue @@ -248,8 +248,6 @@ ul { display: block; - max-height: 100vh; - white-space: nowrap; border-collapse: collapse; diff --git a/src/components/ui/Options.vue b/src/components/ui/Options.vue index 236e7e9..2cd14b6 100644 --- a/src/components/ui/Options.vue +++ b/src/components/ui/Options.vue @@ -5,14 +5,16 @@ class="button-filters" :class="{'open': filtersOpen}" @click="filtersOpen = !filtersOpen" - >FILTRY + > + icon-filter FILTRY +
-
+ -
+ @@ -36,58 +38,55 @@ export default Vue.extend({ @import "../../styles/variables.scss"; @import "../../styles/responsive.scss"; +.slide-enter-active, +.slide-leave-active { + transition: all 0.3s ease; +} + +.slide-enter, +.slide-leave-to { + transform: translateX(10px); + opacity: 0; +} + .options { + position: relative; font-size: calc(0.7rem + 0.5vw); display: flex; - padding: 1rem; - - @include smallScreen() { - flex-direction: column; - padding: 1rem 0; - } } button { color: #e0e0e0; font-size: 1em; + display: flex; + align-items: center; + background: #333; border: none; outline: none; - - padding: 0.5em; + padding: 0.2em; cursor: pointer; - border-left: 3px solid white; transition: all 0.3s; - @include smallScreen { - border-left: none; - border-top: 2px solid white; + img { + width: 1.3em; + margin: 0.2em; } &.open { color: $accentCol; - border-radius: 1em 0 0 1em; border: none; - - @include smallScreen() { - border-radius: 1em 1em 0 0; - } - font-weight: bold; } - &:hover { - color: #ffffff; + &:hover, + &:focus { background: rgba(#e0e0e0, 0.1); } - - img { - width: 45px; - } } \ No newline at end of file diff --git a/src/components/utils/ListFilter.vue b/src/components/utils/ListFilter.vue index be500cc..f366d8b 100644 --- a/src/components/utils/ListFilter.vue +++ b/src/components/utils/ListFilter.vue @@ -1,19 +1,129 @@ @@ -105,11 +215,15 @@ export default Vue.extend({ } }), methods: { - ...mapActions(["addFilters", "removeFilters"]), + ...mapActions(["setFilter"]), handleChange(e: any) { - if (e.target.checked) { - this.removeFilters([e.target.name]); - } else this.addFilters([e.target.name]); + this.setFilter({ filterName: e.target.name, value: !e.target.checked }); + }, + handleInput(e: any) { + this.setFilter({ + filterName: e.target.name, + value: parseInt(e.target.value) + }); } } }); @@ -117,39 +231,52 @@ export default Vue.extend({ \ No newline at end of file diff --git a/src/store/backup.ts b/src/store/backup.ts new file mode 100644 index 0000000..164a5a0 --- /dev/null +++ b/src/store/backup.ts @@ -0,0 +1,134 @@ +import Vue from 'vue' +import Vuex from 'vuex' +import data from '@/data/stations.json'; + +Vue.use(Vuex) + +export default new Vuex.Store({ + state: { + stations: [], + filteredStations: [], + filters: [], + trainCount: 0 + }, + actions: { + fetchStations: async ({ commit }) => { + let onlineStations, statusList, onlineTrains + + try { + onlineStations = (await (await fetch('https://api.td2.info.pl:9640/?method=getStationsOnline')).json()).message + statusList = (await (await fetch('https://api.td2.info.pl:9640/?method=readFromSWDR&value=getDispatcherStatusList%3B1')).json()).message + onlineTrains = (await (await fetch('https://api.td2.info.pl:9640/?method=getTrainsOnline')).json()).message + } catch (error) { + throw Error(error.message); + } + + commit('setTrainCount', onlineTrains.filter((train) => train.isOnline && train.region === 'eu').length); + + const mappedStations = onlineStations + .filter((station) => station.region === 'eu') + .filter((station) => station.isOnline) + .map(( + { stationName = '', stationHash = '', maxUsers = 0, currentUsers = 0, spawnString = '', + dispatcherRate = 0, dispatcherName = '', dispatcherExp = 0, dispatcherId = 0 }) => { + + const status = statusList.find((s) => s[0] === stationHash && s[1] === 'eu') + let occupiedTo = "---" + let occupiedTimestamp = 0 + + if (!status) + occupiedTo = "NIEZALOGOWANY"; + else { + let occupiedCode = status[2]; + + occupiedTimestamp = status[3]; + occupiedTo = "NIEDOSTĘPNY"; + + if (occupiedCode === 0) { + if (occupiedTimestamp - Date.now() > 21000000) + occupiedTo = "BEZ LIMITU"; + else + occupiedTo = new Date(status[3]) + .toLocaleTimeString('en-US', + { hour12: false, hour: '2-digit', minute: '2-digit' }); + } + + if (occupiedCode === 1) + occupiedTo = "Z/W"; + + if (occupiedCode === 2 && occupiedTimestamp === 0) + occupiedTo = "KOŃCZY"; + + if (occupiedCode === 3) + occupiedTo = "BRAK MIEJSCA"; + } + + const trains = onlineTrains.filter((train) => + train.region === 'eu' && train.isOnline === 1 && train.station.stationName === stationName) + + const stationData = data.find((station) => station.stationName === stationName) || { stationName, stationURL: "" } + + return { + ...stationData, + stationHash, + maxUsers, + currentUsers, + spawnString: spawnString && spawnString.split(';').map(v => v.split(',')[6] ? v.split(',')[6] : v.split(',')[0]), + dispatcherName, + dispatcherRate, + dispatcherId, + dispatcherExp: dispatcherExp < 2 ? 'L' : dispatcherExp, + occupiedTo, + trains + } + }) + + commit('setStations', mappedStations); + commit('filterStations'); + }, + + addFilters({ commit }, filterId) { + commit('addFilters', filterId); + commit('filterStations'); + }, + + removeFilters({ commit }, filterId) { + commit('removeFilters', filterId); + commit('filterStations'); + } + }, + mutations: { + setStations: (state, stations) => state.stations = stations, + setTrainCount: (state, count) => state.trainCount = count, + + addFilters(state, filters) { + state.filters.push(...filters); + }, + removeFilters: (state, filters) => { + filters.forEach(filter => { + state.filters = state.filters.filter((id) => id !== filter); + }) + }, + + filterStations(state) { + state.filteredStations = state.stations.filter((station) => { + if (station.default && state.filters.includes("default")) return false; + if ((!station.default) && state.filters.includes("notDefault")) return false; + if ((station.nonPublic || !station.reqLevel) && (state.filters.includes("nonPublic"))) return false; + + if (state.filters.includes(station.controlType)) return false; + if (state.filters.includes(station.signalType)) return false; + + if (station.controlType && state.filters.filter((f) => station.controlType.includes(f)).length > 0) return false; + + return true; + }) + } + }, + getters: { + getStations: state => state.filteredStations, + getStationCount: state => state.stations.length, + getTrainCount: state => state.trainCount, + getFilters: state => state.filters, + } +}) \ No newline at end of file diff --git a/src/store/index.ts b/src/store/index.ts index 2d48e10..9b21490 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,134 +1,10 @@ import Vue from 'vue' import Vuex from 'vuex' -import data from '@/data/stations.json'; - +import Store from '@/store/modules/store' Vue.use(Vuex) - -export default new Vuex.Store({ - state: { - stations: [], - filteredStations: [], - filters: [], - trainCount: 0 - }, - actions: { - fetchStations: async ({ commit }) => { - let onlineStations, statusList: any, onlineTrains: any - - try { - onlineStations = (await (await fetch('https://api.td2.info.pl:9640/?method=getStationsOnline')).json()).message - statusList = (await (await fetch('https://api.td2.info.pl:9640/?method=readFromSWDR&value=getDispatcherStatusList%3B1')).json()).message - onlineTrains = (await (await fetch('https://api.td2.info.pl:9640/?method=getTrainsOnline')).json()).message - } catch (error) { - throw Error(error.message); - } - - commit('setTrainCount', onlineTrains.filter((train: any) => train.isOnline && train.region === 'eu').length); - - const mappedStations = onlineStations - .filter((station: any) => station.region === 'eu') - .filter((station: any) => station.isOnline) - .map(( - { stationName = '', stationHash = '', maxUsers = 0, currentUsers = 0, spawnString = '', - dispatcherRate = 0, dispatcherName = '', dispatcherExp = 0, dispatcherId = 0 }) => { - - const status = statusList.find((s: any) => s[0] === stationHash && s[1] === 'eu') - let occupiedTo: string = "---" - let occupiedTimestamp: number = 0 - - if (!status) - occupiedTo = "NIEZALOGOWANY"; - else { - let occupiedCode: number = status[2]; - - occupiedTimestamp = status[3]; - occupiedTo = "NIEDOSTĘPNY"; - - if (occupiedCode === 0) { - if (occupiedTimestamp - Date.now() > 21000000) - occupiedTo = "BEZ LIMITU"; - else - occupiedTo = new Date(status[3]) - .toLocaleTimeString('en-US', - { hour12: false, hour: '2-digit', minute: '2-digit' }); - } - - if (occupiedCode === 1) - occupiedTo = "Z/W"; - - if (occupiedCode === 2 && occupiedTimestamp === 0) - occupiedTo = "KOŃCZY"; - - if (occupiedCode === 3) - occupiedTo = "BRAK MIEJSCA"; - } - - const trains: {} = onlineTrains.filter((train: any) => - train.region === 'eu' && train.isOnline === 1 && train.station.stationName === stationName) - - const stationData: {} = data.find((station: any) => station.stationName === stationName) || { stationName, stationURL: "" } - - return { - ...stationData, - stationHash, - maxUsers, - currentUsers, - spawnString: spawnString && spawnString.split(';').map(v => v.split(',')[6] ? v.split(',')[6] : v.split(',')[0]), - dispatcherName, - dispatcherRate, - dispatcherId, - dispatcherExp: dispatcherExp < 2 ? 'L' : dispatcherExp, - occupiedTo, - trains - } - }) - - commit('setStations', mappedStations); - commit('filterStations'); - }, - - addFilters({ commit }, filterId) { - commit('addFilters', filterId); - commit('filterStations'); - }, - - removeFilters({ commit }, filterId) { - commit('removeFilters', filterId); - commit('filterStations'); +const store = new Vuex.Store({ + modules: { + Store } - }, - mutations: { - setStations: (state, stations) => state.stations = stations, - setTrainCount: (state, count) => state.trainCount = count, - - addFilters(state: any, filters: string[]) { - state.filters.push(...filters); - }, - removeFilters: (state: { filters: string[] }, filters: string[]) => { - filters.forEach(filter => { - state.filters = state.filters.filter((id: string) => id !== filter); - }) - }, - - filterStations(state: any) { - state.filteredStations = state.stations.filter((station: any) => { - if (station.default && state.filters.includes("default")) return false; - if ((!station.default) && state.filters.includes("notDefault")) return false; - if ((station.nonPublic || !station.reqLevel) && (state.filters.includes("nonPublic"))) return false; - - if (state.filters.includes(station.controlType)) return false; - if (state.filters.includes(station.signalType)) return false; - - if (station.controlType && state.filters.filter((f: string) => station.controlType.includes(f)).length > 0) return false; - - return true; - }) - } - }, - getters: { - getStations: state => state.filteredStations, - getStationCount: state => state.stations.length, - getTrainCount: state => state.trainCount, - getFilters: (state: any) => state.filters, - } }) +export default store \ No newline at end of file diff --git a/src/store/modules/store.ts b/src/store/modules/store.ts new file mode 100644 index 0000000..d5cc4c8 --- /dev/null +++ b/src/store/modules/store.ts @@ -0,0 +1,215 @@ +import { VuexModule, Module, Mutation, Action } from 'vuex-module-decorators'; +import data from '@/data/stations.json'; + +@Module +class Store extends VuexModule { + public trainCount: number = 0; + public stations: { + stationName: string; + stationHash: string; + maxUsers: number; + currentUsers: number; + spawnString: string; + dispatcherRate: number; + dispatcherName: string; + dispatcherExp: number; + dispatcherId: number; + stationLines: string; + stationProject: string; + reqLevel: string; + supportersOnly: string; + signalType: string; + controlType: string; + default: boolean; + nonPublic: boolean; + routes: { oneWay: { catenary: number; noCatenary: number; }, twoWay: { catenary: number; noCatenary: number; } }; + }[] = []; + + public filteredStations: {}[] = []; + + public filters = { + "default": false, + "notDefault": false, + "nonPublic": false, + "SPK": false, + "SCS": false, + "ręczne": false, + "mechaniczne": false, + "współczesna": false, + "kształtowa": false, + "historyczna": false, + "mieszana": false, + "levelFrom": 0, + "levelTo": 20, + "1track-ne": 0, + "2track-ne": 0, + "1track-e": 0, + "2track-e": 0, + } as any; + + + get getStationCount(): number { + return this.stations.length; + } + + get getTrainCount(): number { + return this.trainCount; + } + + get getStations() { + return this.filteredStations; + } + + get getFilters() { + return this.filters; + } + + @Action + public setFilter(payload: { filterName: string, value: number | boolean }) { + this.context.commit('mutateFilter', payload); + this.context.commit('filterStations'); + } + + @Action + public async fetchStations() { + let onlineStations: { + stationName: string, + stationHash: string, + maxUsers: number, + currentUsers: number, + spawnString: string, + dispatcherRate: number, + dispatcherName: string, + dispatcherExp: number, + dispatcherId: number, + region: string, + isOnline: number + }[]; + + let statusList: [string, string, number, number][]; + + let onlineTrains: { isOnline: number, region: string, station: { stationName: string } }[]; + + try { + onlineStations = (await (await fetch('https://api.td2.info.pl:9640/?method=getStationsOnline')).json()).message + statusList = (await (await fetch('https://api.td2.info.pl:9640/?method=readFromSWDR&value=getDispatcherStatusList%3B1')).json()).message + onlineTrains = (await (await fetch('https://api.td2.info.pl:9640/?method=getTrainsOnline')).json()).message + } catch (error) { + throw Error(error.message); + } + + this.context.commit('setTrainCount', onlineTrains.filter((train) => train.isOnline && train.region === 'eu').length); + + const mappedStations = onlineStations + .filter((station) => station.region === 'eu') + .filter((station) => station.isOnline) + .map(( + { stationName = '', stationHash = '', maxUsers = 0, currentUsers = 0, spawnString = '', + dispatcherRate = 0, dispatcherName = '', dispatcherExp = 0, dispatcherId = 0 }) => { + + const status = statusList.find((s) => s[0] === stationHash && s[1] === 'eu') + let occupiedTo = "---" + let occupiedTimestamp = 0 + + if (!status) + occupiedTo = "NIEZALOGOWANY"; + else { + let occupiedCode = status[2]; + + occupiedTimestamp = status[3]; + occupiedTo = "NIEDOSTĘPNY"; + + if (occupiedCode === 0) { + if (occupiedTimestamp - Date.now() > 21000000) + occupiedTo = "BEZ LIMITU"; + else + occupiedTo = new Date(status[3]) + .toLocaleTimeString('en-US', + { hour12: false, hour: '2-digit', minute: '2-digit' }); + } + + if (occupiedCode === 1) + occupiedTo = "Z/W"; + + if (occupiedCode === 2 && occupiedTimestamp === 0) + occupiedTo = "KOŃCZY"; + + if (occupiedCode === 3) + occupiedTo = "BRAK MIEJSCA"; + } + + const trains = onlineTrains.filter((train) => + train.region === 'eu' && train.isOnline && train.station.stationName === stationName) + + const stationData = data.find((station) => station.stationName === stationName) || { stationName, stationURL: "" } + + return { + ...stationData, + stationHash, + maxUsers, + currentUsers, + spawnString: spawnString && spawnString.split(';').map(v => v.split(',')[6] ? v.split(',')[6] : v.split(',')[0]), + dispatcherName, + dispatcherRate, + dispatcherId, + dispatcherExp: dispatcherExp < 2 ? 'L' : dispatcherExp, + occupiedTo, + trains + } + }) + + this.context.commit('setStations', mappedStations); + this.context.commit('filterStations'); + } + + @Mutation + public filterStations() { + this.filteredStations = this.stations.filter(station => { + + if ((station.nonPublic || !station.reqLevel) && this.filters['nonPublic']) return false; + if (!station.reqLevel) return true; + + if (station.default && this.filters['default']) return false; + if (!station.default && this.filters['notDefault']) return false; + + if (station.reqLevel < this.filters['level-from']) return false; + if (station.reqLevel > this.filters['level-to']) return false; + + if (station.routes.oneWay.catenary < this.filters['1track-e']) return false; + if (station.routes.oneWay.noCatenary < this.filters['1track-ne']) return false; + + if (station.routes.twoWay.catenary < this.filters['2track-e']) return false; + if (station.routes.twoWay.noCatenary < this.filters['2track-ne']) return false; + + + if (this.filters[station.controlType]) return false; + if (this.filters[station.signalType]) return false; + + + if (this.filters["SPK"] && station.controlType.includes("SPK")) return false; + if (this.filters["SCS"] && station.controlType.includes("SCS")) return false; + if (this.filters["mechaniczne"] && station.controlType.includes("mechaniczne")) return false; + if (this.filters["ręczne"] && station.controlType.includes("ręczne")) return false; + + return true; + }) + } + + @Mutation + public setStations(stations: []) { + this.stations = stations; + } + + @Mutation + public setTrainCount(count: number) { + this.trainCount = count; + } + + @Mutation + public mutateFilter(payload: { filterName: string, value: number | boolean }) { + this.filters[payload.filterName] = payload.value; + } + +} + +export default Store; \ No newline at end of file diff --git a/src/styles/responsive.scss b/src/styles/responsive.scss index ff106a7..8573682 100644 --- a/src/styles/responsive.scss +++ b/src/styles/responsive.scss @@ -1,5 +1,5 @@ @mixin smallScreen() { - @media only screen and (max-width: 850px) { + @media only screen and (max-width: 650px) { @content; } } diff --git a/src/styles/variables.scss b/src/styles/variables.scss index 5c7bea9..bec59b5 100644 --- a/src/styles/variables.scss +++ b/src/styles/variables.scss @@ -6,5 +6,5 @@ $bgCol: #525252; $errorCol: #ff1919; $warningCol: #ff975b; -$accentCol: #ffbb00; +$accentCol: #ffc62b; $accent2Col: #ff3d5d; diff --git a/src/views/Home.vue b/src/views/Home.vue index 64388fd..2024f2f 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -1,6 +1,5 @@ @@ -8,11 +7,11 @@