mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 13:28:11 +00:00
srjp: poprawki dostępności modalu
This commit is contained in:
@@ -29,9 +29,8 @@
|
|||||||
<span
|
<span
|
||||||
class="general-train"
|
class="general-train"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@click.stop="showTimetable(timetable)"
|
@click.stop="showTimetable(timetable, $event.currentTarget)"
|
||||||
@keydown.enter="showTimetable(timetable)"
|
@keydown.enter="showTimetable(timetable, $event.currentTarget)"
|
||||||
style="cursor: pointer"
|
|
||||||
>
|
>
|
||||||
<span class="text--grayed">#{{ timetable.id }}</span>
|
<span class="text--grayed">#{{ timetable.id }}</span>
|
||||||
|
|
||||||
@@ -360,10 +359,10 @@ export default defineComponent({
|
|||||||
return { stopName, html, confirmed };
|
return { stopName, html, confirmed };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
showTimetable(timetable: TimetableHistory) {
|
showTimetable(timetable: TimetableHistory, target: EventTarget | null) {
|
||||||
if (!timetable) return;
|
if (timetable?.terminated) return;
|
||||||
if (timetable.terminated) return;
|
|
||||||
this.selectModalTrain(timetable.driverName + timetable.trainNo.toString());
|
this.selectModalTrain(timetable.driverName + timetable.trainNo.toString(), target);
|
||||||
},
|
},
|
||||||
onImageError(e: Event) {
|
onImageError(e: Event) {
|
||||||
const imageEl = e.target as HTMLImageElement;
|
const imageEl = e.target as HTMLImageElement;
|
||||||
@@ -437,6 +436,7 @@ hr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.general-train {
|
.general-train {
|
||||||
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -1,133 +1,131 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="info-user-list">
|
<section class="info-user-list">
|
||||||
<h3 class="user-header section-header">
|
<h3 class="user-header section-header">
|
||||||
<img :src="getIcon('user')" alt="icon-user" />
|
<img :src="getIcon('user')" alt="icon-user" />
|
||||||
{{ $t('scenery.users') }}
|
{{ $t('scenery.users') }}
|
||||||
<span class="text--primary">{{ station.onlineInfo?.currentUsers || '0' }}</span
|
<span class="text--primary">{{ station.onlineInfo?.currentUsers || '0' }}</span
|
||||||
> / <span class="text--primary">{{ station.onlineInfo?.maxUsers || '0' }}</span>
|
> / <span class="text--primary">{{ station.onlineInfo?.maxUsers || '0' }}</span>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-for="(train, i) in computedStationTrains"
|
v-for="(train, i) in computedStationTrains"
|
||||||
class="badge user"
|
class="badge user"
|
||||||
:class="train.stopStatus"
|
:class="train.stopStatus"
|
||||||
:key="train.trainId"
|
:key="train.trainId"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@click="selectModalTrain(train.trainId)"
|
@click.prevent="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||||
@keydown.enter="selectModalTrain(train.trainId)"
|
@keydown.enter="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||||
>
|
>
|
||||||
<span class="user_train">{{ train.trainNo }}</span>
|
<span class="user_train">{{ train.trainNo }}</span>
|
||||||
<span class="user_name">{{ train.driverName }}</span>
|
<span class="user_name">{{ train.driverName }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="badge user badge-none" v-if="!computedStationTrains || computedStationTrains.length == 0">
|
<div class="badge user badge-none" v-if="!computedStationTrains || computedStationTrains.length == 0">
|
||||||
{{ $t('scenery.no-users') }}
|
{{ $t('scenery.no-users') }}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent } from 'vue';
|
||||||
import { computed, defineComponent } from 'vue';
|
import imageMixin from '../../../mixins/imageMixin';
|
||||||
import imageMixin from '../../../mixins/imageMixin';
|
import modalTrainMixin from '../../../mixins/modalTrainMixin';
|
||||||
import modalTrainMixin from '../../../mixins/modalTrainMixin';
|
import routerMixin from '../../../mixins/routerMixin';
|
||||||
import routerMixin from '../../../mixins/routerMixin';
|
import Station from '../../../scripts/interfaces/Station';
|
||||||
import Station from '../../../scripts/interfaces/Station';
|
import { useStore } from '../../../store/store';
|
||||||
import { useStore } from '../../../store/store';
|
|
||||||
|
export default defineComponent({
|
||||||
export default defineComponent({
|
mixins: [routerMixin, imageMixin, modalTrainMixin],
|
||||||
mixins: [routerMixin, imageMixin, modalTrainMixin],
|
|
||||||
|
props: {
|
||||||
props: {
|
station: {
|
||||||
station: {
|
type: Object as () => Station,
|
||||||
type: Object as () => Station,
|
default: {},
|
||||||
default: {},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
setup(props) {
|
||||||
setup(props) {
|
const store = useStore();
|
||||||
const store = useStore();
|
|
||||||
|
const computedStationTrains = computed(() => {
|
||||||
const computedStationTrains = computed(() => {
|
if (!props.station) return [];
|
||||||
if (!props.station) return [];
|
|
||||||
|
const station = props.station as Station;
|
||||||
const station = props.station as Station;
|
if (!station.onlineInfo) return [];
|
||||||
if (!station.onlineInfo) return [];
|
if (!station.onlineInfo.stationTrains) return [];
|
||||||
if (!station.onlineInfo.stationTrains) return [];
|
|
||||||
|
return station.onlineInfo.stationTrains.map((train) => {
|
||||||
return station.onlineInfo.stationTrains.map((train) => {
|
const scheduledTrainStatus = station.onlineInfo?.scheduledTrains?.find((st) => st.trainNo === train.trainNo);
|
||||||
const scheduledTrainStatus = station.onlineInfo?.scheduledTrains?.find((st) => st.trainNo === train.trainNo);
|
|
||||||
|
return {
|
||||||
return {
|
...train,
|
||||||
...train,
|
stopStatus: scheduledTrainStatus?.stopStatus || 'no-timetable',
|
||||||
stopStatus: scheduledTrainStatus?.stopStatus || 'no-timetable',
|
};
|
||||||
};
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
return { computedStationTrains, store };
|
||||||
return { computedStationTrains, store };
|
},
|
||||||
},
|
});
|
||||||
});
|
</script>
|
||||||
</script>
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
<style lang="scss" scoped>
|
$no-timetable: #aaa;
|
||||||
$no-timetable: #aaa;
|
$departed: springgreen;
|
||||||
$departed: springgreen;
|
$stopped: #ffa600;
|
||||||
$stopped: #ffa600;
|
$online: gold;
|
||||||
$online: gold;
|
$terminated: salmon;
|
||||||
$terminated: salmon;
|
$disconnected: slategray;
|
||||||
$disconnected: slategray;
|
|
||||||
|
.info-user-list {
|
||||||
.info-user-list {
|
width: 100%;
|
||||||
width: 100%;
|
|
||||||
|
ul {
|
||||||
ul {
|
display: flex;
|
||||||
display: flex;
|
flex-wrap: wrap;
|
||||||
flex-wrap: wrap;
|
justify-content: center;
|
||||||
justify-content: center;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
.user {
|
||||||
.user {
|
cursor: pointer;
|
||||||
cursor: pointer;
|
|
||||||
|
&_train {
|
||||||
&_train {
|
color: black;
|
||||||
color: black;
|
background-color: $no-timetable;
|
||||||
background-color: $no-timetable;
|
|
||||||
|
transition: background-color 200ms;
|
||||||
transition: background-color 200ms;
|
-ms-transition: background-color 200ms;
|
||||||
-ms-transition: background-color 200ms;
|
-webkit-transition: background-color 200ms;
|
||||||
-webkit-transition: background-color 200ms;
|
}
|
||||||
}
|
|
||||||
|
&.no-timetable .user_train {
|
||||||
&.no-timetable .user_train {
|
background-color: $no-timetable;
|
||||||
background-color: $no-timetable;
|
}
|
||||||
}
|
|
||||||
|
&.departed > &_train {
|
||||||
&.departed > &_train {
|
background-color: $departed;
|
||||||
background-color: $departed;
|
}
|
||||||
}
|
|
||||||
|
&.stopped > &_train {
|
||||||
&.stopped > &_train {
|
background-color: $stopped;
|
||||||
background-color: $stopped;
|
}
|
||||||
}
|
|
||||||
|
&.online > &_train {
|
||||||
&.online > &_train {
|
background-color: $online;
|
||||||
background-color: $online;
|
}
|
||||||
}
|
|
||||||
|
&.terminated > &_train {
|
||||||
&.terminated > &_train {
|
background-color: $terminated;
|
||||||
background-color: $terminated;
|
}
|
||||||
}
|
|
||||||
|
&.disconnected > &_train {
|
||||||
&.disconnected > &_train {
|
background-color: $disconnected;
|
||||||
background-color: $disconnected;
|
}
|
||||||
}
|
|
||||||
|
&.offline {
|
||||||
&.offline {
|
background: firebrick;
|
||||||
background: firebrick;
|
pointer-events: none;
|
||||||
pointer-events: none;
|
}
|
||||||
}
|
}
|
||||||
}
|
</style>
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|||||||
@@ -67,8 +67,8 @@
|
|||||||
v-for="(scheduledTrain, i) in computedScheduledTrains"
|
v-for="(scheduledTrain, i) in computedScheduledTrains"
|
||||||
:key="scheduledTrain.trainId"
|
:key="scheduledTrain.trainId"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@click.prevent.stop="selectModalTrain(scheduledTrain.trainId)"
|
@click.prevent.stop="selectModalTrain(scheduledTrain.trainId, $event.currentTarget)"
|
||||||
@keydown.enter.prevent="selectModalTrain(scheduledTrain.trainId)"
|
@keydown.enter.prevent="selectModalTrain(scheduledTrain.trainId, $event.currentTarget)"
|
||||||
>
|
>
|
||||||
<span class="timetable-general">
|
<span class="timetable-general">
|
||||||
<span class="general-info">
|
<span class="general-info">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="train-info" tabindex="0">
|
<div class="train-info">
|
||||||
<section class="train-route">
|
<section class="train-route">
|
||||||
<div class="train_general">
|
<div class="train_general">
|
||||||
<b class="warning-timeout" v-if="train.isTimeout" :title="$t('trains.timeout')">?</b>
|
<b class="warning-timeout" v-if="train.isTimeout" :title="$t('trains.timeout')">?</b>
|
||||||
@@ -41,13 +41,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="timetable_progress" style="margin-top: 0.5em" v-if="train.timetableData">
|
<div class="timetable_progress" style="margin-top: 0.5em" v-if="train.timetableData">
|
||||||
<!-- <span class="timetable_progress-bar">
|
|
||||||
<span class="bar-bg"></span>
|
|
||||||
<span
|
|
||||||
class="bar-fg"
|
|
||||||
:style="{ width: `${Math.floor(confirmedPercentage(train.timetableData.followingStops))}%` }"
|
|
||||||
></span>
|
|
||||||
</span> -->
|
|
||||||
<ProgressBar :progressPercent="confirmedPercentage(train.timetableData.followingStops)" />
|
<ProgressBar :progressPercent="confirmedPercentage(train.timetableData.followingStops)" />
|
||||||
|
|
||||||
<span class="timetable_progress-distance">
|
<span class="timetable_progress-distance">
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
class="train-row"
|
class="train-row"
|
||||||
v-for="train in currentTrains"
|
v-for="train in currentTrains"
|
||||||
:key="train.trainId"
|
:key="train.trainId"
|
||||||
@click.stop="selectModalTrain(train.trainId)"
|
tabindex="0"
|
||||||
@keydown.enter="selectModalTrain(train.trainId)"
|
@click.stop="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||||
|
@keydown.enter="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||||
>
|
>
|
||||||
<TrainInfo :train="train" />
|
<TrainInfo :train="train" />
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { Ref, defineComponent } from 'vue';
|
||||||
import { useStore } from '../store/store';
|
import { useStore } from '../store/store';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@@ -15,15 +15,17 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
selectModalTrain(trainId: string) {
|
selectModalTrain(trainId: string, target?: EventTarget | null) {
|
||||||
this.store.chosenModalTrainId = trainId;
|
this.store.chosenModalTrainId = trainId;
|
||||||
document.body.classList.add('no-scroll');
|
document.body.classList.add('no-scroll');
|
||||||
|
if (target) this.store.modalLastClickedTarget = target;
|
||||||
},
|
},
|
||||||
|
|
||||||
closeModal() {
|
closeModal() {
|
||||||
this.store.chosenModalTrainId = undefined;
|
this.store.chosenModalTrainId = undefined;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
(this.store.modalLastClickedTarget as any)?.focus();
|
||||||
document.body.classList.remove('no-scroll');
|
document.body.classList.remove('no-scroll');
|
||||||
}, 150);
|
}, 150);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import Station from '../Station';
|
|||||||
import Train from '../Train';
|
import Train from '../Train';
|
||||||
import { DispatcherStatsAPIData } from '../api/DispatcherStatsAPIData';
|
import { DispatcherStatsAPIData } from '../api/DispatcherStatsAPIData';
|
||||||
import { DriverStatsAPIData } from '../api/DriverStatsAPIData';
|
import { DriverStatsAPIData } from '../api/DriverStatsAPIData';
|
||||||
|
import { Ref } from 'vue';
|
||||||
|
|
||||||
export type Availability = 'default' | 'unavailable' | 'nonPublic' | 'abandoned' | 'nonDefault';
|
export type Availability = 'default' | 'unavailable' | 'nonPublic' | 'abandoned' | 'nonDefault';
|
||||||
|
|
||||||
@@ -46,6 +47,7 @@ export interface StoreState {
|
|||||||
|
|
||||||
listenerLaunched: boolean;
|
listenerLaunched: boolean;
|
||||||
blockScroll: boolean;
|
blockScroll: boolean;
|
||||||
|
modalLastClickedTarget: EventTarget | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface APIData {
|
export interface APIData {
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ export const useStore = defineStore('store', {
|
|||||||
|
|
||||||
blockScroll: false,
|
blockScroll: false,
|
||||||
listenerLaunched: false,
|
listenerLaunched: false,
|
||||||
|
modalLastClickedTarget: null
|
||||||
} as StoreState),
|
} as StoreState),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
Reference in New Issue
Block a user