mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 05:18:11 +00:00
chore: journal timetable stop labels
This commit is contained in:
@@ -1,25 +1,77 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="timetable-stops">
|
<div class="timetable-stops">
|
||||||
<div class="stop-list">
|
<ul class="stop-list">
|
||||||
<span
|
<li
|
||||||
v-for="(stop, i) in timetableStops.filter((_, i) =>
|
v-for="(stop, i) in timetableStops.filter((_, i) =>
|
||||||
!showExtraInfo ? i == 0 || i == timetableStops.length - 1 : true
|
!showExtraInfo ? i == 0 || i == timetableStops.length - 1 : true
|
||||||
)"
|
)"
|
||||||
class="stop-list-item"
|
class=""
|
||||||
:key="stop.stopName"
|
:key="stop.stopName"
|
||||||
:data-confirmed="stop.confirmed"
|
|
||||||
>
|
>
|
||||||
<span v-if="i > 0">
|
<span class="stop-label" :data-confirmed="stop.isConfirmed">
|
||||||
>
|
<span class="stop-name">{{ stop.stopName }}</span>
|
||||||
<span v-if="!showExtraInfo && i == 1 && timetableStops.length > 2">
|
|
||||||
... (+{{ timetableStops.length - 2 }}) >
|
<span
|
||||||
|
class="stop-date"
|
||||||
|
v-if="stop.scheduledArrivalTimestamp != 0"
|
||||||
|
:data-delayed="
|
||||||
|
stop.isConfirmed && stop.arrivalTimestamp - stop.scheduledArrivalTimestamp > 0
|
||||||
|
"
|
||||||
|
:data-preponed="
|
||||||
|
stop.isConfirmed &&
|
||||||
|
stop.arrivalTimestamp != 0 &&
|
||||||
|
stop.arrivalTimestamp - stop.scheduledArrivalTimestamp < 0
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-if="stop.isConfirmed && stop.arrivalTimestamp - stop.scheduledArrivalTimestamp != 0"
|
||||||
|
>
|
||||||
|
p. <s>{{ timestampToString(stop.scheduledArrivalTimestamp) }}</s>
|
||||||
|
{{ timestampToString(stop.arrivalTimestamp) }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-else>p. {{ timestampToString(stop.scheduledArrivalTimestamp) }}</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
class="stop-time"
|
||||||
|
v-if="stop.stopTime > 0"
|
||||||
|
:data-stop-ph="stop.stopType.includes('ph')"
|
||||||
|
:data-stop-pt="stop.stopType.includes('pt')"
|
||||||
|
:data-stop-pm="stop.stopType.includes('pm')"
|
||||||
|
>
|
||||||
|
{{ stop.stopTime }} {{ stop.stopType }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
class="stop-date"
|
||||||
|
v-if="
|
||||||
|
stop.scheduledDepartureTimestamp != 0 &&
|
||||||
|
stop.scheduledArrivalTimestamp != stop.scheduledDepartureTimestamp
|
||||||
|
"
|
||||||
|
:data-delayed="
|
||||||
|
stop.isConfirmed && stop.departureTimestamp - stop.scheduledDepartureTimestamp > 0
|
||||||
|
"
|
||||||
|
:data-preponed="
|
||||||
|
stop.isConfirmed &&
|
||||||
|
stop.departureTimestamp != 0 &&
|
||||||
|
stop.departureTimestamp - stop.scheduledDepartureTimestamp < 0
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-if="
|
||||||
|
stop.isConfirmed && stop.departureTimestamp - stop.scheduledDepartureTimestamp != 0
|
||||||
|
"
|
||||||
|
>
|
||||||
|
o. <s>{{ timestampToString(stop.scheduledDepartureTimestamp) }}</s>
|
||||||
|
{{ timestampToString(stop.departureTimestamp) }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-else>o. {{ timestampToString(stop.scheduledDepartureTimestamp) }}</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
</li>
|
||||||
<span class="stop-name">{{ stop.stopName }}</span>
|
</ul>
|
||||||
<span v-html="stop.html"></span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="path-details" v-if="showExtraInfo && timetablePathDetails">
|
<div class="path-details" v-if="showExtraInfo && timetablePathDetails">
|
||||||
<span
|
<span
|
||||||
@@ -29,7 +81,9 @@
|
|||||||
i < timetablePathDetails.length - 1 && timetablePathDetails[i + 1].isVisited
|
i < timetablePathDetails.length - 1 && timetablePathDetails[i + 1].isVisited
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<span class="path-arrival" v-if="pathData.arrival">/ {{ pathData.arrival }} → </span>
|
<span class="path-arrival" v-if="pathData.arrival">
|
||||||
|
/ {{ pathData.arrival }} →
|
||||||
|
</span>
|
||||||
<b class="path-scenery">{{ pathData.sceneryName }}</b>
|
<b class="path-scenery">{{ pathData.sceneryName }}</b>
|
||||||
<span class="path-departure" v-if="pathData.departure">
|
<span class="path-departure" v-if="pathData.departure">
|
||||||
→ {{ pathData.departure }}
|
→ {{ pathData.departure }}
|
||||||
@@ -44,6 +98,17 @@ import { PropType, defineComponent } from 'vue';
|
|||||||
import dateMixin from '../../../mixins/dateMixin';
|
import dateMixin from '../../../mixins/dateMixin';
|
||||||
import { API } from '../../../typings/api';
|
import { API } from '../../../typings/api';
|
||||||
|
|
||||||
|
interface ITimetableStopDetails {
|
||||||
|
stopName: string;
|
||||||
|
arrivalTimestamp: number;
|
||||||
|
scheduledArrivalTimestamp: number;
|
||||||
|
departureTimestamp: number;
|
||||||
|
scheduledDepartureTimestamp: number;
|
||||||
|
stopTime: number;
|
||||||
|
stopType: string;
|
||||||
|
isConfirmed: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [dateMixin],
|
mixins: [dateMixin],
|
||||||
|
|
||||||
@@ -78,58 +143,56 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
timetableStops() {
|
timetableStops(): ITimetableStopDetails[] {
|
||||||
const timetable = this.timetable;
|
const timetable = this.timetable;
|
||||||
|
|
||||||
const stopNames = timetable.sceneriesString.split('%');
|
const stopNames = timetable.sceneriesString.split('%');
|
||||||
|
|
||||||
const beginDateHTML = ` (o. ${
|
return stopNames.reduce<ITimetableStopDetails[]>((acc, stopName, i, arr) => {
|
||||||
timetable.beginDate != timetable.scheduledBeginDate
|
const arrivalDate =
|
||||||
? `<s class="text--grayed">${this.localeTime(timetable.beginDate, this.$i18n.locale)}</s>`
|
i == arr.length - 1
|
||||||
: ''
|
? (timetable.checkpointArrivals.at(i) ?? timetable.endDate)
|
||||||
} <span>${this.localeTime(timetable.scheduledBeginDate, this.$i18n.locale)}</span>)`;
|
: timetable.checkpointArrivals.at(i);
|
||||||
|
|
||||||
const endDateHTML = ` (p. ${
|
const scheduledArrivalDate =
|
||||||
timetable.endDate != timetable.scheduledEndDate && timetable.fulfilled
|
i == arr.length - 1
|
||||||
? `<s class="text--grayed">${this.localeTime(timetable.endDate, this.$i18n.locale)}</s>`
|
? (timetable.checkpointArrivalsScheduled.at(i) ?? timetable.scheduledEndDate)
|
||||||
: ''
|
: timetable.checkpointArrivalsScheduled.at(i);
|
||||||
} <span>${this.localeTime(timetable.scheduledEndDate, this.$i18n.locale)}</span>)`;
|
|
||||||
|
|
||||||
return stopNames.map((stopName, i) => {
|
const departureDate =
|
||||||
const confirmed = i < timetable.confirmedStopsCount;
|
i == 0
|
||||||
if (i == 0) return { stopName, html: beginDateHTML, confirmed };
|
? (timetable.checkpointDepartures.at(i) ?? timetable.beginDate)
|
||||||
if (i == stopNames.length - 1) return { stopName, html: endDateHTML, confirmed };
|
: timetable.checkpointDepartures.at(i);
|
||||||
|
|
||||||
const departureDateScheduled = this.stringToDate(
|
const scheduledDepartureDate =
|
||||||
timetable.checkpointDeparturesScheduled?.at(i)
|
i == 0
|
||||||
);
|
? (timetable.checkpointDeparturesScheduled.at(i) ?? timetable.scheduledBeginDate)
|
||||||
const departureDateReal = this.stringToDate(timetable.checkpointDepartures?.at(i));
|
: timetable.checkpointDeparturesScheduled.at(i);
|
||||||
const arrivalDateScheduled = this.stringToDate(
|
|
||||||
timetable.checkpointArrivalsScheduled?.at(i)
|
const stopTime = Number(timetable.checkpointStopTypes.at(i)?.split(',')[0]) || 0;
|
||||||
);
|
const stopType = timetable.checkpointStopTypes.at(i)?.split(',')[1] || '';
|
||||||
const arrivalDateReal = this.stringToDate(timetable.checkpointArrivals?.at(i));
|
|
||||||
const arrivalHTML =
|
acc.push({
|
||||||
(arrivalDateReal &&
|
stopName,
|
||||||
arrivalDateScheduled &&
|
arrivalTimestamp: this.dateStringToTimestamp(arrivalDate),
|
||||||
arrivalDateReal?.getTime() != arrivalDateScheduled?.getTime()
|
scheduledArrivalTimestamp: this.dateStringToTimestamp(scheduledArrivalDate),
|
||||||
? `<s class="text--grayed">${this.parseDateToTimeString(arrivalDateScheduled)}</s> `
|
departureTimestamp: this.dateStringToTimestamp(departureDate),
|
||||||
: '') + this.parseDateToTimeString(arrivalDateReal || arrivalDateScheduled);
|
scheduledDepartureTimestamp: this.dateStringToTimestamp(scheduledDepartureDate),
|
||||||
const departureHTML =
|
stopTime,
|
||||||
(departureDateReal &&
|
stopType,
|
||||||
departureDateScheduled &&
|
isConfirmed: i < timetable.confirmedStopsCount
|
||||||
departureDateReal?.getTime() != departureDateScheduled?.getTime()
|
});
|
||||||
? `<s class="text--grayed">${this.parseDateToTimeString(departureDateScheduled)}</s> `
|
|
||||||
: '') + this.parseDateToTimeString(departureDateReal || departureDateScheduled);
|
return acc;
|
||||||
let html = `${arrivalHTML}${departureHTML ? ` / ${departureHTML}` : ''}`;
|
}, []);
|
||||||
if (html) html = ` (${html})`;
|
|
||||||
return { stopName, html, confirmed };
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import '../../../styles/badge.scss';
|
||||||
|
|
||||||
.timetable-stops {
|
.timetable-stops {
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
gap: 0.25em;
|
gap: 0.25em;
|
||||||
@@ -138,12 +201,63 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.stop-list {
|
.stop-list {
|
||||||
&-item[data-confirmed='true'] {
|
display: flex;
|
||||||
color: lightgreen;
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5em;
|
||||||
|
padding: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
.stop-name {
|
.stop-label {
|
||||||
font-weight: bold;
|
display: flex;
|
||||||
}
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
&[data-confirmed='true'] > .stop-name {
|
||||||
|
color: lightgreen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stop-label > span {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.3em 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stop-name {
|
||||||
|
background-color: #2b2b2b;
|
||||||
|
border-radius: 0.5em 0 0 0.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stop-date {
|
||||||
|
background-color: #444;
|
||||||
|
padding: 0.3em 0.5em;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-radius: 0 0.5em 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-delayed='true'] {
|
||||||
|
color: salmon;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-preponed='true'] {
|
||||||
|
color: lightgreen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stop-time {
|
||||||
|
background-color: #252525;
|
||||||
|
|
||||||
|
&[data-stop-ph='true'],
|
||||||
|
&[data-stop-pm='true'] {
|
||||||
|
background-color: #db8e29;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
:key="spawn.spawnName + onlineScenery?.dispatcherName + i"
|
:key="spawn.spawnName + onlineScenery?.dispatcherName + i"
|
||||||
:data-electrified="spawn.isElectrified"
|
:data-electrified="spawn.isElectrified"
|
||||||
>
|
>
|
||||||
<span class="name">{{ spawn.spawnName }}</span>
|
<span class="stop-name">{{ spawn.spawnName }}</span>
|
||||||
<span class="length">{{ spawn.spawnLength }}m</span>
|
<span class="length">{{ spawn.spawnLength }}m</span>
|
||||||
</li>
|
</li>
|
||||||
</transition-group>
|
</transition-group>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
:data-minor="stop.isSBL || (stop.nameRaw.endsWith(', po') && !stop.duration)"
|
:data-minor="stop.isSBL || (stop.nameRaw.endsWith(', po') && !stop.duration)"
|
||||||
>
|
>
|
||||||
<router-link v-if="/(, podg$|<strong>)/.test(stop.nameHtml)" :to="sceneryHref">
|
<router-link v-if="/(, podg$|<strong>)/.test(stop.nameHtml)" :to="sceneryHref">
|
||||||
<span class="name" v-html="stop.nameHtml"></span>
|
<span class="stop-name" v-html="stop.nameHtml"></span>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<span v-else class="name" v-html="stop.nameHtml"></span>
|
<span v-else class="stop-name" v-html="stop.nameHtml"></span>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
v-if="stop.position != 'begin'"
|
v-if="stop.position != 'begin'"
|
||||||
@@ -107,7 +107,7 @@ s {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.name {
|
.stop-name {
|
||||||
background: $stopNameClr;
|
background: $stopNameClr;
|
||||||
border-radius: 0.5em 0 0 0.5em;
|
border-radius: 0.5em 0 0 0.5em;
|
||||||
padding: 0.3em 0.5em;
|
padding: 0.3em 0.5em;
|
||||||
@@ -134,7 +134,7 @@ s {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.name {
|
.stop-name {
|
||||||
background: none;
|
background: none;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ export default defineComponent({
|
|||||||
: '';
|
: '';
|
||||||
},
|
},
|
||||||
|
|
||||||
|
dateStringToTimestamp(dateString?: string) {
|
||||||
|
return dateString ? new Date(dateString).getTime() : 0;
|
||||||
|
},
|
||||||
|
|
||||||
calculateDuration(timestampMs: number, showSeconds = false) {
|
calculateDuration(timestampMs: number, showSeconds = false) {
|
||||||
const secondsTotal = Math.floor(timestampMs / 1000);
|
const secondsTotal = Math.floor(timestampMs / 1000);
|
||||||
const minsTotal = Math.round(timestampMs / 60000);
|
const minsTotal = Math.round(timestampMs / 60000);
|
||||||
@@ -70,8 +74,8 @@ export default defineComponent({
|
|||||||
minsInHour
|
minsInHour
|
||||||
)}`
|
)}`
|
||||||
: showSeconds && secondsTotal <= 60
|
: showSeconds && secondsTotal <= 60
|
||||||
? this.$t('journal.seconds', { value: secondsTotal }, secondsTotal)
|
? this.$t('journal.seconds', { value: secondsTotal }, secondsTotal)
|
||||||
: this.$t('journal.minutes', { value: minsTotal }, minsTotal);
|
: this.$t('journal.minutes', { value: minsTotal }, minsTotal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
@import 'variables.scss';
|
@import 'variables.scss';
|
||||||
|
@import 'responsive.scss';
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|||||||
+8
-10
@@ -246,8 +246,6 @@ export namespace API {
|
|||||||
authorName?: string;
|
authorName?: string;
|
||||||
authorId?: number;
|
authorId?: number;
|
||||||
|
|
||||||
stopsString?: string;
|
|
||||||
|
|
||||||
stockString?: string;
|
stockString?: string;
|
||||||
stockHistory: string[];
|
stockHistory: string[];
|
||||||
|
|
||||||
@@ -255,16 +253,16 @@ export namespace API {
|
|||||||
stockLength?: number;
|
stockLength?: number;
|
||||||
maxSpeed?: number;
|
maxSpeed?: number;
|
||||||
|
|
||||||
hashesString?: string;
|
|
||||||
currentSceneryName?: string;
|
currentSceneryName?: string;
|
||||||
currentSceneryHash?: string;
|
currentSceneryHash?: string;
|
||||||
routeSceneries?: string;
|
routeSceneries: string;
|
||||||
checkpointArrivals?: string[];
|
checkpointArrivals: string[];
|
||||||
checkpointDepartures?: string[];
|
checkpointDepartures: string[];
|
||||||
checkpointArrivalsScheduled?: string[];
|
checkpointArrivalsScheduled: string[];
|
||||||
checkpointDeparturesScheduled?: string[];
|
checkpointDeparturesScheduled: string[];
|
||||||
checkpointStopTypes?: string[];
|
checkpointStopTypes: string[];
|
||||||
visitedSceneries?: string[];
|
visitedSceneries: string[];
|
||||||
|
sceneryNames: string[];
|
||||||
path: string;
|
path: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user