mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 13:28:11 +00:00
Aktualizacja
This commit is contained in:
+334
-342
@@ -1,342 +1,334 @@
|
||||
<template>
|
||||
<div class="app">
|
||||
<UpdateModal
|
||||
:currentVersion="VERSION"
|
||||
@toggleUpdateModal="toggleUpdateModal"
|
||||
v-if="updateModalVisible"
|
||||
/>
|
||||
|
||||
<div class="app_container">
|
||||
<header class="app_header">
|
||||
<div class="header_body">
|
||||
<span class="header_brand">
|
||||
<span>
|
||||
<span>Stacj</span>
|
||||
<img src="@/assets/trainlogo.png" alt="trainlogo" />
|
||||
<span>wnik</span>
|
||||
</span>
|
||||
|
||||
<span class="brand_lang">
|
||||
<span
|
||||
class="lang pl"
|
||||
@click="changeLang('en')"
|
||||
:class="{ current: currentLang == 'pl' }"
|
||||
v-if="currentLang == 'pl'"
|
||||
>
|
||||
<img :src="iconPL" alt="icon-pl" />
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="lang en"
|
||||
@click="changeLang('pl')"
|
||||
:class="{ current: currentLang == 'en' }"
|
||||
v-if="currentLang == 'en'"
|
||||
>
|
||||
<img :src="iconEN" alt="icon-en" />
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="header_info">
|
||||
<Clock />
|
||||
<div class="info_counter">
|
||||
<img src="@/assets/icon-dispatcher.svg" alt="icon dispatcher" />
|
||||
<span>{{ data.stationCount }}</span>
|
||||
<span>{{ data.trainCount }}</span>
|
||||
<img src="@/assets/icon-train.svg" alt="icon train" />
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<span class="header_links">
|
||||
<router-link class="route" active-class="route-active" to="/" exact
|
||||
>{{ $t("app.sceneries") }}
|
||||
</router-link>
|
||||
/
|
||||
<router-link class="route" active-class="route-active" to="/trains"
|
||||
>{{ $t("app.trains") }}
|
||||
</router-link>
|
||||
|
||||
<!-- <router-link
|
||||
class="route"
|
||||
active-class="route-active"
|
||||
to="/history"
|
||||
>{{ $t("app.journal") }}</router-link
|
||||
> -->
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="app_main">
|
||||
<transition name="view-anim" mode="out-in">
|
||||
<keep-alive>
|
||||
<router-view />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</main>
|
||||
|
||||
<footer class="app_footer">
|
||||
©
|
||||
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">
|
||||
Spythere
|
||||
</a>
|
||||
2021 | v{{ VERSION }} | [<a
|
||||
target="_blank"
|
||||
href="https://paypal.me/spythere"
|
||||
>{{ $t("app.support") }}!</a
|
||||
>]
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component } from "vue-property-decorator";
|
||||
import { Action, Getter } from "vuex-class";
|
||||
|
||||
import UpdateModal from "@/components/Global/UpdateModal.vue";
|
||||
import Clock from "@/components/App/Clock.vue";
|
||||
|
||||
import StorageManager from "@/scripts/storageManager";
|
||||
|
||||
import DataModule from "@/store/modules/DataModule";
|
||||
import { getModule } from "vuex-module-decorators";
|
||||
|
||||
@Component({
|
||||
components: { Clock, UpdateModal },
|
||||
})
|
||||
export default class App extends Vue {
|
||||
@Action("synchronizeData") synchronizeData;
|
||||
@Getter("getAllData") data;
|
||||
|
||||
private VERSION = "1.4.4";
|
||||
|
||||
hasReleaseNotes = false;
|
||||
updateModalVisible = false;
|
||||
|
||||
currentLang = "pl";
|
||||
|
||||
iconEN = require("@/assets/icon-en.jpg");
|
||||
iconPL = require("@/assets/icon-pl.svg");
|
||||
|
||||
dataStore: DataModule = getModule(DataModule);
|
||||
|
||||
get test() {
|
||||
return this.dataStore.getTest;
|
||||
}
|
||||
|
||||
mounted() {
|
||||
this.synchronizeData();
|
||||
|
||||
setTimeout(() => {
|
||||
this.dataStore.fetchTest();
|
||||
}, 3000);
|
||||
|
||||
if (StorageManager.getStringValue("lang")) {
|
||||
this.changeLang(StorageManager.getStringValue("lang"));
|
||||
} else if (window.navigator.language) {
|
||||
switch (window.navigator.language) {
|
||||
case "pl-PL":
|
||||
this.changeLang("pl");
|
||||
break;
|
||||
case "en-EN":
|
||||
default:
|
||||
this.changeLang("en");
|
||||
break;
|
||||
}
|
||||
|
||||
this.currentLang = this.$i18n.locale;
|
||||
}
|
||||
|
||||
if (StorageManager.getStringValue("version") != this.VERSION) {
|
||||
StorageManager.setStringValue("version", this.VERSION);
|
||||
|
||||
if (this.hasReleaseNotes)
|
||||
StorageManager.setBooleanValue("version_notes_read", false);
|
||||
}
|
||||
|
||||
this.updateModalVisible =
|
||||
this.hasReleaseNotes &&
|
||||
!StorageManager.getBooleanValue("version_notes_read");
|
||||
}
|
||||
|
||||
changeLang(lang: string) {
|
||||
this.$i18n.locale = lang;
|
||||
this.currentLang = lang;
|
||||
|
||||
StorageManager.setStringValue("lang", lang);
|
||||
console.log("Switched to: " + lang);
|
||||
}
|
||||
|
||||
toggleUpdateModal() {
|
||||
this.updateModalVisible = !this.updateModalVisible;
|
||||
StorageManager.setBooleanValue("version_notes_read", true);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "./styles/responsive.scss";
|
||||
@import "./styles/variables.scss";
|
||||
@import "./styles/global.scss";
|
||||
@import "./styles/scenery_status.scss";
|
||||
|
||||
:root {
|
||||
--clr-primary: #ffc014;
|
||||
--clr-secondary: #2f2f2f;
|
||||
|
||||
--clr-bg: #333;
|
||||
|
||||
--clr-accent: #1085b3;
|
||||
--clr-accent2: #ff3d5d;
|
||||
|
||||
--clr-skr: #ff5100;
|
||||
--clr-twr: #ffbb00;
|
||||
}
|
||||
|
||||
// VUE ROUTE CHANGE ANIMATION
|
||||
.view-anim {
|
||||
&-enter {
|
||||
opacity: 0.02;
|
||||
}
|
||||
|
||||
&-leave-to {
|
||||
opacity: 0.02;
|
||||
}
|
||||
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: all $animDuration $animType;
|
||||
min-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.route {
|
||||
margin: 0 0.2em;
|
||||
|
||||
&-active {
|
||||
color: $accentCol;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
// APP
|
||||
.app {
|
||||
background: $bgCol;
|
||||
color: white;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
font-size: 1rem;
|
||||
|
||||
@include smallScreen() {
|
||||
font-size: calc(0.45rem + 1vw);
|
||||
}
|
||||
}
|
||||
|
||||
// CONTAINER
|
||||
.app_container {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
|
||||
min-width: 0;
|
||||
min-height: 100vh;
|
||||
|
||||
header {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
footer {
|
||||
flex: 0 1 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
// HEADER
|
||||
.app_header {
|
||||
background: $primaryCol;
|
||||
padding: 0.15em;
|
||||
|
||||
border-radius: 0 0 1em 1em;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.header {
|
||||
&_brand {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
font-size: 4.25em;
|
||||
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
width: 0.8em;
|
||||
}
|
||||
|
||||
.brand_lang {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
|
||||
transform: translate(110%, -35%);
|
||||
|
||||
img {
|
||||
width: 0.6em;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&_info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
font-size: 1.25em;
|
||||
|
||||
margin: 0 0.3em;
|
||||
padding: 0.2em;
|
||||
}
|
||||
|
||||
&_links {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
border-radius: 0.7em;
|
||||
|
||||
font-size: 1.25em;
|
||||
padding: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
// COUNTER
|
||||
.info_counter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: $accentCol;
|
||||
|
||||
span {
|
||||
margin: 0 0.15em;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 1.35em;
|
||||
}
|
||||
}
|
||||
|
||||
// FOOTER
|
||||
footer.app_footer {
|
||||
max-width: 100%;
|
||||
padding: 0.5em;
|
||||
|
||||
z-index: 10;
|
||||
|
||||
background: #111;
|
||||
color: white;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<div class="app">
|
||||
<UpdateModal
|
||||
:currentVersion="VERSION"
|
||||
@toggleUpdateModal="toggleUpdateModal"
|
||||
v-if="updateModalVisible"
|
||||
/>
|
||||
|
||||
<div class="app_container">
|
||||
<header class="app_header">
|
||||
<div class="header_body">
|
||||
<span class="header_brand">
|
||||
<span>
|
||||
<span>Stacj</span>
|
||||
<img src="@/assets/trainlogo.png" alt="trainlogo" />
|
||||
<span>wnik</span>
|
||||
</span>
|
||||
|
||||
<span class="brand_lang">
|
||||
<span
|
||||
class="lang pl"
|
||||
@click="changeLang('en')"
|
||||
:class="{ current: currentLang == 'pl' }"
|
||||
v-if="currentLang == 'pl'"
|
||||
>
|
||||
<img :src="iconPL" alt="icon-pl" />
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="lang en"
|
||||
@click="changeLang('pl')"
|
||||
:class="{ current: currentLang == 'en' }"
|
||||
v-if="currentLang == 'en'"
|
||||
>
|
||||
<img :src="iconEN" alt="icon-en" />
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="header_info">
|
||||
<Clock />
|
||||
<div class="info_counter">
|
||||
<img src="@/assets/icon-dispatcher.svg" alt="icon dispatcher" />
|
||||
<span>{{ data.stationCount }}</span>
|
||||
<span>{{ data.trainCount }}</span>
|
||||
<img src="@/assets/icon-train.svg" alt="icon train" />
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<span class="header_links">
|
||||
<router-link class="route" active-class="route-active" to="/" exact
|
||||
>{{ $t("app.sceneries") }}
|
||||
</router-link>
|
||||
/
|
||||
<router-link class="route" active-class="route-active" to="/trains"
|
||||
>{{ $t("app.trains") }}
|
||||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="app_main">
|
||||
<transition name="view-anim" mode="out-in">
|
||||
<keep-alive>
|
||||
<router-view />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</main>
|
||||
|
||||
<footer class="app_footer">
|
||||
©
|
||||
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">
|
||||
Spythere
|
||||
</a>
|
||||
2021 | v{{ VERSION }} | [<a
|
||||
target="_blank"
|
||||
href="https://paypal.me/spythere"
|
||||
>{{ $t("app.support") }}!</a
|
||||
>]
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component } from "vue-property-decorator";
|
||||
import { Action, Getter } from "vuex-class";
|
||||
|
||||
import UpdateModal from "@/components/Global/UpdateModal.vue";
|
||||
import Clock from "@/components/App/Clock.vue";
|
||||
|
||||
import StorageManager from "@/scripts/storageManager";
|
||||
|
||||
@Component({
|
||||
components: { Clock, UpdateModal },
|
||||
})
|
||||
export default class App extends Vue {
|
||||
@Action("synchronizeData") synchronizeData;
|
||||
@Getter("getAllData") data;
|
||||
|
||||
private VERSION = "1.4.4";
|
||||
|
||||
hasReleaseNotes = false;
|
||||
updateModalVisible = false;
|
||||
|
||||
currentLang = "pl";
|
||||
|
||||
iconEN = require("@/assets/icon-en.jpg");
|
||||
iconPL = require("@/assets/icon-pl.svg");
|
||||
|
||||
toggleUpdateModal() {
|
||||
this.updateModalVisible = !this.updateModalVisible;
|
||||
StorageManager.setBooleanValue("version_notes_read", true);
|
||||
}
|
||||
|
||||
changeLang(lang: string) {
|
||||
this.$i18n.locale = lang;
|
||||
this.currentLang = lang;
|
||||
|
||||
StorageManager.setStringValue("lang", lang);
|
||||
}
|
||||
|
||||
loadLang() {
|
||||
const storageLang = StorageManager.getStringValue("lang");
|
||||
|
||||
if (storageLang) {
|
||||
this.changeLang(storageLang);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!window.navigator.language) {
|
||||
this.changeLang("pl");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (window.navigator.language) {
|
||||
case "pl-PL":
|
||||
this.changeLang("pl");
|
||||
break;
|
||||
case "en-EN":
|
||||
default:
|
||||
this.changeLang("en");
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
created() {
|
||||
this.loadLang();
|
||||
this.synchronizeData();
|
||||
}
|
||||
|
||||
mounted() {
|
||||
if (StorageManager.getStringValue("version") != this.VERSION) {
|
||||
StorageManager.setStringValue("version", this.VERSION);
|
||||
|
||||
if (this.hasReleaseNotes)
|
||||
StorageManager.setBooleanValue("version_notes_read", false);
|
||||
}
|
||||
|
||||
this.updateModalVisible =
|
||||
this.hasReleaseNotes &&
|
||||
!StorageManager.getBooleanValue("version_notes_read");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "./styles/responsive.scss";
|
||||
@import "./styles/variables.scss";
|
||||
@import "./styles/global.scss";
|
||||
@import "./styles/scenery_status.scss";
|
||||
|
||||
:root {
|
||||
--clr-primary: #ffc014;
|
||||
--clr-secondary: #2f2f2f;
|
||||
|
||||
--clr-bg: #333;
|
||||
|
||||
--clr-accent: #1085b3;
|
||||
--clr-accent2: #ff3d5d;
|
||||
|
||||
--clr-skr: #ff5100;
|
||||
--clr-twr: #ffbb00;
|
||||
}
|
||||
|
||||
// VUE ROUTE CHANGE ANIMATION
|
||||
.view-anim {
|
||||
&-enter {
|
||||
opacity: 0.02;
|
||||
}
|
||||
|
||||
&-leave-to {
|
||||
opacity: 0.02;
|
||||
}
|
||||
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: all $animDuration $animType;
|
||||
min-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.route {
|
||||
margin: 0 0.2em;
|
||||
|
||||
&-active {
|
||||
color: $accentCol;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
// APP
|
||||
.app {
|
||||
background: $bgCol;
|
||||
color: white;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
font-size: 1rem;
|
||||
|
||||
@include smallScreen() {
|
||||
font-size: calc(0.45rem + 1vw);
|
||||
}
|
||||
}
|
||||
|
||||
// CONTAINER
|
||||
.app_container {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
|
||||
min-width: 0;
|
||||
min-height: 100vh;
|
||||
|
||||
header {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
footer {
|
||||
flex: 0 1 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
// HEADER
|
||||
.app_header {
|
||||
background: $primaryCol;
|
||||
padding: 0.15em;
|
||||
|
||||
border-radius: 0 0 1em 1em;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.header {
|
||||
&_brand {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
font-size: 4.25em;
|
||||
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
width: 0.8em;
|
||||
}
|
||||
|
||||
.brand_lang {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
|
||||
transform: translate(110%, -35%);
|
||||
|
||||
img {
|
||||
width: 0.6em;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&_info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
font-size: 1.25em;
|
||||
|
||||
margin: 0 0.3em;
|
||||
padding: 0.2em;
|
||||
}
|
||||
|
||||
&_links {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
border-radius: 0.7em;
|
||||
|
||||
font-size: 1.25em;
|
||||
padding: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
// COUNTER
|
||||
.info_counter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: $accentCol;
|
||||
|
||||
span {
|
||||
margin: 0 0.15em;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 1.35em;
|
||||
}
|
||||
}
|
||||
|
||||
// FOOTER
|
||||
footer.app_footer {
|
||||
max-width: 100%;
|
||||
padding: 0.5em;
|
||||
|
||||
z-index: 10;
|
||||
|
||||
background: #111;
|
||||
color: white;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,97 +1,97 @@
|
||||
<template>
|
||||
<div class="modal">
|
||||
<div class="header">
|
||||
<span>Stacj</span>
|
||||
<img src="@/assets/trainlogo.png" alt="trainlogo" />
|
||||
<span>wnik</span>
|
||||
<sup style="font-size: 0.5em; margin-left: 10px;" class="title">1.4</sup>
|
||||
</div>
|
||||
|
||||
<div class="title">Dziennik Aktywności Scenerii dostępny w wersji beta!</div>
|
||||
|
||||
<div class="content">
|
||||
Do użytku został oddany Dziennik Aktywności Scenerii, który pozwala na dostęp do informacji kto i kiedy dyżurował na danej stacji.
|
||||
Aby przejść do zakładki z dziennikiem wystarczy wybrać opcję "DZIENNIK" w menu na górze strony. Funkcjonalność ta jest nadal w trakcie prac,
|
||||
więc informacje, które pokazuje, mogą być niepoprawne, a dane kasowane w ramach dalszych testów.
|
||||
<div style="text-align: center; font-weight: bold; margin: 0.5em 0;">Miłego korzystania!</div>
|
||||
</div>
|
||||
|
||||
<button class="button" @click="toggleUpdateModal">PRZYJĄŁEM!</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from "vue-property-decorator";
|
||||
|
||||
@Component
|
||||
export default class UpdateModal extends Vue {
|
||||
@Prop() currentVersion!: string;
|
||||
|
||||
STORAGE_ID = "modal_update";
|
||||
|
||||
toggleUpdateModal(type: string) {
|
||||
this.$emit("toggleUpdateModal");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../../styles/responsive";
|
||||
|
||||
.modal {
|
||||
z-index: 100;
|
||||
|
||||
padding: 1em;
|
||||
|
||||
border-radius: 1em;
|
||||
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
|
||||
width: 65%;
|
||||
max-width: 950px;
|
||||
|
||||
max-height: 95vh;
|
||||
overflow: auto;
|
||||
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
background: rgba(black, 0.85);
|
||||
color: white;
|
||||
|
||||
text-align: center;
|
||||
|
||||
@include smallScreen() {
|
||||
font-size: 0.8em;
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
font-size: 4.5em;
|
||||
|
||||
img {
|
||||
width: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.content {
|
||||
font-size: 1.4em;
|
||||
|
||||
text-align: justify;
|
||||
|
||||
ul {
|
||||
list-style: square inside;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
font-size: 1.25em;
|
||||
margin: 0 auto;
|
||||
}
|
||||
<template>
|
||||
<div class="modal">
|
||||
<div class="header">
|
||||
<span>Stacj</span>
|
||||
<img src="@/assets/trainlogo.png" alt="trainlogo" />
|
||||
<span>wnik</span>
|
||||
<sup style="font-size: 0.5em; margin-left: 10px;" class="title">1.4</sup>
|
||||
</div>
|
||||
|
||||
<div class="title">Dziennik Aktywności Scenerii dostępny w wersji beta!</div>
|
||||
|
||||
<div class="content">
|
||||
Do użytku został oddany Dziennik Aktywności Scenerii, który pozwala na dostęp do informacji kto i kiedy dyżurował na danej stacji.
|
||||
Aby przejść do zakładki z dziennikiem wystarczy wybrać opcję "DZIENNIK" w menu na górze strony. Funkcjonalność ta jest nadal w trakcie prac,
|
||||
więc informacje, które pokazuje, mogą być niepoprawne, a dane kasowane w ramach dalszych testów.
|
||||
<div style="text-align: center; font-weight: bold; margin: 0.5em 0;">Miłego korzystania!</div>
|
||||
</div>
|
||||
|
||||
<button class="button" @click="toggleUpdateModal">PRZYJĄŁEM!</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from "vue-property-decorator";
|
||||
|
||||
@Component
|
||||
export default class UpdateModal extends Vue {
|
||||
@Prop() currentVersion!: string;
|
||||
|
||||
STORAGE_ID = "modal_update";
|
||||
|
||||
toggleUpdateModal(type: string) {
|
||||
this.$emit("toggleUpdateModal");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../../styles/responsive";
|
||||
|
||||
.modal {
|
||||
z-index: 100;
|
||||
|
||||
padding: 1em;
|
||||
|
||||
border-radius: 1em;
|
||||
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
|
||||
width: 65%;
|
||||
max-width: 950px;
|
||||
|
||||
max-height: 95vh;
|
||||
overflow: auto;
|
||||
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
background: rgba(black, 0.85);
|
||||
color: white;
|
||||
|
||||
text-align: center;
|
||||
|
||||
@include smallScreen() {
|
||||
font-size: 0.8em;
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
font-size: 4.5em;
|
||||
|
||||
img {
|
||||
width: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.content {
|
||||
font-size: 1.4em;
|
||||
|
||||
text-align: justify;
|
||||
|
||||
ul {
|
||||
list-style: square inside;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
font-size: 1.25em;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
@@ -1,287 +1,287 @@
|
||||
<template>
|
||||
<div class="train-options">
|
||||
<div class="options_wrapper">
|
||||
<div class="train-sorter option">
|
||||
<div class="train-sorter_wrapper">
|
||||
<div class="train-sorter_selected" @click="toggleSorterOptions">
|
||||
<span>{{ currentSorterOption }}</span>
|
||||
<img :src="descIcon" alt="icon-select" />
|
||||
</div>
|
||||
|
||||
<div class="train-sorter_options">
|
||||
<ul :class="{ open: sorterOptionsOpen }">
|
||||
<li
|
||||
v-for="(option, i) in sorterOptions"
|
||||
:key="i"
|
||||
@click="() => chooseOption(option)"
|
||||
>
|
||||
<input type="radio" name="sort" :id="option.id" />
|
||||
<label :for="option.id">
|
||||
{{ $t(`trains.option-${option.id}`) }}
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="train-search_train option">
|
||||
<div class="search-box">
|
||||
<input
|
||||
class="search-input"
|
||||
:placeholder="$t('trains.search-no')"
|
||||
v-model="searchedTrain"
|
||||
/>
|
||||
<img
|
||||
class="search-exit"
|
||||
:src="exitIcon"
|
||||
alt="exit-icon"
|
||||
@click="() => (searchedTrain = '')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="train-search_driver option">
|
||||
<div class="search-box">
|
||||
<input
|
||||
class="search-input"
|
||||
:placeholder="$t('trains.search-driver')"
|
||||
v-model="searchedDriver"
|
||||
/>
|
||||
<img
|
||||
class="search-exit"
|
||||
:src="exitIcon"
|
||||
alt="exit-icon"
|
||||
@click="() => (searchedDriver = '')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Watch, Prop } from "vue-property-decorator";
|
||||
|
||||
@Component
|
||||
export default class TrainOptions extends Vue {
|
||||
ascIcon = require("@/assets/icon-arrow-asc.svg");
|
||||
descIcon = require("@/assets/icon-arrow-desc.svg");
|
||||
exitIcon = require("@/assets/icon-exit.svg");
|
||||
|
||||
clickEventListener!: EventListener;
|
||||
|
||||
sorterOptionsOpen = false;
|
||||
currentSorterOption = this.$t("trains.option-distance");
|
||||
|
||||
searchedTrain = "";
|
||||
searchedDriver = "";
|
||||
|
||||
// Passed as component parameters
|
||||
@Prop() readonly queryTrain!: string;
|
||||
@Prop() readonly focusedTrain!: string;
|
||||
|
||||
mounted() {
|
||||
if (this.queryTrain) {
|
||||
this.searchedTrain = this.queryTrain;
|
||||
this.searchedDriver = "";
|
||||
}
|
||||
}
|
||||
|
||||
sorterOptions: { id: string; content: string }[] = [
|
||||
{
|
||||
id: "mass",
|
||||
content: "masa",
|
||||
},
|
||||
{
|
||||
id: "speed",
|
||||
content: "prędkość",
|
||||
},
|
||||
{
|
||||
id: "length",
|
||||
content: "długość",
|
||||
},
|
||||
{
|
||||
id: "distance",
|
||||
content: "kilometraż",
|
||||
},
|
||||
{
|
||||
id: "timetable",
|
||||
content: "numer pociągu",
|
||||
},
|
||||
];
|
||||
|
||||
toggleSorterOptions() {
|
||||
this.sorterOptionsOpen = !this.sorterOptionsOpen;
|
||||
}
|
||||
|
||||
closeSorterOptions() {
|
||||
this.sorterOptionsOpen = false;
|
||||
}
|
||||
|
||||
chooseOption(option: { id: string; content: string }) {
|
||||
this.$emit("changeSorter", { id: option.id, dir: -1 });
|
||||
|
||||
this.currentSorterOption = this.$t(`trains.option-${option.id}`);
|
||||
|
||||
this.closeSorterOptions();
|
||||
}
|
||||
|
||||
@Watch("searchedTrain")
|
||||
onSearchedTrainChanged(train: string) {
|
||||
this.$emit("changeSearchedTrain", train);
|
||||
}
|
||||
|
||||
@Watch("searchedDriver")
|
||||
onSearchedDriverChanged(driver: string) {
|
||||
this.$emit("changeSearchedDriver", driver);
|
||||
}
|
||||
|
||||
@Watch("queryTrain")
|
||||
onQueryTrainChanged(train: string) {
|
||||
if (train && train != "") {
|
||||
this.searchedTrain = train;
|
||||
this.searchedDriver = "";
|
||||
}
|
||||
}
|
||||
|
||||
@Watch("focusedTrain")
|
||||
onFocusedTrainChanged(train: string) {
|
||||
this.searchedTrain = train;
|
||||
this.searchedDriver = "";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../../styles/responsive";
|
||||
|
||||
.train-options {
|
||||
@include smallScreen() {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.options_wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.option {
|
||||
background: #333;
|
||||
border-radius: 0.5em 0.5em 0 0;
|
||||
|
||||
margin-right: 0.35em;
|
||||
|
||||
@include smallScreen() {
|
||||
width: 100%;
|
||||
margin: 0.35em 0;
|
||||
}
|
||||
}
|
||||
|
||||
.train-sorter {
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
|
||||
&_options {
|
||||
position: relative;
|
||||
|
||||
ul {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
|
||||
transition: all 150ms ease-in;
|
||||
|
||||
z-index: 9;
|
||||
overflow: hidden;
|
||||
|
||||
max-height: 0;
|
||||
|
||||
&.open {
|
||||
max-height: 250px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
transition: background 150ms ease-in;
|
||||
|
||||
background-color: rgba(#222, 0.95);
|
||||
|
||||
&:last-child {
|
||||
border-radius: 0 0 0.5em 0.5em;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(#868686, 0.85);
|
||||
}
|
||||
|
||||
input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
label {
|
||||
padding: 0.5em 1em;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&_selected {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
padding: 0.5em 0.5em;
|
||||
min-width: 200px;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
span {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search {
|
||||
&-box {
|
||||
position: relative;
|
||||
|
||||
background: #333;
|
||||
border-radius: 0.5em;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
&-input {
|
||||
border: none;
|
||||
|
||||
padding: 0.5em 0.5em;
|
||||
|
||||
margin: 0;
|
||||
|
||||
min-width: 85%;
|
||||
}
|
||||
|
||||
&-exit {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
|
||||
top: 50%;
|
||||
right: 10px;
|
||||
transform: translateY(-50%);
|
||||
|
||||
width: 1em;
|
||||
}
|
||||
}
|
||||
<template>
|
||||
<div class="train-options">
|
||||
<div class="options_wrapper">
|
||||
<div class="train-sorter option">
|
||||
<div class="train-sorter_wrapper">
|
||||
<div class="train-sorter_selected" @click="toggleSorterOptions">
|
||||
<span>{{ currentSorterOption }}</span>
|
||||
<img :src="descIcon" alt="icon-select" />
|
||||
</div>
|
||||
|
||||
<div class="train-sorter_options">
|
||||
<ul :class="{ open: sorterOptionsOpen }">
|
||||
<li
|
||||
v-for="(option, i) in sorterOptions"
|
||||
:key="i"
|
||||
@click="() => chooseOption(option)"
|
||||
>
|
||||
<input type="radio" name="sort" :id="option.id" />
|
||||
<label :for="option.id">
|
||||
{{ $t(`trains.option-${option.id}`) }}
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="train-search_train option">
|
||||
<div class="search-box">
|
||||
<input
|
||||
class="search-input"
|
||||
:placeholder="$t('trains.search-no')"
|
||||
v-model="searchedTrain"
|
||||
/>
|
||||
<img
|
||||
class="search-exit"
|
||||
:src="exitIcon"
|
||||
alt="exit-icon"
|
||||
@click="() => (searchedTrain = '')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="train-search_driver option">
|
||||
<div class="search-box">
|
||||
<input
|
||||
class="search-input"
|
||||
:placeholder="$t('trains.search-driver')"
|
||||
v-model="searchedDriver"
|
||||
/>
|
||||
<img
|
||||
class="search-exit"
|
||||
:src="exitIcon"
|
||||
alt="exit-icon"
|
||||
@click="() => (searchedDriver = '')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Watch, Prop } from "vue-property-decorator";
|
||||
|
||||
@Component
|
||||
export default class TrainOptions extends Vue {
|
||||
ascIcon = require("@/assets/icon-arrow-asc.svg");
|
||||
descIcon = require("@/assets/icon-arrow-desc.svg");
|
||||
exitIcon = require("@/assets/icon-exit.svg");
|
||||
|
||||
clickEventListener!: EventListener;
|
||||
|
||||
sorterOptionsOpen = false;
|
||||
currentSorterOption = this.$t("trains.option-distance");
|
||||
|
||||
searchedTrain = "";
|
||||
searchedDriver = "";
|
||||
|
||||
// Passed as component parameters
|
||||
@Prop() readonly queryTrain!: string;
|
||||
@Prop() readonly focusedTrain!: string;
|
||||
|
||||
mounted() {
|
||||
if (this.queryTrain) {
|
||||
this.searchedTrain = this.queryTrain;
|
||||
this.searchedDriver = "";
|
||||
}
|
||||
}
|
||||
|
||||
sorterOptions: { id: string; content: string }[] = [
|
||||
{
|
||||
id: "mass",
|
||||
content: "masa",
|
||||
},
|
||||
{
|
||||
id: "speed",
|
||||
content: "prędkość",
|
||||
},
|
||||
{
|
||||
id: "length",
|
||||
content: "długość",
|
||||
},
|
||||
{
|
||||
id: "distance",
|
||||
content: "kilometraż",
|
||||
},
|
||||
{
|
||||
id: "timetable",
|
||||
content: "numer pociągu",
|
||||
},
|
||||
];
|
||||
|
||||
toggleSorterOptions() {
|
||||
this.sorterOptionsOpen = !this.sorterOptionsOpen;
|
||||
}
|
||||
|
||||
closeSorterOptions() {
|
||||
this.sorterOptionsOpen = false;
|
||||
}
|
||||
|
||||
chooseOption(option: { id: string; content: string }) {
|
||||
this.$emit("changeSorter", { id: option.id, dir: -1 });
|
||||
|
||||
this.currentSorterOption = this.$t(`trains.option-${option.id}`);
|
||||
|
||||
this.closeSorterOptions();
|
||||
}
|
||||
|
||||
@Watch("searchedTrain")
|
||||
onSearchedTrainChanged(train: string) {
|
||||
this.$emit("changeSearchedTrain", train);
|
||||
}
|
||||
|
||||
@Watch("searchedDriver")
|
||||
onSearchedDriverChanged(driver: string) {
|
||||
this.$emit("changeSearchedDriver", driver);
|
||||
}
|
||||
|
||||
@Watch("queryTrain")
|
||||
onQueryTrainChanged(train: string) {
|
||||
if (train && train != "") {
|
||||
this.searchedTrain = train;
|
||||
this.searchedDriver = "";
|
||||
}
|
||||
}
|
||||
|
||||
@Watch("focusedTrain")
|
||||
onFocusedTrainChanged(train: string) {
|
||||
this.searchedTrain = train;
|
||||
this.searchedDriver = "";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../../styles/responsive";
|
||||
|
||||
.train-options {
|
||||
@include smallScreen() {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.options_wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.option {
|
||||
background: #333;
|
||||
border-radius: 0.5em 0.5em 0 0;
|
||||
|
||||
margin-right: 0.35em;
|
||||
|
||||
@include smallScreen() {
|
||||
width: 100%;
|
||||
margin: 0.35em 0;
|
||||
}
|
||||
}
|
||||
|
||||
.train-sorter {
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
|
||||
&_options {
|
||||
position: relative;
|
||||
|
||||
ul {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
|
||||
transition: all 150ms ease-in;
|
||||
|
||||
z-index: 9;
|
||||
overflow: hidden;
|
||||
|
||||
max-height: 0;
|
||||
|
||||
&.open {
|
||||
max-height: 250px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
transition: background 150ms ease-in;
|
||||
|
||||
background-color: rgba(#222, 0.95);
|
||||
|
||||
&:last-child {
|
||||
border-radius: 0 0 0.5em 0.5em;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(#868686, 0.85);
|
||||
}
|
||||
|
||||
input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
label {
|
||||
padding: 0.5em 1em;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&_selected {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
padding: 0.5em 0.5em;
|
||||
min-width: 200px;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
span {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search {
|
||||
&-box {
|
||||
position: relative;
|
||||
|
||||
background: #333;
|
||||
border-radius: 0.5em;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
&-input {
|
||||
border: none;
|
||||
|
||||
padding: 0.5em 0.5em;
|
||||
|
||||
margin: 0;
|
||||
|
||||
min-width: 85%;
|
||||
}
|
||||
|
||||
&-exit {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
|
||||
top: 50%;
|
||||
right: 10px;
|
||||
transform: translateY(-50%);
|
||||
|
||||
width: 1em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+2147
-2147
File diff suppressed because it is too large
Load Diff
+134
-134
@@ -1,134 +1,134 @@
|
||||
{
|
||||
"app": {
|
||||
"sceneries": "SCENERIES",
|
||||
"trains": "TRAINS",
|
||||
"journal": "JOURNAL",
|
||||
"loading": "Loading data...",
|
||||
"support": "Support the project"
|
||||
},
|
||||
"desc": {
|
||||
"control-type": "Control type: ",
|
||||
"signals-type": "Signals type: ",
|
||||
"SBL": "This scenery has automatic line blockade system on following routes: ",
|
||||
"default": "This scenery is available by default",
|
||||
"non-public": "This scenery is not public",
|
||||
"unavailable": "This scenery is unavailable",
|
||||
"real": "This scenery is real"
|
||||
},
|
||||
"signals": {
|
||||
"współczesna": "modern",
|
||||
"mieszana": "mixed",
|
||||
"kształtowa": "mechanical",
|
||||
"historyczna": "historyczna"
|
||||
},
|
||||
"controls": {
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"SCS-SPK": "SCS/SPK",
|
||||
"ręczne": "manual",
|
||||
"ręczne+SPK": "manual + SPK",
|
||||
"ręczne+SCS": "manual + SCS",
|
||||
"mechaniczne": "levers (mechanical)",
|
||||
"mechaniczne+SPK": "levers + SPK",
|
||||
"mechaniczne+SCS": "levers + SCS"
|
||||
},
|
||||
"status": {
|
||||
"online": "UNTIL ",
|
||||
"free": "FREE",
|
||||
"ending": "ENDS SOON",
|
||||
"not-signed": "NOT SIGNED IN",
|
||||
"no-limit": "NO LIMIT",
|
||||
"unavailable": "UNAVAILABLE",
|
||||
"brb": "AFK",
|
||||
"no-space": "NO SPACE"
|
||||
},
|
||||
"options": {
|
||||
"filters": "FILTERS",
|
||||
"donate": "DONATE"
|
||||
},
|
||||
"filters": {
|
||||
"title": "STATION FILTER",
|
||||
"default": "DEFAULT",
|
||||
"not-default": "OTHER",
|
||||
"real": "REAL",
|
||||
"fictional": "FICTIONAL",
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"manual": "MANUAL",
|
||||
"mechanical": "MECHANICAL",
|
||||
"modern": "MODERN",
|
||||
"semaphores": "SEMAPHORES",
|
||||
"mixed": "MIXED",
|
||||
"historical": "HISTORICAL",
|
||||
"free": "FREE",
|
||||
"occupied": "OCCUPIED",
|
||||
"sliders": {
|
||||
"min-lvl": "MINIMUM REQUIRED DISPATCHER LEVEL",
|
||||
"routes-1t-cat": "MINIMUM CATENARY SINGLE TRACK ROUTES",
|
||||
"routes-1t-other": "MINIMUM OTHER SINGLE TRACK ROUTES",
|
||||
"routes-2t-cat": "MINIMUM CATENARY DOUBLE TRACK ROUTES",
|
||||
"routes-2t-other": "MINIMUM OTHER DOUBLE TRACK ROUTES"
|
||||
},
|
||||
"save": "SAVE FILTERS",
|
||||
"reset": "RESET FILTERS",
|
||||
"close": "CLOSE FILTERS"
|
||||
},
|
||||
"sceneries": {
|
||||
"station": "Station",
|
||||
"min-lvl": "Min. dispatcher <br> level",
|
||||
"status": "Status",
|
||||
"dispatcher": "Dispatcher",
|
||||
"dispatcher-lvl": "Dispatcher <br> level",
|
||||
"routes": "Routes <br> double | single",
|
||||
"general": "General info",
|
||||
"users": "Drivers online",
|
||||
"spawns": "Spawns online",
|
||||
"timetables": "Active timetables",
|
||||
"no-stations": "No stations to show here!"
|
||||
},
|
||||
"trains": {
|
||||
"no-trains": "Oops! No trains online!",
|
||||
"stats": "TRAFFIC STATISTICS",
|
||||
"stats-speed": "TRAINS SPEED (MIN | AVG | MAX) [km/h]",
|
||||
"stats-length": "TIMETABLES LENGTH (MIN | AVG | MAX) [km]",
|
||||
"stats-categories": "TIMETABLE CATEGORIES",
|
||||
"stats-special-twr": "HIGH RISK",
|
||||
"stats-special-skr": "EXCEEDED STRUCT. GAUGE",
|
||||
"stats-locos": "MOST COMMON UNITS",
|
||||
"option-mass": "mass",
|
||||
"option-speed": "speed",
|
||||
"option-length": "length",
|
||||
"option-distance": "distance",
|
||||
"option-timetable": "train no.",
|
||||
"search-no": "Search for train no...",
|
||||
"search-driver": "Search for driver...",
|
||||
"detailed-timetable": "Detailed timetable for train no. ",
|
||||
"via-title": "Via: "
|
||||
},
|
||||
"journal": {
|
||||
"title": "SCENERY ACTIVITY JOURNAL",
|
||||
"subtitle": "Shows all recent dispatchers on a selected scenery",
|
||||
"disclaimer": "<b>This functionality is unfinished!</b> <br> Information shown here could be false or incorrect!",
|
||||
"select": "Select a scenery"
|
||||
},
|
||||
"scenery": {
|
||||
"users": "PLAYERS ONLINE",
|
||||
"spawns": "OPEN SPAWNS",
|
||||
"timetables": "ACTIVE TIMETABLES",
|
||||
"no-timetables": "No active timetables!",
|
||||
"no-users": "NO ACTIVE PLAYERS",
|
||||
"no-spawns": "NO OPEN SPAWNS",
|
||||
"no-scenery": "Oops! This scenery doesn't exist or is offline!",
|
||||
"return-btn": "Return to main site"
|
||||
},
|
||||
"timetables": {
|
||||
"online": "At station",
|
||||
"departed": "Dispatched",
|
||||
"departed-away": "Departed",
|
||||
"arriving": "En route",
|
||||
"stopped": "Stopped",
|
||||
"terminated": "Terminated",
|
||||
"begins": "BEGINS HERE",
|
||||
"terminates": "TERMINATES <br /> HERE"
|
||||
}
|
||||
}
|
||||
{
|
||||
"app": {
|
||||
"sceneries": "SCENERIES",
|
||||
"trains": "TRAINS",
|
||||
"journal": "JOURNAL",
|
||||
"loading": "Loading data...",
|
||||
"support": "Support the project"
|
||||
},
|
||||
"desc": {
|
||||
"control-type": "Control type: ",
|
||||
"signals-type": "Signals type: ",
|
||||
"SBL": "This scenery has automatic line blockade system on following routes: ",
|
||||
"default": "This scenery is available by default",
|
||||
"non-public": "This scenery is not public",
|
||||
"unavailable": "This scenery is unavailable",
|
||||
"real": "This scenery is real"
|
||||
},
|
||||
"signals": {
|
||||
"współczesna": "modern",
|
||||
"mieszana": "mixed",
|
||||
"kształtowa": "mechanical",
|
||||
"historyczna": "historyczna"
|
||||
},
|
||||
"controls": {
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"SCS-SPK": "SCS/SPK",
|
||||
"ręczne": "manual",
|
||||
"ręczne+SPK": "manual + SPK",
|
||||
"ręczne+SCS": "manual + SCS",
|
||||
"mechaniczne": "levers (mechanical)",
|
||||
"mechaniczne+SPK": "levers + SPK",
|
||||
"mechaniczne+SCS": "levers + SCS"
|
||||
},
|
||||
"status": {
|
||||
"online": "UNTIL ",
|
||||
"free": "FREE",
|
||||
"ending": "ENDS SOON",
|
||||
"not-signed": "NOT SIGNED IN",
|
||||
"no-limit": "NO LIMIT",
|
||||
"unavailable": "UNAVAILABLE",
|
||||
"brb": "AFK",
|
||||
"no-space": "NO SPACE"
|
||||
},
|
||||
"options": {
|
||||
"filters": "FILTERS",
|
||||
"donate": "DONATE"
|
||||
},
|
||||
"filters": {
|
||||
"title": "STATION FILTER",
|
||||
"default": "DEFAULT",
|
||||
"not-default": "OTHER",
|
||||
"real": "REAL",
|
||||
"fictional": "FICTIONAL",
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"manual": "MANUAL",
|
||||
"mechanical": "MECHANICAL",
|
||||
"modern": "MODERN",
|
||||
"semaphores": "SEMAPHORES",
|
||||
"mixed": "MIXED",
|
||||
"historical": "HISTORICAL",
|
||||
"free": "FREE",
|
||||
"occupied": "OCCUPIED",
|
||||
"sliders": {
|
||||
"min-lvl": "MINIMUM REQUIRED DISPATCHER LEVEL",
|
||||
"routes-1t-cat": "MINIMUM CATENARY SINGLE TRACK ROUTES",
|
||||
"routes-1t-other": "MINIMUM OTHER SINGLE TRACK ROUTES",
|
||||
"routes-2t-cat": "MINIMUM CATENARY DOUBLE TRACK ROUTES",
|
||||
"routes-2t-other": "MINIMUM OTHER DOUBLE TRACK ROUTES"
|
||||
},
|
||||
"save": "SAVE FILTERS",
|
||||
"reset": "RESET FILTERS",
|
||||
"close": "CLOSE FILTERS"
|
||||
},
|
||||
"sceneries": {
|
||||
"station": "Station",
|
||||
"min-lvl": "Min. dispatcher <br> level",
|
||||
"status": "Status",
|
||||
"dispatcher": "Dispatcher",
|
||||
"dispatcher-lvl": "Dispatcher <br> level",
|
||||
"routes": "Routes <br> double | single",
|
||||
"general": "General info",
|
||||
"users": "Drivers online",
|
||||
"spawns": "Spawns online",
|
||||
"timetables": "Active timetables",
|
||||
"no-stations": "No stations to show here!"
|
||||
},
|
||||
"trains": {
|
||||
"no-trains": "Oops! No trains online!",
|
||||
"stats": "TRAFFIC STATISTICS",
|
||||
"stats-speed": "TRAINS SPEED (MIN | AVG | MAX) [km/h]",
|
||||
"stats-length": "TIMETABLES LENGTH (MIN | AVG | MAX) [km]",
|
||||
"stats-categories": "TIMETABLE CATEGORIES",
|
||||
"stats-special-twr": "HIGH RISK",
|
||||
"stats-special-skr": "EXCEEDED STRUCT. GAUGE",
|
||||
"stats-locos": "MOST COMMON UNITS",
|
||||
"option-mass": "mass",
|
||||
"option-speed": "speed",
|
||||
"option-length": "length",
|
||||
"option-distance": "distance",
|
||||
"option-timetable": "train no.",
|
||||
"search-no": "Search for train no...",
|
||||
"search-driver": "Search for driver...",
|
||||
"detailed-timetable": "Detailed timetable for train no. ",
|
||||
"via-title": "Via: "
|
||||
},
|
||||
"journal": {
|
||||
"title": "SCENERY ACTIVITY JOURNAL",
|
||||
"subtitle": "Shows all recent dispatchers on a selected scenery",
|
||||
"disclaimer": "<b>This functionality is unfinished!</b> <br> Information shown here could be false or incorrect!",
|
||||
"select": "Select a scenery"
|
||||
},
|
||||
"scenery": {
|
||||
"users": "PLAYERS ONLINE",
|
||||
"spawns": "OPEN SPAWNS",
|
||||
"timetables": "ACTIVE TIMETABLES",
|
||||
"no-timetables": "No active timetables!",
|
||||
"no-users": "NO ACTIVE PLAYERS",
|
||||
"no-spawns": "NO OPEN SPAWNS",
|
||||
"no-scenery": "Oops! This scenery doesn't exist or is offline!",
|
||||
"return-btn": "Return to main site"
|
||||
},
|
||||
"timetables": {
|
||||
"online": "At station",
|
||||
"departed": "Dispatched",
|
||||
"departed-away": "Departed",
|
||||
"arriving": "En route",
|
||||
"stopped": "Stopped",
|
||||
"terminated": "Terminated",
|
||||
"begins": "BEGINS HERE",
|
||||
"terminates": "TERMINATES <br /> HERE"
|
||||
}
|
||||
}
|
||||
|
||||
+134
-134
@@ -1,134 +1,134 @@
|
||||
{
|
||||
"app": {
|
||||
"sceneries": "SCENERIE",
|
||||
"trains": "POCIĄGI",
|
||||
"journal": "DZIENNIK",
|
||||
"loading": "Pobieranie danych...",
|
||||
"support": "Wspomóż projekt"
|
||||
},
|
||||
"desc": {
|
||||
"control-type": "Sterowanie: ",
|
||||
"signals-type": "Sygnalizacja: ",
|
||||
"SBL": "Sceneria posiada SBL na szlakach: ",
|
||||
"default": "Sceneria dostępna domyślnie w paczce z grą",
|
||||
"non-public": "Sceneria niepubliczna",
|
||||
"unavailable": "Sceneria niedostępna",
|
||||
"real": "Sceneria realna"
|
||||
},
|
||||
"signals": {
|
||||
"współczesna": "współczesna",
|
||||
"mieszana": "mieszana",
|
||||
"kształtowa": "kształtowa",
|
||||
"historyczna": "historyczna"
|
||||
},
|
||||
"controls": {
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"SCS-SPK": "SCS/SPK",
|
||||
"ręczne": "ręczne",
|
||||
"ręczne+SPK": "ręczne + SPK",
|
||||
"ręczne+SCS": "ręczne + SCS",
|
||||
"mechaniczne": "mechaniczne",
|
||||
"mechaniczne+SPK": "mechaniczne + SPK",
|
||||
"mechaniczne+SCS": "mechaniczne + SCS"
|
||||
},
|
||||
"status": {
|
||||
"online": "DO ",
|
||||
"free": "WOLNA",
|
||||
"ending": "KOŃCZY",
|
||||
"not-signed": "NIEZALOGOWANY",
|
||||
"no-limit": "BEZ LIMITU",
|
||||
"unavailable": "NIEDOSTĘPNY",
|
||||
"brb": "Z/W",
|
||||
"no-space": "BRAK MIEJSCA"
|
||||
},
|
||||
"options": {
|
||||
"filters": "FILTRY",
|
||||
"donate": "WESPRZYJ"
|
||||
},
|
||||
"filters": {
|
||||
"title": "FILTRUJ STACJE",
|
||||
"default": "DOMYŚLNA",
|
||||
"not-default": "POZA PACZKĄ",
|
||||
"real": "REALNA",
|
||||
"fictional": "FIKCYJNA",
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"manual": "RĘCZNE",
|
||||
"mechanical": "MECHANICZNE",
|
||||
"modern": "WSPÓŁCZESNA",
|
||||
"semaphores": "KSZTAŁTOWA",
|
||||
"mixed": "MIESZANA",
|
||||
"historical": "HISTORYCZNA",
|
||||
"free": "WOLNA",
|
||||
"occupied": "ZAJĘTA",
|
||||
"sliders": {
|
||||
"min-lvl": "MINIMALNY WYMAGANY POZIOM DYŻURNEGO",
|
||||
"routes-1t-cat": "SZLAKI JEDNOTOROWE ZELEKTR. (MINIMUM)",
|
||||
"routes-1t-other": "SZLAKI JEDNOTOROWE NIEZELEKTR. (MINIMUM)",
|
||||
"routes-2t-cat": "SZLAKI DWUTOROWE ZELEKTR. (MINIMUM)",
|
||||
"routes-2t-other": "SZLAKI DWUTOROWE NIEZELEKTR. (MINIMUM)"
|
||||
},
|
||||
"save": "ZAPISZ FILTRY",
|
||||
"reset": "RESETUJ FILTRY",
|
||||
"close": "ZAMKNIJ FILTRY"
|
||||
},
|
||||
"sceneries": {
|
||||
"station": "Stacja",
|
||||
"min-lvl": "Min. poziom <br/> dyżurnego",
|
||||
"status": "Status",
|
||||
"dispatcher": "Dyżurny",
|
||||
"dispatcher-lvl": "Poziom <br> dyżurnego",
|
||||
"routes": "Szlaki <br> 2tor | 1tor",
|
||||
"general": "Informacje <br> ogólne",
|
||||
"users": "Maszyniści online",
|
||||
"spawns": "Otwarte spawny",
|
||||
"timetables": "Aktywne rozkłady jazdy",
|
||||
"no-stations": "Brak stacji do wyświetlenia!"
|
||||
},
|
||||
"trains": {
|
||||
"no-trains": "Brak pociągów online!",
|
||||
"stats": "STATYSTYKI RUCHU",
|
||||
"stats-speed": "PRĘDKOŚCI POCIĄGÓW (MIN | ŚR | MAX) [km/h]",
|
||||
"stats-length": "DŁUGOŚCI ROZKŁADÓW (MIN | ŚR | MAX) [km]",
|
||||
"stats-categories": "KATEGORIE RJ",
|
||||
"stats-special-twr": "WYSOKIEGO RYZYKA",
|
||||
"stats-special-skr": "PRZEKROCZONA SKRAJNIA",
|
||||
"stats-locos": "NAJCZĘSTSZE JEDNOSTKI",
|
||||
"option-mass": "masa",
|
||||
"option-speed": "prędkość",
|
||||
"option-length": "długość",
|
||||
"option-distance": "kilometraż",
|
||||
"option-timetable": "numer pociagu",
|
||||
"search-no": "Szukaj nr pociągu...",
|
||||
"search-driver": "Szukaj maszynisty...",
|
||||
"detailed-timetable": "Szczegółowy rozkład jazdy pociągu ",
|
||||
"via-title": "Przez: "
|
||||
},
|
||||
"journal": {
|
||||
"title": "DZIENNIK AKTYWNOŚCI SCENERII",
|
||||
"subtitle": "Pokazuje dyżurnych, którzy ostatnio byli aktywni na wybranej scenerii",
|
||||
"disclaimer": "<b>Ta funkcjonalność jest w testach beta!</b> <br> Informacje pokazywane na ekranie mogą znikać, a ich zawartość może być fałszywa!",
|
||||
"select": "Wybierz scenerię"
|
||||
},
|
||||
"scenery": {
|
||||
"users": "GRACZE ONLINE",
|
||||
"spawns": "OTWARTE SPAWNY",
|
||||
"timetables": "AKTYWNE ROZKŁADY JAZDY",
|
||||
"no-timetables": "Brak aktywnych rozkładów!",
|
||||
"no-users": "BRAK AKTYWNYCH GRACZY",
|
||||
"no-spawns": "BRAK OTWARTYCH SPAWNÓW",
|
||||
"no-scenery": "Ups! Nie znaleziono danej stacji bądź jest ona offline!",
|
||||
"return-btn": "Wróć na stronę główną"
|
||||
},
|
||||
"timetables": {
|
||||
"online": "Na stacji",
|
||||
"departed": "Odprawiony",
|
||||
"departed-away": "Odjechał",
|
||||
"arriving": "W drodze",
|
||||
"stopped": "Postój",
|
||||
"terminated": "Skończył bieg",
|
||||
"begins": "ROZPOCZYNA <br /> BIEG",
|
||||
"terminates": "KOŃCZY BIEG"
|
||||
}
|
||||
}
|
||||
{
|
||||
"app": {
|
||||
"sceneries": "SCENERIE",
|
||||
"trains": "POCIĄGI",
|
||||
"journal": "DZIENNIK",
|
||||
"loading": "Pobieranie danych...",
|
||||
"support": "Wspomóż projekt"
|
||||
},
|
||||
"desc": {
|
||||
"control-type": "Sterowanie: ",
|
||||
"signals-type": "Sygnalizacja: ",
|
||||
"SBL": "Sceneria posiada SBL na szlakach: ",
|
||||
"default": "Sceneria dostępna domyślnie w paczce z grą",
|
||||
"non-public": "Sceneria niepubliczna",
|
||||
"unavailable": "Sceneria niedostępna",
|
||||
"real": "Sceneria realna"
|
||||
},
|
||||
"signals": {
|
||||
"współczesna": "współczesna",
|
||||
"mieszana": "mieszana",
|
||||
"kształtowa": "kształtowa",
|
||||
"historyczna": "historyczna"
|
||||
},
|
||||
"controls": {
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"SCS-SPK": "SCS/SPK",
|
||||
"ręczne": "ręczne",
|
||||
"ręczne+SPK": "ręczne + SPK",
|
||||
"ręczne+SCS": "ręczne + SCS",
|
||||
"mechaniczne": "mechaniczne",
|
||||
"mechaniczne+SPK": "mechaniczne + SPK",
|
||||
"mechaniczne+SCS": "mechaniczne + SCS"
|
||||
},
|
||||
"status": {
|
||||
"online": "DO ",
|
||||
"free": "WOLNA",
|
||||
"ending": "KOŃCZY",
|
||||
"not-signed": "NIEZALOGOWANY",
|
||||
"no-limit": "BEZ LIMITU",
|
||||
"unavailable": "NIEDOSTĘPNY",
|
||||
"brb": "Z/W",
|
||||
"no-space": "BRAK MIEJSCA"
|
||||
},
|
||||
"options": {
|
||||
"filters": "FILTRY",
|
||||
"donate": "WESPRZYJ"
|
||||
},
|
||||
"filters": {
|
||||
"title": "FILTRUJ STACJE",
|
||||
"default": "DOMYŚLNA",
|
||||
"not-default": "POZA PACZKĄ",
|
||||
"real": "REALNA",
|
||||
"fictional": "FIKCYJNA",
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"manual": "RĘCZNE",
|
||||
"mechanical": "MECHANICZNE",
|
||||
"modern": "WSPÓŁCZESNA",
|
||||
"semaphores": "KSZTAŁTOWA",
|
||||
"mixed": "MIESZANA",
|
||||
"historical": "HISTORYCZNA",
|
||||
"free": "WOLNA",
|
||||
"occupied": "ZAJĘTA",
|
||||
"sliders": {
|
||||
"min-lvl": "MINIMALNY WYMAGANY POZIOM DYŻURNEGO",
|
||||
"routes-1t-cat": "SZLAKI JEDNOTOROWE ZELEKTR. (MINIMUM)",
|
||||
"routes-1t-other": "SZLAKI JEDNOTOROWE NIEZELEKTR. (MINIMUM)",
|
||||
"routes-2t-cat": "SZLAKI DWUTOROWE ZELEKTR. (MINIMUM)",
|
||||
"routes-2t-other": "SZLAKI DWUTOROWE NIEZELEKTR. (MINIMUM)"
|
||||
},
|
||||
"save": "ZAPISZ FILTRY",
|
||||
"reset": "RESETUJ FILTRY",
|
||||
"close": "ZAMKNIJ FILTRY"
|
||||
},
|
||||
"sceneries": {
|
||||
"station": "Stacja",
|
||||
"min-lvl": "Min. poziom <br/> dyżurnego",
|
||||
"status": "Status",
|
||||
"dispatcher": "Dyżurny",
|
||||
"dispatcher-lvl": "Poziom <br> dyżurnego",
|
||||
"routes": "Szlaki <br> 2tor | 1tor",
|
||||
"general": "Informacje <br> ogólne",
|
||||
"users": "Maszyniści online",
|
||||
"spawns": "Otwarte spawny",
|
||||
"timetables": "Aktywne rozkłady jazdy",
|
||||
"no-stations": "Brak stacji do wyświetlenia!"
|
||||
},
|
||||
"trains": {
|
||||
"no-trains": "Brak pociągów online!",
|
||||
"stats": "STATYSTYKI RUCHU",
|
||||
"stats-speed": "PRĘDKOŚCI POCIĄGÓW (MIN | ŚR | MAX) [km/h]",
|
||||
"stats-length": "DŁUGOŚCI ROZKŁADÓW (MIN | ŚR | MAX) [km]",
|
||||
"stats-categories": "KATEGORIE RJ",
|
||||
"stats-special-twr": "WYSOKIEGO RYZYKA",
|
||||
"stats-special-skr": "PRZEKROCZONA SKRAJNIA",
|
||||
"stats-locos": "NAJCZĘSTSZE JEDNOSTKI",
|
||||
"option-mass": "masa",
|
||||
"option-speed": "prędkość",
|
||||
"option-length": "długość",
|
||||
"option-distance": "kilometraż",
|
||||
"option-timetable": "numer pociagu",
|
||||
"search-no": "Szukaj nr pociągu...",
|
||||
"search-driver": "Szukaj maszynisty...",
|
||||
"detailed-timetable": "Szczegółowy rozkład jazdy pociągu ",
|
||||
"via-title": "Przez: "
|
||||
},
|
||||
"journal": {
|
||||
"title": "DZIENNIK AKTYWNOŚCI SCENERII",
|
||||
"subtitle": "Pokazuje dyżurnych, którzy ostatnio byli aktywni na wybranej scenerii",
|
||||
"disclaimer": "<b>Ta funkcjonalność jest w testach beta!</b> <br> Informacje pokazywane na ekranie mogą znikać, a ich zawartość może być fałszywa!",
|
||||
"select": "Wybierz scenerię"
|
||||
},
|
||||
"scenery": {
|
||||
"users": "GRACZE ONLINE",
|
||||
"spawns": "OTWARTE SPAWNY",
|
||||
"timetables": "AKTYWNE ROZKŁADY JAZDY",
|
||||
"no-timetables": "Brak aktywnych rozkładów!",
|
||||
"no-users": "BRAK AKTYWNYCH GRACZY",
|
||||
"no-spawns": "BRAK OTWARTYCH SPAWNÓW",
|
||||
"no-scenery": "Ups! Nie znaleziono danej stacji bądź jest ona offline!",
|
||||
"return-btn": "Wróć na stronę główną"
|
||||
},
|
||||
"timetables": {
|
||||
"online": "Na stacji",
|
||||
"departed": "Odprawiony",
|
||||
"departed-away": "Odjechał",
|
||||
"arriving": "W drodze",
|
||||
"stopped": "Postój",
|
||||
"terminated": "Skończył bieg",
|
||||
"begins": "ROZPOCZYNA <br /> BIEG",
|
||||
"terminates": "KOŃCZY BIEG"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
interface ISceneryInfoData {
|
||||
stationName: string;
|
||||
stationURL: string;
|
||||
stationLines: string;
|
||||
stationProject: string;
|
||||
|
||||
reqLevel: string;
|
||||
supportersOnly: string;
|
||||
signalType: string;
|
||||
controlType: string;
|
||||
SBL: string;
|
||||
twoWayBlock: string;
|
||||
|
||||
routesOneWayCatenary: number;
|
||||
routesOneWayOther: number;
|
||||
routesTwoWayCatenary: number;
|
||||
routesToWayOther: number;
|
||||
|
||||
default: boolean;
|
||||
nonPublic: boolean;
|
||||
unavailable: boolean;
|
||||
hasData: boolean;
|
||||
|
||||
stops: string[];
|
||||
checkpoints: string[];
|
||||
|
||||
currentDispatcher: string;
|
||||
currentDispatcherId: number;
|
||||
currentDispatcherFrom: number;
|
||||
dispatcherHistory: { dispatcherName: string; dispatcherId: number; dispatcherFrom: number; dispatcherTo: number }[];
|
||||
}
|
||||
|
||||
export default ISceneryInfoData;
|
||||
interface ISceneryInfoData {
|
||||
stationName: string;
|
||||
stationURL: string;
|
||||
stationLines: string;
|
||||
stationProject: string;
|
||||
|
||||
reqLevel: string;
|
||||
supportersOnly: string;
|
||||
signalType: string;
|
||||
controlType: string;
|
||||
SBL: string;
|
||||
twoWayBlock: string;
|
||||
|
||||
routesOneWayCatenary: number;
|
||||
routesOneWayOther: number;
|
||||
routesTwoWayCatenary: number;
|
||||
routesToWayOther: number;
|
||||
|
||||
default: boolean;
|
||||
nonPublic: boolean;
|
||||
unavailable: boolean;
|
||||
hasData: boolean;
|
||||
|
||||
stops: string[];
|
||||
checkpoints: string[];
|
||||
|
||||
currentDispatcher: string;
|
||||
currentDispatcherId: number;
|
||||
currentDispatcherFrom: number;
|
||||
dispatcherHistory: { dispatcherName: string; dispatcherId: number; dispatcherFrom: number; dispatcherTo: number }[];
|
||||
}
|
||||
|
||||
export default ISceneryInfoData;
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import store from "@/store";
|
||||
import { Module, VuexModule, Mutation, Action, MutationAction } from "vuex-module-decorators";
|
||||
|
||||
@Module({ dynamic: true, store, name: "dataModule" })
|
||||
export default class MyModule extends VuexModule {
|
||||
test: string = "xd";
|
||||
|
||||
get getTest() {
|
||||
return this.test;
|
||||
}
|
||||
|
||||
@MutationAction
|
||||
async fetchTest() {
|
||||
const fetched = "aaa";
|
||||
|
||||
return { test: fetched };
|
||||
}
|
||||
}
|
||||
+116
-266
@@ -1,20 +1,22 @@
|
||||
import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators';
|
||||
import axios from 'axios';
|
||||
import { Module, VuexModule, Mutation, Action } from "vuex-module-decorators";
|
||||
import axios from "axios";
|
||||
|
||||
import JSONStationData from '@/data/stationData.json';
|
||||
import JSONStationData from "@/data/stationData.json";
|
||||
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
import Train from '@/scripts/interfaces/Train';
|
||||
import TrainStop from '@/scripts/interfaces/TrainStop';
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
import Train from "@/scripts/interfaces/Train";
|
||||
import TrainStop from "@/scripts/interfaces/TrainStop";
|
||||
|
||||
import utils from "@/scripts/utils/storeUtils";
|
||||
|
||||
enum Status {
|
||||
Initialized = -1,
|
||||
Loading = 0,
|
||||
Error = 1,
|
||||
Loaded = 2,
|
||||
Loaded = 2
|
||||
}
|
||||
|
||||
interface ITimetableData {
|
||||
interface TimetableData {
|
||||
trainNo: number;
|
||||
driverName: string;
|
||||
driverId: number;
|
||||
@@ -50,87 +52,11 @@ interface IOnlineStationData {
|
||||
}
|
||||
|
||||
const URLs = {
|
||||
stations: 'https://api.td2.info.pl:9640/?method=getStationsOnline',
|
||||
trains: 'https://api.td2.info.pl:9640/?method=getTrainsOnline',
|
||||
dispatchers: 'https://api.td2.info.pl:9640/?method=readFromSWDR&value=getDispatcherStatusList%3B1',
|
||||
stations: "https://api.td2.info.pl:9640/?method=getStationsOnline",
|
||||
trains: "https://api.td2.info.pl:9640/?method=getTrainsOnline",
|
||||
dispatchers: "https://api.td2.info.pl:9640/?method=readFromSWDR&value=getDispatcherStatusList%3B1"
|
||||
};
|
||||
|
||||
const timetableURL = (trainNo: number) => `https://api.td2.info.pl:9640/?method=readFromSWDR&value=getTimetable%3B${trainNo}%3Beu`;
|
||||
const getLocoURL = (locoType: string) => `https://rj.td2.info.pl/dist/img/thumbnails/${locoType.includes('EN') ? locoType + 'rb' : locoType}.png`;
|
||||
|
||||
const getStatusID = (stationStatus: any) => {
|
||||
if (!stationStatus) return 'not-signed';
|
||||
|
||||
const statusCode = stationStatus[2];
|
||||
const statusTimestamp = stationStatus[3];
|
||||
|
||||
switch (statusCode) {
|
||||
case 0:
|
||||
if (statusTimestamp - Date.now() > 21000000) return 'no-limit';
|
||||
|
||||
return 'online';
|
||||
|
||||
case 1:
|
||||
return 'brb';
|
||||
|
||||
case 2:
|
||||
if (statusTimestamp == 0) return 'ending';
|
||||
break;
|
||||
|
||||
case 3:
|
||||
return 'no-space';
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 'unavailable';
|
||||
};
|
||||
|
||||
const getStatusTimestamp = (stationStatus: any) => {
|
||||
if (!stationStatus) return -2;
|
||||
|
||||
const statusCode = stationStatus[2];
|
||||
const statusTimestamp = stationStatus[3];
|
||||
|
||||
switch (statusCode) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 3:
|
||||
return statusTimestamp;
|
||||
|
||||
case 2:
|
||||
if (statusTimestamp == 0) return 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
};
|
||||
|
||||
const parseSpawns = (spawnString: string) => {
|
||||
if (!spawnString) return [];
|
||||
if (spawnString === 'NO_SPAWN') return [];
|
||||
|
||||
return spawnString.split(';').map(spawn => {
|
||||
const spawnArray = spawn.split(',');
|
||||
const spawnName = spawnArray[6] ? spawnArray[6] : spawnArray[0];
|
||||
const spawnLength = parseInt(spawnArray[2]);
|
||||
|
||||
return { spawnName, spawnLength };
|
||||
});
|
||||
};
|
||||
|
||||
const getTimestamp = (date: string) => (date ? new Date(date).getTime() : 0);
|
||||
|
||||
const timestampToString = (timestamp: number) =>
|
||||
new Date(timestamp).toLocaleTimeString('pl-PL', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
});
|
||||
|
||||
@Module
|
||||
export default class Store extends VuexModule {
|
||||
private trainCount: number = 0;
|
||||
@@ -151,7 +77,7 @@ export default class Store extends VuexModule {
|
||||
trainCount: this.trainCount,
|
||||
stationCount: this.stationCount,
|
||||
dataConnectionStatus: this.dataConnectionStatus,
|
||||
timetableDataStatus: this.timetableLoaded,
|
||||
timetableDataStatus: this.timetableLoaded
|
||||
};
|
||||
}
|
||||
|
||||
@@ -177,27 +103,27 @@ export default class Store extends VuexModule {
|
||||
//ACTIONS
|
||||
@Action
|
||||
async synchronizeData() {
|
||||
this.context.commit('setSceneryData');
|
||||
this.context.commit('setSceneryDataStatus', Status.Loaded);
|
||||
this.context.commit("setSceneryData");
|
||||
this.context.commit("setSceneryDataStatus", Status.Loaded);
|
||||
|
||||
this.context.dispatch('fetchOnlineData');
|
||||
setInterval(() => this.context.dispatch('fetchOnlineData'), 20000);
|
||||
this.context.dispatch("fetchOnlineData");
|
||||
setInterval(() => this.context.dispatch("fetchOnlineData"), 20000);
|
||||
}
|
||||
|
||||
@Action({ commit: 'updateTimetableData' })
|
||||
@Action({ commit: "updateTimetableData" })
|
||||
async fetchTimetableData() {
|
||||
return this.trainList.reduce(async (acc: Promise<ITimetableData[]>, train) => {
|
||||
const timetable = await (await axios.get(timetableURL(train.trainNo))).data.message;
|
||||
return this.trainList.reduce(async (acc: Promise<TimetableData[]>, train) => {
|
||||
const timetable = await (await axios.get(utils.timetableURL(train.trainNo))).data.message;
|
||||
const trainInfo = timetable.trainInfo;
|
||||
|
||||
if (!timetable || !trainInfo) return acc;
|
||||
|
||||
const followingStops: TrainStop[] = timetable.stopPoints.reduce((stopsAcc: TrainStop[], point) => {
|
||||
const arrivalTimestamp = getTimestamp(point.arrivalTime);
|
||||
const arrivalRealTimestamp = getTimestamp(point.arrivalRealTime);
|
||||
const arrivalTimestamp = utils.getTimestamp(point.arrivalTime);
|
||||
const arrivalRealTimestamp = utils.getTimestamp(point.arrivalRealTime);
|
||||
|
||||
const departureTimestamp = getTimestamp(point.departureTime);
|
||||
const departureRealTimestamp = getTimestamp(point.departureRealTime);
|
||||
const departureTimestamp = utils.getTimestamp(point.departureTime);
|
||||
const departureRealTimestamp = utils.getTimestamp(point.departureRealTime);
|
||||
|
||||
stopsAcc.push({
|
||||
stopName: point.pointName,
|
||||
@@ -205,19 +131,19 @@ export default class Store extends VuexModule {
|
||||
stopType: point.pointStopType,
|
||||
stopDistance: point.pointDistance,
|
||||
|
||||
mainStop: point.pointName.includes('strong'),
|
||||
mainStop: point.pointName.includes("strong"),
|
||||
|
||||
arrivalLine: point.arrivalLine,
|
||||
arrivalTimeString: timestampToString(point.arrivalTime),
|
||||
arrivalTimeString: utils.timestampToString(point.arrivalTime),
|
||||
arrivalTimestamp: arrivalTimestamp,
|
||||
arrivalRealTimeString: timestampToString(point.arrivalRealTime),
|
||||
arrivalRealTimeString: utils.timestampToString(point.arrivalRealTime),
|
||||
arrivalRealTimestamp: arrivalRealTimestamp,
|
||||
arrivalDelay: point.arrivalDelay,
|
||||
|
||||
departureLine: point.departureLine,
|
||||
departureTimeString: timestampToString(point.departureTime),
|
||||
departureTimeString: utils.timestampToString(point.departureTime),
|
||||
departureTimestamp: departureTimestamp,
|
||||
departureRealTimeString: timestampToString(point.departureRealTime),
|
||||
departureRealTimeString: utils.timestampToString(point.departureRealTime),
|
||||
departureRealTimestamp: departureRealTimestamp,
|
||||
departureDelay: point.departureDelay,
|
||||
|
||||
@@ -226,7 +152,7 @@ export default class Store extends VuexModule {
|
||||
|
||||
confirmed: point.confirmed,
|
||||
stopped: point.isStopped,
|
||||
stopTime: point.pointStopTime,
|
||||
stopTime: point.pointStopTime
|
||||
});
|
||||
|
||||
return stopsAcc;
|
||||
@@ -245,7 +171,7 @@ export default class Store extends VuexModule {
|
||||
SKR: trainInfo.skr,
|
||||
routeDistance: timetable.stopPoints[timetable.stopPoints.length - 1].pointDistance,
|
||||
followingStops,
|
||||
followingSceneries: trainInfo.sceneries,
|
||||
followingSceneries: trainInfo.sceneries
|
||||
});
|
||||
|
||||
return acc;
|
||||
@@ -261,15 +187,15 @@ export default class Store extends VuexModule {
|
||||
const onlineDispatchersData = await response[2].data.message;
|
||||
|
||||
let updatedStationList = onlineStationsData.reduce((acc, station) => {
|
||||
if (station.region !== 'eu' || !station.isOnline) return acc;
|
||||
if (station.region !== "eu" || !station.isOnline) return acc;
|
||||
|
||||
const stationStatus = onlineDispatchersData.find(status => status[0] == station.stationHash && status[1] == 'eu');
|
||||
const stationStatus = onlineDispatchersData.find(status => status[0] == station.stationHash && status[1] == "eu");
|
||||
|
||||
const statusTimestamp = getStatusTimestamp(stationStatus);
|
||||
const statusID = getStatusID(stationStatus);
|
||||
const statusTimestamp = utils.getStatusTimestamp(stationStatus);
|
||||
const statusID = utils.getStatusID(stationStatus);
|
||||
|
||||
const stationTrains = onlineTrainsData.filter(
|
||||
train => train.region === 'eu' && train.isOnline && train.station.stationName === station.stationName
|
||||
train => train.region === "eu" && train.isOnline && train.station.stationName === station.stationName
|
||||
);
|
||||
|
||||
acc.push({
|
||||
@@ -277,7 +203,7 @@ export default class Store extends VuexModule {
|
||||
stationHash: station.stationHash,
|
||||
maxUsers: station.maxUsers,
|
||||
currentUsers: station.currentUsers,
|
||||
spawns: parseSpawns(station.spawnString),
|
||||
spawns: utils.parseSpawns(station.spawnString),
|
||||
dispatcherName: station.dispatcherName,
|
||||
dispatcherRate: station.dispatcherRate,
|
||||
dispatcherId: station.dispatcherId,
|
||||
@@ -286,7 +212,7 @@ export default class Store extends VuexModule {
|
||||
stationTrains,
|
||||
statusTimestamp,
|
||||
statusID,
|
||||
statusTimeString: timestampToString(statusTimestamp),
|
||||
statusTimeString: utils.timestampToString(statusTimestamp)
|
||||
});
|
||||
|
||||
return acc;
|
||||
@@ -294,9 +220,9 @@ export default class Store extends VuexModule {
|
||||
|
||||
let updatedTrainList = await Promise.all(
|
||||
onlineTrainsData
|
||||
.filter(train => train.region === 'eu')
|
||||
.filter(train => train.region === "eu")
|
||||
.map(async train => {
|
||||
const locoType = train.dataCon.split(';') ? train.dataCon.split(';')[0] : train.dataCon;
|
||||
const locoType = train.dataCon.split(";") ? train.dataCon.split(";")[0] : train.dataCon;
|
||||
|
||||
return {
|
||||
trainNo: train.trainNo,
|
||||
@@ -312,18 +238,18 @@ export default class Store extends VuexModule {
|
||||
currentStationHash: train.station.stationHash,
|
||||
connectedTrack: train.dataSceneryConnection,
|
||||
locoType,
|
||||
locoURL: getLocoURL(locoType),
|
||||
locoURL: utils.getLocoURL(locoType)
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
this.context.commit('updateOnlineStations', updatedStationList);
|
||||
this.context.commit('updateOnlineTrains', updatedTrainList);
|
||||
this.context.commit("updateOnlineStations", updatedStationList);
|
||||
this.context.commit("updateOnlineTrains", updatedTrainList);
|
||||
|
||||
this.context.dispatch('fetchTimetableData');
|
||||
this.context.dispatch("fetchTimetableData");
|
||||
})
|
||||
.catch(err => {
|
||||
this.context.commit('setDataConnectionStatus', Status.Error);
|
||||
this.context.commit("setDataConnectionStatus", Status.Error);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -368,7 +294,7 @@ export default class Store extends VuexModule {
|
||||
stationLines: station[2] as string,
|
||||
stationProject: station[3] as string,
|
||||
reqLevel: station[4] as string,
|
||||
supportersOnly: station[5] == 'TAK',
|
||||
supportersOnly: station[5] == "TAK",
|
||||
signalType: station[6] as string,
|
||||
controlType: station[7] as string,
|
||||
SBL: station[8] as string,
|
||||
@@ -376,12 +302,12 @@ export default class Store extends VuexModule {
|
||||
routes: {
|
||||
oneWay: {
|
||||
catenary: station[10] as number,
|
||||
noCatenary: station[11] as number,
|
||||
noCatenary: station[11] as number
|
||||
},
|
||||
twoWay: {
|
||||
catenary: station[12] as number,
|
||||
noCatenary: station[13] as number,
|
||||
},
|
||||
noCatenary: station[13] as number
|
||||
}
|
||||
},
|
||||
checkpoints: station[14] ? (station[14] as string[]).map(sub => ({ checkpointName: sub, scheduledTrains: [] })) : null,
|
||||
stops: station[15] as string[],
|
||||
@@ -390,21 +316,21 @@ export default class Store extends VuexModule {
|
||||
nonPublic: station[17] as boolean,
|
||||
unavailable: station[18] as boolean,
|
||||
|
||||
stationHash: '',
|
||||
stationHash: "",
|
||||
maxUsers: 0,
|
||||
currentUsers: 0,
|
||||
dispatcherName: '',
|
||||
dispatcherName: "",
|
||||
dispatcherRate: 0,
|
||||
dispatcherExp: -1,
|
||||
dispatcherId: 0,
|
||||
dispatcherIsSupporter: false,
|
||||
online: false,
|
||||
statusTimestamp: -3,
|
||||
statusID: 'free',
|
||||
statusTimeString: '',
|
||||
statusID: "free",
|
||||
statusTimeString: "",
|
||||
stationTrains: [],
|
||||
scheduledTrains: [],
|
||||
spawns: [],
|
||||
spawns: []
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -418,27 +344,27 @@ export default class Store extends VuexModule {
|
||||
acc.push({
|
||||
...station,
|
||||
...onlineStationData,
|
||||
online: true,
|
||||
online: true
|
||||
});
|
||||
else if (registeredStation)
|
||||
acc.push({
|
||||
...station,
|
||||
stationProject: '',
|
||||
stationHash: '',
|
||||
stationProject: "",
|
||||
stationHash: "",
|
||||
maxUsers: 0,
|
||||
currentUsers: 0,
|
||||
dispatcherName: '',
|
||||
dispatcherName: "",
|
||||
dispatcherRate: 0,
|
||||
dispatcherExp: -1,
|
||||
dispatcherId: 0,
|
||||
dispatcherIsSupporter: false,
|
||||
online: false,
|
||||
statusID: 'free',
|
||||
statusID: "free",
|
||||
statusTimestamp: -3,
|
||||
statusTimeString: '',
|
||||
statusTimeString: "",
|
||||
stationTrains: [],
|
||||
scheduledTrains: [],
|
||||
checkpoints: null,
|
||||
checkpoints: null
|
||||
});
|
||||
|
||||
return acc;
|
||||
@@ -453,8 +379,8 @@ export default class Store extends VuexModule {
|
||||
stationTrains: [],
|
||||
subStations: [],
|
||||
online: true,
|
||||
reqLevel: '-1',
|
||||
nonPublic: true,
|
||||
reqLevel: "-1",
|
||||
nonPublic: true
|
||||
});
|
||||
});
|
||||
|
||||
@@ -478,153 +404,77 @@ export default class Store extends VuexModule {
|
||||
}
|
||||
|
||||
@Mutation
|
||||
private updateTimetableData(timetableList: ITimetableData[]) {
|
||||
private updateTimetableData(timetableList: TimetableData[]) {
|
||||
this.stationList = this.stationList.map(station => {
|
||||
const stationName = station.stationName.toLowerCase();
|
||||
const scheduledTrains: Station['scheduledTrains'] = timetableList.reduce(
|
||||
(acc: Station['scheduledTrains'], timetableData: ITimetableData, index) => {
|
||||
if (!timetableData.followingSceneries.includes(station.stationHash)) return acc;
|
||||
|
||||
const stopInfoIndex = timetableData.followingStops.findIndex(stop => {
|
||||
const stopName = stop.stopNameRAW.toLowerCase();
|
||||
const scheduledTrains: Station["scheduledTrains"] = timetableList.reduce((acc: Station["scheduledTrains"], timetable: TimetableData, index) => {
|
||||
if (!timetable.followingSceneries.includes(station.stationHash)) return acc;
|
||||
|
||||
if (stationName === stopName) return true;
|
||||
if (stopName.includes(stationName) && !stop.stopName.includes('po.') && !stop.stopName.includes('podg.')) return true;
|
||||
if (stationName.includes(stopName) && !stop.stopName.includes('po.') && !stop.stopName.includes('podg.')) return true;
|
||||
if (stopName.includes('podg.') && stopName.split(', podg.')[0] && stationName.includes(stopName.split(', podg.')[0])) return true;
|
||||
const stopInfoIndex = timetable.followingStops.findIndex(stop => {
|
||||
const stopName = stop.stopNameRAW.toLowerCase();
|
||||
|
||||
if (station.stops && station.stops.includes(stop.stopNameRAW)) return true;
|
||||
if (stationName === stopName) return true;
|
||||
if (stopName.includes(stationName) && !stop.stopName.includes("po.") && !stop.stopName.includes("podg.")) return true;
|
||||
if (stationName.includes(stopName) && !stop.stopName.includes("po.") && !stop.stopName.includes("podg.")) return true;
|
||||
if (stopName.includes("podg.") && stopName.split(", podg.")[0] && stationName.includes(stopName.split(", podg.")[0])) return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
if (station.stops && station.stops.includes(stop.stopNameRAW)) return true;
|
||||
|
||||
if (stopInfoIndex == -1) return acc;
|
||||
return false;
|
||||
});
|
||||
|
||||
const stopInfo = timetableData.followingStops[stopInfoIndex];
|
||||
if (stopInfoIndex == -1) return acc;
|
||||
|
||||
let stopStatus = '';
|
||||
let stopLabel = '';
|
||||
let stopStatusID = 0;
|
||||
let nearestStop = '';
|
||||
const trainStop = timetable.followingStops[stopInfoIndex];
|
||||
const trainStopStatus = utils.getTrainStopStatus(trainStop, timetable, station);
|
||||
|
||||
if (stopInfo.terminatesHere && stopInfo.confirmed) {
|
||||
stopStatus = 'terminated';
|
||||
stopLabel = 'Skończył bieg';
|
||||
stopStatusID = 5;
|
||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && timetableData.currentStationName == station.stationName) {
|
||||
stopStatus = 'departed';
|
||||
stopLabel = 'Odprawiony';
|
||||
stopStatusID = 2;
|
||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && timetableData.currentStationName != station.stationName) {
|
||||
stopStatus = 'departed-away';
|
||||
stopLabel = 'Odjechał';
|
||||
stopStatusID = 4;
|
||||
} else if (timetableData.currentStationName == station.stationName && !stopInfo.stopped) {
|
||||
stopStatus = 'online';
|
||||
stopLabel = 'Na stacji';
|
||||
stopStatusID = 0;
|
||||
} else if (timetableData.currentStationName == station.stationName && stopInfo.stopped) {
|
||||
stopStatus = 'stopped';
|
||||
stopLabel = 'Postój';
|
||||
stopStatusID = 1;
|
||||
} else if (timetableData.currentStationName != station.stationName) {
|
||||
stopStatus = 'arriving';
|
||||
stopLabel = 'W drodze';
|
||||
stopStatusID = 3;
|
||||
}
|
||||
acc.push({
|
||||
trainNo: timetable.trainNo,
|
||||
driverName: timetable.driverName,
|
||||
driverId: timetable.driverId,
|
||||
currentStationName: timetable.currentStationName,
|
||||
currentStationHash: timetable.currentStationHash,
|
||||
category: timetable.category,
|
||||
beginsAt: timetable.followingStops[0].stopNameRAW,
|
||||
terminatesAt: timetable.followingStops[timetable.followingStops.length - 1].stopNameRAW,
|
||||
nearestStop: "",
|
||||
stopInfo: trainStop,
|
||||
stopLabel: trainStopStatus.stopLabel,
|
||||
stopStatus: trainStopStatus.stopStatus,
|
||||
stopStatusID: trainStopStatus.stopStatusID
|
||||
});
|
||||
|
||||
if (stopInfoIndex < timetableData.followingStops.length - 2) {
|
||||
for (let i = stopInfoIndex + 1; i < timetableData.followingStops.length - 1; i++) {
|
||||
const stop = timetableData.followingStops[i];
|
||||
|
||||
if (stop.mainStop && stop.stopType.includes('ph')) {
|
||||
nearestStop = stop.stopNameRAW;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
acc.push({
|
||||
trainNo: timetableData.trainNo,
|
||||
driverName: timetableData.driverName,
|
||||
driverId: timetableData.driverId,
|
||||
currentStationName: timetableData.currentStationName,
|
||||
currentStationHash: timetableData.currentStationHash,
|
||||
category: timetableData.category,
|
||||
beginsAt: timetableData.followingStops[0].stopNameRAW,
|
||||
terminatesAt: timetableData.followingStops[timetableData.followingStops.length - 1].stopNameRAW,
|
||||
nearestStop,
|
||||
stopInfo,
|
||||
stopLabel,
|
||||
stopStatus,
|
||||
stopStatusID,
|
||||
});
|
||||
|
||||
return acc;
|
||||
},
|
||||
[]
|
||||
);
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
if (station.checkpoints) {
|
||||
station.checkpoints.forEach(cp => (cp.scheduledTrains.length = 0));
|
||||
|
||||
for (let checkpoint of station.checkpoints) {
|
||||
timetableList.reduce((acc, data) => {
|
||||
data.followingStops
|
||||
.filter(stop => stop.stopNameRAW.toLowerCase() === checkpoint.checkpointName.toLowerCase())
|
||||
.forEach(stopInfo => {
|
||||
// const stopInfo = data.followingStops[stopInfoIndex];
|
||||
|
||||
let stopStatus = '';
|
||||
let stopLabel = '';
|
||||
let nearestStop = '';
|
||||
let stopStatusID = 0;
|
||||
|
||||
if (stopInfo.terminatesHere && stopInfo.confirmed) {
|
||||
stopStatus = 'terminated';
|
||||
stopLabel = 'Skończył bieg';
|
||||
stopStatusID = 5;
|
||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && data.currentStationName == station.stationName) {
|
||||
stopStatus = 'departed';
|
||||
stopLabel = 'Odprawiony';
|
||||
stopStatusID = 2;
|
||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && data.currentStationName != station.stationName) {
|
||||
stopStatus = 'departed-away';
|
||||
stopLabel = 'Odjechał';
|
||||
stopStatusID = 4;
|
||||
} else if (data.currentStationName == station.stationName && !stopInfo.stopped) {
|
||||
stopStatus = 'online';
|
||||
stopLabel = 'Na stacji';
|
||||
stopStatusID = 0;
|
||||
} else if (data.currentStationName == station.stationName && stopInfo.stopped) {
|
||||
stopStatus = 'stopped';
|
||||
stopLabel = 'Postój';
|
||||
stopStatusID = 1;
|
||||
} else if (data.currentStationName != station.stationName) {
|
||||
stopStatus = 'arriving';
|
||||
stopLabel = 'W drodze';
|
||||
stopStatusID = 3;
|
||||
}
|
||||
timetableList.forEach(timetable => {
|
||||
timetable.followingStops
|
||||
.filter(trainStop => trainStop.stopNameRAW.toLowerCase() === checkpoint.checkpointName.toLowerCase())
|
||||
.forEach(trainStop => {
|
||||
const trainStopStatus = utils.getTrainStopStatus(trainStop, timetable, station);
|
||||
|
||||
checkpoint.scheduledTrains.push({
|
||||
trainNo: data.trainNo,
|
||||
driverName: data.driverName,
|
||||
driverId: data.driverId,
|
||||
currentStationName: data.currentStationName,
|
||||
currentStationHash: data.currentStationHash,
|
||||
category: data.category,
|
||||
beginsAt: data.followingStops[0].stopNameRAW,
|
||||
terminatesAt: data.followingStops[data.followingStops.length - 1].stopNameRAW,
|
||||
stopInfo,
|
||||
stopLabel,
|
||||
stopStatus,
|
||||
nearestStop,
|
||||
stopStatusID,
|
||||
trainNo: timetable.trainNo,
|
||||
driverName: timetable.driverName,
|
||||
driverId: timetable.driverId,
|
||||
currentStationName: timetable.currentStationName,
|
||||
currentStationHash: timetable.currentStationHash,
|
||||
category: timetable.category,
|
||||
beginsAt: timetable.followingStops[0].stopNameRAW,
|
||||
terminatesAt: timetable.followingStops[timetable.followingStops.length - 1].stopNameRAW,
|
||||
nearestStop: "",
|
||||
stopInfo: trainStop,
|
||||
stopLabel: trainStopStatus.stopLabel,
|
||||
stopStatus: trainStopStatus.stopStatus,
|
||||
stopStatusID: trainStopStatus.stopStatusID
|
||||
});
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,7 +489,7 @@ export default class Store extends VuexModule {
|
||||
.find(station => station.stationName === train.currentStationName)
|
||||
?.scheduledTrains.find(stationTrain => stationTrain.trainNo === train.trainNo);
|
||||
|
||||
acc.push({ ...train, timetableData, stopStatus: trainData?.stopStatus || '', stopLabel: trainData?.stopLabel || '' });
|
||||
acc.push({ ...train, timetableData, stopStatus: trainData?.stopStatus || "", stopLabel: trainData?.stopLabel || "" });
|
||||
}
|
||||
|
||||
return acc;
|
||||
|
||||
+46
-46
@@ -1,47 +1,47 @@
|
||||
@import './variables.scss';
|
||||
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 4;
|
||||
|
||||
overflow: auto;
|
||||
background: $primaryCol;
|
||||
|
||||
box-shadow: 0 0 15px 5px #474747;
|
||||
|
||||
// width: 75%;
|
||||
width: 650px;
|
||||
max-height: 95%;
|
||||
|
||||
padding: 0.5em 1em;
|
||||
|
||||
|
||||
@include smallScreen {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
// @include midScreen {
|
||||
// width: 85%;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
&-exit {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin: 0.3em 0em;
|
||||
|
||||
img {
|
||||
width: 1.6em;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
@import './variables.scss';
|
||||
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 4;
|
||||
|
||||
overflow: auto;
|
||||
background: $primaryCol;
|
||||
|
||||
box-shadow: 0 0 15px 5px #474747;
|
||||
|
||||
// width: 75%;
|
||||
width: 650px;
|
||||
max-height: 95%;
|
||||
|
||||
padding: 0.5em 1em;
|
||||
|
||||
|
||||
@include smallScreen {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
// @include midScreen {
|
||||
// width: 85%;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
&-exit {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin: 0.3em 0em;
|
||||
|
||||
img {
|
||||
width: 1.6em;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
+347
-347
@@ -1,348 +1,348 @@
|
||||
<template>
|
||||
<div class="history_view">
|
||||
<div class="history_wrapper">
|
||||
<div class="header">
|
||||
<h2>{{ $t("journal.title") }}</h2>
|
||||
<p style="color: #ccc">
|
||||
{{ $t("journal.subtitle") }}
|
||||
</p>
|
||||
|
||||
<div class="search-box">
|
||||
<div class="search-box_content">
|
||||
<label :class="{ disabled: dataLoading }">
|
||||
<select v-model="inputStationName" :disabled="dataLoading">
|
||||
<option value disabled selected hidden>
|
||||
{{ dataLoading ? $t("app.loading") : $t("journal.select") }}
|
||||
</option>
|
||||
<option
|
||||
v-for="station in filteredStationList"
|
||||
:key="station"
|
||||
:value="station"
|
||||
>
|
||||
{{ station }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="disclaimer" v-html="$t('journal.disclaimer')"></div>
|
||||
</div>
|
||||
|
||||
<div class="list">
|
||||
<div class="list_wrapper">
|
||||
<!-- <div class="list_loading" v-if="dataLoading">POBIERANIE DANYCH...</div> -->
|
||||
<transition name="list-anim" mode="out-in">
|
||||
<ul
|
||||
class="list_content"
|
||||
v-if="
|
||||
!dataLoading &&
|
||||
!historyLoading &&
|
||||
computedHistoryList.length != 0
|
||||
"
|
||||
:key="inputStationName"
|
||||
>
|
||||
<li v-if="currentDispatcherFrom != -1" class="current">
|
||||
<div class="dispatcher-name">
|
||||
<a
|
||||
:href="`https://td2.info.pl/profile/?u=${currentDispatcherId}`"
|
||||
>{{ currentDispatcher }}</a
|
||||
>
|
||||
</div>
|
||||
<div class="dispatcher-date">
|
||||
<span style="color: #bbb">{{
|
||||
new Date(currentDispatcherFrom).toLocaleDateString("pl-PL")
|
||||
}}</span>
|
||||
{{
|
||||
new Date(currentDispatcherFrom).toLocaleTimeString(
|
||||
"pl-PL",
|
||||
{ hour: "2-digit", minute: "2-digit" }
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li v-for="(history, i) in computedHistoryList" :key="i">
|
||||
<div class="dispatcher-name">
|
||||
<a
|
||||
:href="`https://td2.info.pl/profile/?u=${history.dispatcherId}`"
|
||||
>{{ history.dispatcherName }}</a
|
||||
>
|
||||
</div>
|
||||
<div class="dispatcher-date">
|
||||
<div>
|
||||
<span style="color: #888">{{
|
||||
history.dispatcherFromDate
|
||||
}}</span>
|
||||
{{ history.dispatcherFromTime }}
|
||||
</div>
|
||||
<div>
|
||||
<span style="color: #888">{{
|
||||
history.dispatcherToDate
|
||||
}}</span>
|
||||
{{ history.dispatcherToTime }}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import axios from "axios";
|
||||
|
||||
import { Component, Vue, Watch } from "vue-property-decorator";
|
||||
import { Getter } from "vuex-class";
|
||||
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
import ISceneryInfoData from "@/scripts/interfaces/ISceneryInfoData";
|
||||
|
||||
@Component
|
||||
export default class HistoryView extends Vue {
|
||||
@Getter("getStationList") stationList!: Station[];
|
||||
|
||||
sceneryHistoryList: ISceneryInfoData[] = [];
|
||||
currentSceneryHistory: ISceneryInfoData["dispatcherHistory"] = [];
|
||||
|
||||
currentDispatcher: string = "";
|
||||
currentDispatcherId: number = 0;
|
||||
currentDispatcherFrom: number = -1;
|
||||
|
||||
inputStationName = "";
|
||||
|
||||
dataLoading = true; /* Initial data */
|
||||
historyLoading = false; /* History loaded after input is checked */
|
||||
|
||||
async mounted() {
|
||||
try {
|
||||
const responseData: ISceneryInfoData[] = await (
|
||||
await axios.get(
|
||||
"https://stacjownik.herokuapp.com/api/getSceneryInfo?items=-1"
|
||||
)
|
||||
).data;
|
||||
|
||||
this.sceneryHistoryList = responseData;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
this.dataLoading = false;
|
||||
}
|
||||
|
||||
@Watch("inputStationName")
|
||||
onInputChanged(val: string) {
|
||||
this.itemSelected(val);
|
||||
}
|
||||
|
||||
get filteredStationList() {
|
||||
return this.sceneryHistoryList
|
||||
.map((station) => station.stationName)
|
||||
.sort((a, b) => (a.toLowerCase() >= b.toLowerCase() ? 1 : -1));
|
||||
}
|
||||
|
||||
get computedHistoryList() {
|
||||
return this.currentSceneryHistory
|
||||
.map(
|
||||
({ dispatcherName, dispatcherFrom, dispatcherTo, dispatcherId }) => ({
|
||||
dispatcherName,
|
||||
dispatcherFrom,
|
||||
dispatcherTo,
|
||||
dispatcherId,
|
||||
dispatcherFromDate: new Date(dispatcherFrom).toLocaleDateString(
|
||||
"pl-PL"
|
||||
),
|
||||
dispatcherFromTime: new Date(
|
||||
dispatcherFrom
|
||||
).toLocaleTimeString("pl-PL", { hour: "2-digit", minute: "2-digit" }),
|
||||
dispatcherToDate: new Date(dispatcherTo).toLocaleDateString("pl-PL"),
|
||||
dispatcherToTime: new Date(dispatcherTo).toLocaleTimeString("pl-PL", {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
}),
|
||||
})
|
||||
)
|
||||
.reverse();
|
||||
}
|
||||
|
||||
async itemSelected(itemName: string) {
|
||||
try {
|
||||
this.historyLoading = true;
|
||||
|
||||
const selectedScenery: ISceneryInfoData = await (
|
||||
await axios.get(
|
||||
`https://stacjownik.herokuapp.com/api/getSceneryInfo?name=${itemName}&items=10`
|
||||
)
|
||||
).data;
|
||||
|
||||
this.currentSceneryHistory = selectedScenery.dispatcherHistory;
|
||||
this.currentDispatcher = selectedScenery.currentDispatcher;
|
||||
this.currentDispatcherId = selectedScenery.currentDispatcherId;
|
||||
this.currentDispatcherFrom = selectedScenery.currentDispatcherFrom;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
this.historyLoading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "../styles/responsive.scss";
|
||||
|
||||
.history {
|
||||
&_view {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
&_wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.list-anim {
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: all 150ms ease-out;
|
||||
}
|
||||
|
||||
&-enter,
|
||||
&-leave-to {
|
||||
opacity: 0.1;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
&-move {
|
||||
transition: transform 100ms;
|
||||
}
|
||||
}
|
||||
|
||||
.disclaimer {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&_content {
|
||||
position: relative;
|
||||
margin: 1em 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
select {
|
||||
border: none;
|
||||
font-size: 1em;
|
||||
|
||||
background-color: rgb(87, 87, 87);
|
||||
padding: 0.3em;
|
||||
padding-right: 50px;
|
||||
outline: none;
|
||||
|
||||
color: white;
|
||||
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
label {
|
||||
position: relative;
|
||||
|
||||
&.disabled::after {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "<>";
|
||||
|
||||
position: absolute;
|
||||
top: -5%;
|
||||
right: 0.3em;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
text-align: center;
|
||||
margin: 1em 0;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
&_loading,
|
||||
&_no-info {
|
||||
margin: 0.3em 0;
|
||||
padding: 0.5em 2em;
|
||||
|
||||
color: white;
|
||||
}
|
||||
|
||||
&_loading {
|
||||
background-color: #b96b11;
|
||||
}
|
||||
|
||||
&_no-info {
|
||||
background-color: firebrick;
|
||||
}
|
||||
|
||||
&_wrapper {
|
||||
@include smallScreen() {
|
||||
width: 95%;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
|
||||
&_content {
|
||||
max-height: 75vh;
|
||||
overflow: auto;
|
||||
|
||||
padding: 0.2em 0.5em;
|
||||
}
|
||||
|
||||
&_content > li {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
|
||||
background: #222;
|
||||
padding: 0.3em 0.8em;
|
||||
margin: 0.3em 0;
|
||||
|
||||
gap: 10em;
|
||||
|
||||
@include smallScreen() {
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
& > div {
|
||||
margin: 0 1em;
|
||||
}
|
||||
|
||||
&.current {
|
||||
background: #007200;
|
||||
}
|
||||
|
||||
& > .dispatcher-name {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
font-size: 1.1em;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
<template>
|
||||
<div class="history_view">
|
||||
<div class="history_wrapper">
|
||||
<div class="header">
|
||||
<h2>{{ $t("journal.title") }}</h2>
|
||||
<p style="color: #ccc">
|
||||
{{ $t("journal.subtitle") }}
|
||||
</p>
|
||||
|
||||
<div class="search-box">
|
||||
<div class="search-box_content">
|
||||
<label :class="{ disabled: dataLoading }">
|
||||
<select v-model="inputStationName" :disabled="dataLoading">
|
||||
<option value disabled selected hidden>
|
||||
{{ dataLoading ? $t("app.loading") : $t("journal.select") }}
|
||||
</option>
|
||||
<option
|
||||
v-for="station in filteredStationList"
|
||||
:key="station"
|
||||
:value="station"
|
||||
>
|
||||
{{ station }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="disclaimer" v-html="$t('journal.disclaimer')"></div>
|
||||
</div>
|
||||
|
||||
<div class="list">
|
||||
<div class="list_wrapper">
|
||||
<!-- <div class="list_loading" v-if="dataLoading">POBIERANIE DANYCH...</div> -->
|
||||
<transition name="list-anim" mode="out-in">
|
||||
<ul
|
||||
class="list_content"
|
||||
v-if="
|
||||
!dataLoading &&
|
||||
!historyLoading &&
|
||||
computedHistoryList.length != 0
|
||||
"
|
||||
:key="inputStationName"
|
||||
>
|
||||
<li v-if="currentDispatcherFrom != -1" class="current">
|
||||
<div class="dispatcher-name">
|
||||
<a
|
||||
:href="`https://td2.info.pl/profile/?u=${currentDispatcherId}`"
|
||||
>{{ currentDispatcher }}</a
|
||||
>
|
||||
</div>
|
||||
<div class="dispatcher-date">
|
||||
<span style="color: #bbb">{{
|
||||
new Date(currentDispatcherFrom).toLocaleDateString("pl-PL")
|
||||
}}</span>
|
||||
{{
|
||||
new Date(currentDispatcherFrom).toLocaleTimeString(
|
||||
"pl-PL",
|
||||
{ hour: "2-digit", minute: "2-digit" }
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li v-for="(history, i) in computedHistoryList" :key="i">
|
||||
<div class="dispatcher-name">
|
||||
<a
|
||||
:href="`https://td2.info.pl/profile/?u=${history.dispatcherId}`"
|
||||
>{{ history.dispatcherName }}</a
|
||||
>
|
||||
</div>
|
||||
<div class="dispatcher-date">
|
||||
<div>
|
||||
<span style="color: #888">{{
|
||||
history.dispatcherFromDate
|
||||
}}</span>
|
||||
{{ history.dispatcherFromTime }}
|
||||
</div>
|
||||
<div>
|
||||
<span style="color: #888">{{
|
||||
history.dispatcherToDate
|
||||
}}</span>
|
||||
{{ history.dispatcherToTime }}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import axios from "axios";
|
||||
|
||||
import { Component, Vue, Watch } from "vue-property-decorator";
|
||||
import { Getter } from "vuex-class";
|
||||
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
import ISceneryInfoData from "@/scripts/interfaces/ISceneryInfoData";
|
||||
|
||||
@Component
|
||||
export default class HistoryView extends Vue {
|
||||
@Getter("getStationList") stationList!: Station[];
|
||||
|
||||
sceneryHistoryList: ISceneryInfoData[] = [];
|
||||
currentSceneryHistory: ISceneryInfoData["dispatcherHistory"] = [];
|
||||
|
||||
currentDispatcher: string = "";
|
||||
currentDispatcherId: number = 0;
|
||||
currentDispatcherFrom: number = -1;
|
||||
|
||||
inputStationName = "";
|
||||
|
||||
dataLoading = true; /* Initial data */
|
||||
historyLoading = false; /* History loaded after input is checked */
|
||||
|
||||
async mounted() {
|
||||
try {
|
||||
const responseData: ISceneryInfoData[] = await (
|
||||
await axios.get(
|
||||
"https://stacjownik.herokuapp.com/api/getSceneryInfo?items=-1"
|
||||
)
|
||||
).data;
|
||||
|
||||
this.sceneryHistoryList = responseData;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
this.dataLoading = false;
|
||||
}
|
||||
|
||||
@Watch("inputStationName")
|
||||
onInputChanged(val: string) {
|
||||
this.itemSelected(val);
|
||||
}
|
||||
|
||||
get filteredStationList() {
|
||||
return this.sceneryHistoryList
|
||||
.map((station) => station.stationName)
|
||||
.sort((a, b) => (a.toLowerCase() >= b.toLowerCase() ? 1 : -1));
|
||||
}
|
||||
|
||||
get computedHistoryList() {
|
||||
return this.currentSceneryHistory
|
||||
.map(
|
||||
({ dispatcherName, dispatcherFrom, dispatcherTo, dispatcherId }) => ({
|
||||
dispatcherName,
|
||||
dispatcherFrom,
|
||||
dispatcherTo,
|
||||
dispatcherId,
|
||||
dispatcherFromDate: new Date(dispatcherFrom).toLocaleDateString(
|
||||
"pl-PL"
|
||||
),
|
||||
dispatcherFromTime: new Date(
|
||||
dispatcherFrom
|
||||
).toLocaleTimeString("pl-PL", { hour: "2-digit", minute: "2-digit" }),
|
||||
dispatcherToDate: new Date(dispatcherTo).toLocaleDateString("pl-PL"),
|
||||
dispatcherToTime: new Date(dispatcherTo).toLocaleTimeString("pl-PL", {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
}),
|
||||
})
|
||||
)
|
||||
.reverse();
|
||||
}
|
||||
|
||||
async itemSelected(itemName: string) {
|
||||
try {
|
||||
this.historyLoading = true;
|
||||
|
||||
const selectedScenery: ISceneryInfoData = await (
|
||||
await axios.get(
|
||||
`https://stacjownik.herokuapp.com/api/getSceneryInfo?name=${itemName}&items=10`
|
||||
)
|
||||
).data;
|
||||
|
||||
this.currentSceneryHistory = selectedScenery.dispatcherHistory;
|
||||
this.currentDispatcher = selectedScenery.currentDispatcher;
|
||||
this.currentDispatcherId = selectedScenery.currentDispatcherId;
|
||||
this.currentDispatcherFrom = selectedScenery.currentDispatcherFrom;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
this.historyLoading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "../styles/responsive.scss";
|
||||
|
||||
.history {
|
||||
&_view {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
&_wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.list-anim {
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: all 150ms ease-out;
|
||||
}
|
||||
|
||||
&-enter,
|
||||
&-leave-to {
|
||||
opacity: 0.1;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
&-move {
|
||||
transition: transform 100ms;
|
||||
}
|
||||
}
|
||||
|
||||
.disclaimer {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&_content {
|
||||
position: relative;
|
||||
margin: 1em 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
select {
|
||||
border: none;
|
||||
font-size: 1em;
|
||||
|
||||
background-color: rgb(87, 87, 87);
|
||||
padding: 0.3em;
|
||||
padding-right: 50px;
|
||||
outline: none;
|
||||
|
||||
color: white;
|
||||
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
label {
|
||||
position: relative;
|
||||
|
||||
&.disabled::after {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "<>";
|
||||
|
||||
position: absolute;
|
||||
top: -5%;
|
||||
right: 0.3em;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
text-align: center;
|
||||
margin: 1em 0;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
&_loading,
|
||||
&_no-info {
|
||||
margin: 0.3em 0;
|
||||
padding: 0.5em 2em;
|
||||
|
||||
color: white;
|
||||
}
|
||||
|
||||
&_loading {
|
||||
background-color: #b96b11;
|
||||
}
|
||||
|
||||
&_no-info {
|
||||
background-color: firebrick;
|
||||
}
|
||||
|
||||
&_wrapper {
|
||||
@include smallScreen() {
|
||||
width: 95%;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
|
||||
&_content {
|
||||
max-height: 75vh;
|
||||
overflow: auto;
|
||||
|
||||
padding: 0.2em 0.5em;
|
||||
}
|
||||
|
||||
&_content > li {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
|
||||
background: #222;
|
||||
padding: 0.3em 0.8em;
|
||||
margin: 0.3em 0;
|
||||
|
||||
gap: 10em;
|
||||
|
||||
@include smallScreen() {
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
& > div {
|
||||
margin: 0 1em;
|
||||
}
|
||||
|
||||
&.current {
|
||||
background: #007200;
|
||||
}
|
||||
|
||||
& > .dispatcher-name {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
font-size: 1.1em;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user