Modal widoku pociągu

This commit is contained in:
2022-07-11 18:04:07 +02:00
parent b14ba94abe
commit fb85352ce3
11 changed files with 209 additions and 71 deletions
+104
View File
@@ -0,0 +1,104 @@
<template>
<div class="card-dimmer"></div>
<div class="train-modal" v-click-outside="closeModal" @keydown.esc="closeModal" >
<button class="btn exit" @click="closeModal" >
<img :src="icons.exit" alt="close card" />
</button>
<div class="content" tabindex="0" ref="content">
<TrainInfo :train="chosenTrain" :extended="false" />
<TrainSchedule :train="chosenTrain" tabindex="0" />
</div>
</div>
</template>
<script lang="ts">
import Train from '@/scripts/interfaces/Train';
import { defineComponent, PropType } from 'vue';
import TrainInfo from '../TrainsView/TrainInfo.vue';
import TrainSchedule from '../TrainsView/TrainSchedule.vue';
export default defineComponent({
components: { TrainInfo, TrainSchedule },
emits: ['closeModal'],
data() {
return {
icons: {
exit: require('@/assets/icon-exit.svg'),
},
};
},
props: {
chosenTrain: {
type: Object as PropType<Train>,
required: true,
},
},
activated() {
this.$nextTick(() => {
(this.$refs['content'] as HTMLElement).focus();
});
},
methods: {
closeModal() {
this.$emit('closeModal');
},
},
});
</script>
<style lang="scss" scoped>
@import '../../styles/responsive.scss';
@import '../../styles/card.scss';
.exit {
position: absolute;
top: 0;
right: 0;
margin: 1em 2em;
background-color: white;
padding: 0.25em;
border-radius: 50%;
z-index: 101;
img {
width: 1.5rem;
vertical-align: middle;
filter: invert(100%);
-moz-filter: invert(100%);
}
}
.train-modal {
position: fixed;
top: 1em;
left: 50%;
text-align: left;
transform: translateX(-50%);
background-color: #202020;
z-index: 100;
width: 95vw;
border: 1px solid gray;
overflow: hidden;
}
.content {
overflow: auto;
max-height: 95vh;
}
</style>
+1 -27
View File
@@ -103,6 +103,7 @@ export default defineComponent({
<style lang="scss">
@import '../../styles/responsive.scss';
@import '../../styles/badge.scss';
h3.section-header {
margin: 0.5em 0;
@@ -143,32 +144,5 @@ h3.section-header {
}
}
.badge {
font-weight: 600;
display: inline-block;
padding: 0;
background: #585858;
margin: 0.25em;
span {
display: inline-block;
padding: 0.2em 0.4em;
}
&-none {
font-weight: 600;
padding: 0.2em 0.4em;
background: firebrick;
text-align: center;
@include smallScreen() {
font-size: 1em;
}
}
}
</style>
@@ -25,6 +25,10 @@
</div>
</div>
<keep-alive>
<TrainModal v-if="chosenTrain" :chosen-train="chosenTrain" @close-modal="closeTrainModal" />
</keep-alive>
<div class="timetable-list">
<!-- <transition name="scenery-timetable-list-anim" mode="out-in"> -->
<!-- <div :key="store.dataStatuses.trains + selectedCheckpoint" class="scenery-timetable-list"> -->
@@ -41,13 +45,8 @@
v-for="(scheduledTrain, i) in computedScheduledTrains"
:key="i + 1"
tabindex="0"
@click="navigateTo('/trains', { trainNo: scheduledTrain.trainNo, driverName: scheduledTrain.driverName })"
@keydown.enter="
navigateTo('/trains', {
trainNo: scheduledTrain.trainNo,
driverName: scheduledTrain.driverName,
})
"
@click.prevent.stop="selectTrain(scheduledTrain.trainId)"
@keydown.enter.prevent="selectTrain(scheduledTrain.trainId)"
>
<span class="timetable-general">
<span class="general-info">
@@ -166,11 +165,12 @@ import dateMixin from '@/mixins/dateMixin';
import routerMixin from '@/mixins/routerMixin';
import { useStore } from '@/store/store';
import Loading from '../Global/Loading.vue';
import TrainModal from '../Global/TrainModal.vue';
export default defineComponent({
name: 'SceneryTimetable',
components: { SelectBox, Loading },
components: { SelectBox, Loading, TrainModal },
mixins: [dateMixin, routerMixin],
@@ -188,6 +188,8 @@ export default defineComponent({
warning: require('@/assets/icon-warning.svg'),
timetable: require('@/assets/icon-timetable.svg'),
},
chosenTrainId: null as string | null,
}),
setup(props) {
@@ -236,6 +238,12 @@ export default defineComponent({
};
},
computed: {
chosenTrain() {
return this.store.trainList.find((train) => train.trainId == this.chosenTrainId);
},
},
methods: {
loadSelectedOption() {
if (!this.station) return;
@@ -251,6 +259,14 @@ export default defineComponent({
selectCheckpoint(cp: { checkpointName: string }) {
this.selectedCheckpoint = cp.checkpointName;
},
selectTrain(trainId: string) {
this.chosenTrainId = trainId;
},
closeTrainModal() {
this.chosenTrainId = null;
},
},
mounted() {
+29 -24
View File
@@ -1,17 +1,9 @@
<template>
<div class="train-info simple" tabindex="0">
<section>
<div class="train-info" tabindex="0">
<section class="train-route">
<span>
<div>
<span>
<!-- <router-link
v-if="train.timetableData"
:to="`/journal/timetables?timetableId=${train.timetableData.timetableId}`"
style="color: #ddd; margin-right: 0.3em"
>
#{{ train.timetableData.timetableId }}
</router-link> -->
<span class="timetable-id" v-if="train.timetableData">#{{ train.timetableData.timetableId }}</span>
<span class="timetable_warnings">
@@ -96,8 +88,10 @@
</span>
</section>
<section class="train-image" style="display: flex; justify-content: center; align-items: center">
<img :src="train.locoURL" loading="lazy" alt="Loco image not found" @error="onImageError" />
<section class="train-stats">
<div>
<img :src="train.locoURL" loading="lazy" alt="Loco image not found" @error="onImageError" />
</div>
<div class="text--grayed">
{{ train.locoType }}
@@ -108,12 +102,10 @@
</div>
<div>
<div>
<span v-for="(stat, i) in STATS.main" :key="stat.name">
<span v-if="i > 0"> &bull; </span>
<span>{{ `${~~(train[stat.name] * (stat.multiplier || 1))}${stat.unit}` }} </span>
</span>
</div>
<span v-for="(stat, i) in STATS.main" :key="stat.name">
<span v-if="i > 0"> &bull; </span>
<span>{{ `${~~(train[stat.name] * (stat.multiplier || 1))}${stat.unit}` }} </span>
</span>
</div>
</section>
</div>
@@ -130,6 +122,11 @@ export default defineComponent({
type: Object as () => Train,
required: true,
},
extended: {
type: Boolean,
default: true,
},
},
mixins: [trainInfoMixin],
@@ -153,9 +150,13 @@ export default defineComponent({
margin-left: 0.5em;
}
.train-image {
.train-stats {
display: flex;
justify-content: center;
align-content: center;
flex-direction: column;
text-align: center;
img {
margin: 0.5em 0;
@@ -163,7 +164,7 @@ export default defineComponent({
}
}
.simple {
.train-info {
display: grid;
grid-template-columns: 2fr 1fr;
grid-template-rows: 1fr;
@@ -258,16 +259,20 @@ export default defineComponent({
}
@include smallScreen() {
.simple {
.train-info {
grid-template-columns: 1fr;
gap: 1em 0;
text-align: center;
font-size: 1.25em;
font-size: 1.15em;
}
.info-stats {
text-align: center;
.train-stats {
font-size: 1.1em;
img {
display: none;
}
}
.timetable_route {
@@ -207,7 +207,6 @@ ul.stock-list {
.schedule-wrapper {
overflow-y: auto;
max-height: 500px;
width: 100%;
z-index: 5;
+15 -11
View File
@@ -1,4 +1,8 @@
<template>
<keep-alive>
<TrainModal v-if="chosenTrain" :chosen-train="chosenTrain" @close-modal="closeTimetable" />
</keep-alive>
<div class="train-table" @keydown.esc="closeTimetable">
<button class="return-btn" @click="scrollToTop" v-if="showReturnButton">
<img :src="icons.arrowAsc" alt="return arrow" />
@@ -17,12 +21,10 @@
class="train-row"
v-for="train in currentTrains"
:key="train.trainNo + train.driverId"
@click="toggleTimetable(train)"
@click.stop="toggleTimetable(train)"
@keydown.enter="toggleTimetable(train)"
>
<TrainInfo :train="train" />
<TrainSchedule v-if="chosenTrainId == getTrainId(train)" :train="train" ref="card-inner" tabindex="0" />
</li>
</ul>
</div>
@@ -43,12 +45,14 @@ import TrainInfo from '@/components/TrainsView/TrainInfo.vue';
import returnBtnMixin from '@/mixins/returnBtnMixin';
import { useStore } from '@/store/store';
import Loading from '../Global/Loading.vue';
import TrainModal from '../Global/TrainModal.vue';
export default defineComponent({
components: {
TrainSchedule,
TrainInfo,
Loading,
TrainModal,
},
mixins: [returnBtnMixin],
@@ -95,6 +99,12 @@ export default defineComponent({
};
},
computed: {
chosenTrain() {
return this.trains.find((train) => train.trainId == this.chosenTrainId);
},
},
activated() {
const query = this.$route.query;
@@ -138,23 +148,17 @@ export default defineComponent({
},
toggleTimetable(train: Train, state?: boolean) {
const id = this.getTrainId(train);
if (state !== undefined) {
this.chosenTrainId = state ? id : null;
this.chosenTrainId = train.trainId;
return;
}
this.chosenTrainId = this.chosenTrainId && this.chosenTrainId == id ? null : id;
this.chosenTrainId = this.chosenTrainId && this.chosenTrainId == train.trainId ? null : train.trainId;
},
closeTimetable() {
this.chosenTrainId = null;
},
getTrainId(train: Train) {
return train.driverName + train.trainNo.toString();
},
},
});
</script>
+2
View File
@@ -1,7 +1,9 @@
import TrainStop from "./TrainStop";
export default interface ScheduledTrain {
trainId: string;
trainNo: number;
driverName: string;
driverId: number;
currentStationName: string;
+2
View File
@@ -1,6 +1,8 @@
import TrainStop from "@/scripts/interfaces/TrainStop";
export default interface Train {
trainId: string;
mass: number;
length: number;
speed: number;
+2
View File
@@ -159,6 +159,8 @@ export function getScheduledTrain(train: Train, trainStopIndex: number, stationN
return {
trainNo: train.trainNo,
trainId: train.trainId,
driverName: train.driverName,
driverId: train.driverId,
currentStationName: train.currentStationName,
+2
View File
@@ -70,6 +70,8 @@ export const useStore = defineStore('store', {
const timetable = train.timetable;
return {
trainId: train.driverName + train.trainNo.toString(),
trainNo: train.trainNo,
mass: train.mass,
length: train.length,
+28
View File
@@ -0,0 +1,28 @@
.badge {
font-weight: 600;
display: inline-block;
padding: 0;
background: #585858;
margin: 0.25em;
span {
display: inline-block;
padding: 0.2em 0.4em;
}
&-none {
font-weight: 600;
padding: 0.2em 0.4em;
background: firebrick;
text-align: center;
@include smallScreen() {
font-size: 1em;
}
}
}