mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 05:18:11 +00:00
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.28.0",
|
"version": "1.28.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="144" height="144" viewBox="0 0 144 144" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M82.7143 61.3284L118.429 7L22 74.9104H68.4286L36.2857 137L122 61.3284H82.7143Z" fill="#FFF500"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 213 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="144" height="144" viewBox="0 0 144 144" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="9.20437" y="2.4661" width="36.5457" height="57.8287" rx="16.7449" transform="matrix(0.869001 -0.494811 0.505207 0.862998 50.006 87.4256)" stroke="white" stroke-width="13.3959"/>
|
||||||
|
<rect x="9.20437" y="2.4661" width="36.5457" height="57.8287" rx="16.7449" transform="matrix(0.869001 -0.494811 0.505207 0.862998 14.9599 29.6039)" stroke="white" stroke-width="13.3959"/>
|
||||||
|
<path d="M65.1133 58.145L79.8524 84.3103" stroke="white" stroke-width="10.0469" stroke-linecap="round" stroke-linejoin="bevel"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 611 B |
@@ -81,6 +81,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
window.addEventListener('mousemove', (e: MouseEvent) => this.tooltipStore.handle(e));
|
window.addEventListener('mousemove', (e: MouseEvent) => this.tooltipStore.handle(e));
|
||||||
|
window.addEventListener('mousedown', () => this.tooltipStore.hide());
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -1,21 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="stock-list">
|
<div class="stock-list">
|
||||||
<ul>
|
<ul>
|
||||||
<li
|
<li v-for="({ images, imagesFallbacks, vehicleString }, i) in thumbnailNames" :key="i">
|
||||||
v-for="(
|
|
||||||
{ vehicleName, vehicleCargo, images, imagesFallbacks, vehicleString }, i
|
|
||||||
) in thumbnailNames"
|
|
||||||
:key="i"
|
|
||||||
>
|
|
||||||
<div class="stock-text">
|
|
||||||
<div>{{ vehicleName.replace(/_/g, ' ') }}</div>
|
|
||||||
<small v-if="vehicleCargo">({{ vehicleCargo }})</small>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span>
|
<span>
|
||||||
<VehicleThumbnail
|
<VehicleThumbnail
|
||||||
v-for="(thumbnailImage, imageIndex) in images"
|
v-for="(thumbnailImage, imageIndex) in images"
|
||||||
:vehicle-name="vehicleString"
|
:vehicle-string="vehicleString"
|
||||||
:img-name="thumbnailImage"
|
:img-name="thumbnailImage"
|
||||||
:fallback-name="imagesFallbacks[imageIndex]"
|
:fallback-name="imagesFallbacks[imageIndex]"
|
||||||
/>
|
/>
|
||||||
@@ -59,13 +49,12 @@ export default defineComponent({
|
|||||||
return (this.tractionOnly ? this.trainStockList.slice(0, 1) : this.trainStockList)
|
return (this.tractionOnly ? this.trainStockList.slice(0, 1) : this.trainStockList)
|
||||||
.filter((v) => v.length != 0)
|
.filter((v) => v.length != 0)
|
||||||
.map((vehicleString) => {
|
.map((vehicleString) => {
|
||||||
const [vehicleName, vehicleCargo] = vehicleString.split(':');
|
const [vehicleName] = vehicleString.split(':');
|
||||||
|
|
||||||
const vehicleThumbnailData = {
|
const vehicleThumbnailData = {
|
||||||
images: [] as string[],
|
images: [] as string[],
|
||||||
imagesFallbacks: [] as string[],
|
imagesFallbacks: [] as string[],
|
||||||
vehicleName,
|
vehicleName,
|
||||||
vehicleCargo,
|
|
||||||
vehicleString
|
vehicleString
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -187,12 +176,4 @@ ul > li > span {
|
|||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
cursor: crosshair;
|
cursor: crosshair;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stock-text {
|
|
||||||
text-align: center;
|
|
||||||
color: #aaa;
|
|
||||||
font-size: 0.9em;
|
|
||||||
margin-bottom: 0.25em;
|
|
||||||
padding: 0.25em 0;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="vehicle-thumbnail" :data-load-status="imgStatus">
|
<div class="vehicle-thumbnail" :data-load-status="imgStatus" ref="thumbRef">
|
||||||
|
<div class="stock-text">
|
||||||
|
<div>{{ vehicleName }}</div>
|
||||||
|
<small v-if="vehicleCargo">({{ vehicleCargo }})</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
<img
|
<img
|
||||||
ref="imgRef"
|
|
||||||
:src="`https://static.spythere.eu/thumbnails/v2/${imgName}.png`"
|
:src="`https://static.spythere.eu/thumbnails/v2/${imgName}.png`"
|
||||||
height="60"
|
height="60"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
data-tooltip-type="VehiclePreviewTooltip"
|
data-tooltip-type="VehiclePreviewTooltip"
|
||||||
:data-tooltip-content="vehicleName"
|
:data-tooltip-content="vehicleString"
|
||||||
@error="onImageError"
|
@error="onImageError"
|
||||||
@load="onImageLoad"
|
@load="onImageLoad"
|
||||||
/>
|
/>
|
||||||
@@ -14,19 +18,21 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Ref, ref } from 'vue';
|
import { computed, Ref, ref } from 'vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
vehicleName: { type: String, required: true },
|
vehicleString: { type: String, required: true },
|
||||||
imgName: { type: String, required: true },
|
imgName: { type: String, required: true },
|
||||||
fallbackName: { type: String, required: true },
|
fallbackName: { type: String, required: true },
|
||||||
placeholderName: String
|
placeholderName: String
|
||||||
});
|
});
|
||||||
|
|
||||||
const imgRef = ref(null) as Ref<HTMLElement | null>;
|
const thumbRef = ref(null) as Ref<HTMLElement | null>;
|
||||||
|
|
||||||
const imgStatus = ref('loading');
|
const imgStatus = ref('loading');
|
||||||
|
|
||||||
|
const vehicleName = computed(() => props.vehicleString.split(':')[0].replace(/_/g, ' '));
|
||||||
|
const vehicleCargo = computed(() => props.vehicleString.split(':')[1]);
|
||||||
|
|
||||||
function onImageError(event: Event) {
|
function onImageError(event: Event) {
|
||||||
(event.target as HTMLImageElement).src = `/images/${props.fallbackName}.png`;
|
(event.target as HTMLImageElement).src = `/images/${props.fallbackName}.png`;
|
||||||
imgStatus.value = 'error';
|
imgStatus.value = 'error';
|
||||||
@@ -37,13 +43,15 @@ function onImageLoad() {
|
|||||||
imgStatus.value = 'loaded';
|
imgStatus.value = 'loaded';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imgRef.value) imgRef.value.style.opacity = '1';
|
if (thumbRef.value) thumbRef.value.style.opacity = '1';
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.vehicle-thumbnail {
|
.vehicle-thumbnail {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 100ms ease-in-out;
|
||||||
|
|
||||||
&[data-load-status='loading'] {
|
&[data-load-status='loading'] {
|
||||||
min-height: 60px;
|
min-height: 60px;
|
||||||
@@ -51,8 +59,11 @@ function onImageLoad() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
.stock-text {
|
||||||
opacity: 0;
|
text-align: center;
|
||||||
transition: opacity 100ms ease-in-out;
|
color: #aaa;
|
||||||
|
font-size: 0.9em;
|
||||||
|
margin-bottom: 0.25em;
|
||||||
|
padding: 0.25em 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -91,10 +91,6 @@ export default defineComponent({
|
|||||||
deep: true,
|
deep: true,
|
||||||
handler() {
|
handler() {
|
||||||
this.extraInfoIndexes.length = 0;
|
this.extraInfoIndexes.length = 0;
|
||||||
|
|
||||||
this.$nextTick(() => {
|
|
||||||
console.log(this.$el.querySelector('ul'));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -32,12 +32,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.tooltip-content {
|
.tooltip-content {
|
||||||
width: 300px;
|
width: 200px;
|
||||||
|
|
||||||
padding: 0.25em 0.5em;
|
padding: 0.25em 0.5em;
|
||||||
border-radius: 0.25em;
|
border-radius: 0.25em;
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
background-color: #1b1b1b;
|
background-color: #1b1b1b;
|
||||||
box-shadow: 0 0 5px 2px #aaa;
|
box-shadow: 0 0 5px 2px #aaa;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,12 +32,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.tooltip-content {
|
.tooltip-content {
|
||||||
width: 300px;
|
width: 200px;
|
||||||
|
|
||||||
padding: 0.25em 0.5em;
|
padding: 0.25em 0.5em;
|
||||||
border-radius: 0.25em;
|
border-radius: 0.25em;
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
background-color: #1b1b1b;
|
background-color: #1b1b1b;
|
||||||
box-shadow: 0 0 5px 2px #aaa;
|
box-shadow: 0 0 5px 2px #aaa;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,9 +77,11 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
vehicleCargo() {
|
vehicleCargo() {
|
||||||
return this.vehicleData?.group.cargoTypes?.find(
|
const x = this.vehicleData?.group.cargoTypes?.find(
|
||||||
(c) => c.id == this.tooltipStore.content.split(':')[1]
|
(c) => c.id == this.tooltipStore.content.split(':')[1]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PropType, defineComponent } from 'vue';
|
import { PropType, defineComponent } from 'vue';
|
||||||
import dateMixin from '../../mixins/dateMixin';
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
import { TrainScheduleStop } from './TrainSchedule.vue';
|
import { TrainScheduleStop } from './typings';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [dateMixin],
|
mixins: [dateMixin],
|
||||||
|
|||||||
@@ -55,12 +55,28 @@
|
|||||||
<span>{{ stop.departureLine }}</span>
|
<span>{{ stop.departureLine }}</span>
|
||||||
<span v-if="stop.departureLineInfo">
|
<span v-if="stop.departureLineInfo">
|
||||||
| {{ stop.departureLineInfo.routeSpeed }}
|
| {{ stop.departureLineInfo.routeSpeed }}
|
||||||
<span v-if="stop.departureLineInfo.isElectric">⚡</span>
|
|
||||||
<img
|
<img
|
||||||
v-else
|
:src="
|
||||||
src="/images/icon-we4a.png"
|
stop.departureLineInfo.isElectric
|
||||||
:title="$t('trains.we4a-tooltip')"
|
? '/images/icon-catenary.svg'
|
||||||
|
: '/images/icon-we4a.png'
|
||||||
|
"
|
||||||
width="10"
|
width="10"
|
||||||
|
data-tooltip-type="BaseTooltip"
|
||||||
|
:data-tooltip-content="
|
||||||
|
$t(
|
||||||
|
`trains.${!stop.departureLineInfo.isElectric ? 'no-' : ''}catenary-tooltip`
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<img
|
||||||
|
v-if="stop.departureLineInfo.isRouteSBL"
|
||||||
|
src="/images/icon-sbl-transparent.svg"
|
||||||
|
width="10"
|
||||||
|
data-tooltip-type="BaseTooltip"
|
||||||
|
:data-tooltip-content="$t('trains.sbl-tooltip')"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -71,7 +87,7 @@
|
|||||||
>
|
>
|
||||||
<span>{{ scheduleStops[i + 1].sceneryName }}</span>
|
<span>{{ scheduleStops[i + 1].sceneryName }}</span>
|
||||||
<span v-if="stop.departureLineInfo?.routeTracks == 1"> ↕</span>
|
<span v-if="stop.departureLineInfo?.routeTracks == 1"> ↕</span>
|
||||||
<span v-else> ⇅</span>
|
<span v-else> ⇵</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="scenery-route">
|
<div class="scenery-route">
|
||||||
@@ -79,13 +95,29 @@
|
|||||||
|
|
||||||
<span v-if="scheduleStops[i + 1].arrivalLineInfo">
|
<span v-if="scheduleStops[i + 1].arrivalLineInfo">
|
||||||
| {{ scheduleStops[i + 1].arrivalLineInfo!.routeSpeed }}
|
| {{ scheduleStops[i + 1].arrivalLineInfo!.routeSpeed }}
|
||||||
<span v-if="scheduleStops[i + 1].arrivalLineInfo!.isElectric">⚡</span>
|
|
||||||
<img
|
<img
|
||||||
v-else
|
:src="
|
||||||
src="/images/icon-we4a.png"
|
scheduleStops[i + 1].arrivalLineInfo!.isElectric
|
||||||
:title="$t('trains.we4a-tooltip')"
|
? '/images/icon-catenary.svg'
|
||||||
|
: '/images/icon-we4a.png'
|
||||||
|
"
|
||||||
|
data-tooltip-type="BaseTooltip"
|
||||||
|
:data-tooltip-content="
|
||||||
|
$t(
|
||||||
|
`trains.${!scheduleStops[i + 1].arrivalLineInfo!.isElectric ? 'no-' : ''}catenary-tooltip`
|
||||||
|
)
|
||||||
|
"
|
||||||
width="10"
|
width="10"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<img
|
||||||
|
v-if="scheduleStops[i + 1].arrivalLineInfo!.isRouteSBL"
|
||||||
|
src="/images/icon-sbl-transparent.svg"
|
||||||
|
width="10"
|
||||||
|
data-tooltip-type="BaseTooltip"
|
||||||
|
:data-tooltip-content="$t('trains.sbl-tooltip')"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
@@ -105,43 +137,7 @@ import StockList from '../Global/StockList.vue';
|
|||||||
import { useMainStore } from '../../store/mainStore';
|
import { useMainStore } from '../../store/mainStore';
|
||||||
import { useApiStore } from '../../store/apiStore';
|
import { useApiStore } from '../../store/apiStore';
|
||||||
import { StationRoutesInfo, Train } from '../../typings/common';
|
import { StationRoutesInfo, Train } from '../../typings/common';
|
||||||
|
import { TrainScheduleStop } from './typings';
|
||||||
export interface TrainScheduleStop {
|
|
||||||
nameHtml: string;
|
|
||||||
nameRaw: string;
|
|
||||||
|
|
||||||
status: 'confirmed' | 'unconfirmed' | 'stopped';
|
|
||||||
type: string;
|
|
||||||
position: 'begin' | 'end' | 'en-route';
|
|
||||||
|
|
||||||
arrivalScheduled: number;
|
|
||||||
arrivalReal: number;
|
|
||||||
|
|
||||||
departureScheduled: number;
|
|
||||||
departureReal: number;
|
|
||||||
|
|
||||||
departureDelay: number;
|
|
||||||
arrivalDelay: number;
|
|
||||||
|
|
||||||
duration: number | null;
|
|
||||||
|
|
||||||
isActive: boolean;
|
|
||||||
isLastConfirmed: boolean;
|
|
||||||
isSBL: boolean;
|
|
||||||
|
|
||||||
sceneryName: string | null;
|
|
||||||
distance: number;
|
|
||||||
|
|
||||||
arrivalLine: string | null;
|
|
||||||
departureLine: string | null;
|
|
||||||
|
|
||||||
arrivalLineInfo?: StationRoutesInfo;
|
|
||||||
departureLineInfo?: StationRoutesInfo;
|
|
||||||
|
|
||||||
isExternal: boolean;
|
|
||||||
|
|
||||||
comments: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { StopLabel, StockList },
|
components: { StopLabel, StockList },
|
||||||
@@ -534,6 +530,7 @@ $blinkAnim: 0.5s ease-in-out alternate infinite blink;
|
|||||||
|
|
||||||
img {
|
img {
|
||||||
width: 1em;
|
width: 1em;
|
||||||
|
cursor: help;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { StationRoutesInfo } from "../../typings/common";
|
||||||
|
|
||||||
export enum TrainFilterSection {
|
export enum TrainFilterSection {
|
||||||
TRAIN_TYPE = 'TRAIN_TYPE',
|
TRAIN_TYPE = 'TRAIN_TYPE',
|
||||||
TIMETABLE_TYPE = 'TIMETABLE_TYPE',
|
TIMETABLE_TYPE = 'TIMETABLE_TYPE',
|
||||||
@@ -117,3 +119,40 @@ export const sorterOptions: TrainSorter[] = [
|
|||||||
value: 'długość'
|
value: 'długość'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export interface TrainScheduleStop {
|
||||||
|
nameHtml: string;
|
||||||
|
nameRaw: string;
|
||||||
|
|
||||||
|
status: 'confirmed' | 'unconfirmed' | 'stopped';
|
||||||
|
type: string;
|
||||||
|
position: 'begin' | 'end' | 'en-route';
|
||||||
|
|
||||||
|
arrivalScheduled: number;
|
||||||
|
arrivalReal: number;
|
||||||
|
|
||||||
|
departureScheduled: number;
|
||||||
|
departureReal: number;
|
||||||
|
|
||||||
|
departureDelay: number;
|
||||||
|
arrivalDelay: number;
|
||||||
|
|
||||||
|
duration: number | null;
|
||||||
|
|
||||||
|
isActive: boolean;
|
||||||
|
isLastConfirmed: boolean;
|
||||||
|
isSBL: boolean;
|
||||||
|
|
||||||
|
sceneryName: string | null;
|
||||||
|
distance: number;
|
||||||
|
|
||||||
|
arrivalLine: string | null;
|
||||||
|
departureLine: string | null;
|
||||||
|
|
||||||
|
arrivalLineInfo?: StationRoutesInfo;
|
||||||
|
departureLineInfo?: StationRoutesInfo;
|
||||||
|
|
||||||
|
isExternal: boolean;
|
||||||
|
|
||||||
|
comments: string | null;
|
||||||
|
}
|
||||||
+4
-1
@@ -377,7 +377,10 @@
|
|||||||
"current-track": "on track",
|
"current-track": "on track",
|
||||||
|
|
||||||
"vmax-tooltip": "Maximum train speed based on rolling stock vehicles - braked weight is not included",
|
"vmax-tooltip": "Maximum train speed based on rolling stock vehicles - braked weight is not included",
|
||||||
"we4a-tooltip": "Non-electrified track",
|
|
||||||
|
"catenary-tooltip": "Electrified route",
|
||||||
|
"no-catenary-tooltip": "Non-electrified route",
|
||||||
|
"sbl-tooltip": "Route with SBL\n(automatic block signalling)",
|
||||||
|
|
||||||
"delayed": "Delayed: ",
|
"delayed": "Delayed: ",
|
||||||
"preponed": "Ahead of schedule: ",
|
"preponed": "Ahead of schedule: ",
|
||||||
|
|||||||
+4
-1
@@ -364,7 +364,10 @@
|
|||||||
"current-track": "na szlaku",
|
"current-track": "na szlaku",
|
||||||
|
|
||||||
"vmax-tooltip": "Maksymalna prędkość na podstawie pojazdów w składzie - nie bierze pod uwagę masy hamowania",
|
"vmax-tooltip": "Maksymalna prędkość na podstawie pojazdów w składzie - nie bierze pod uwagę masy hamowania",
|
||||||
"we4a-tooltip": "Szlak niezelektryfikowany",
|
|
||||||
|
"catenary-tooltip": "Szlak zelektryfikowany",
|
||||||
|
"no-catenary-tooltip": "Szlak niezelektryfikowany",
|
||||||
|
"sbl-tooltip": "Szlak posiadający\nsamoczynną blokadę liniową",
|
||||||
|
|
||||||
"delayed": "Opóźniony: ",
|
"delayed": "Opóźniony: ",
|
||||||
"preponed": "Przed czasem: ",
|
"preponed": "Przed czasem: ",
|
||||||
|
|||||||
Reference in New Issue
Block a user