chore: print styles; Czech timetable (concept)

This commit is contained in:
2025-05-02 17:08:25 +02:00
parent 86185a8f98
commit 2f946a37b4
5 changed files with 131 additions and 71 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="text-white min-h-screen bg-zinc-950"> <div class="text-white min-h-screen bg-zinc-950 print:bg-white">
<!-- PWA update prompt --> <!-- PWA update prompt -->
<transition name="slide-anim"> <transition name="slide-anim">
<UpdatePrompt v-if="needRefresh" @onUpdateClick="updateApp()" /> <UpdatePrompt v-if="needRefresh" @onUpdateClick="updateApp()" />
+1 -1
View File
@@ -1,6 +1,6 @@
<template> <template>
<main <main
class="grid print:block p-3 mx-auto max-w-[800px] h-[calc(100vh-40px)] min-h-[300px] grid-rows-[auto_auto_1fr] gap-1" class="grid print:block print:bg-white p-3 mx-auto max-w-[800px] h-[calc(100vh-40px)] min-h-[300px] grid-rows-[auto_auto_1fr] gap-1"
> >
<SearchContainer /> <SearchContainer />
<TimetableWarnings /> <TimetableWarnings />
+122 -66
View File
@@ -10,52 +10,61 @@
</h3> </h3>
<p class="mt-2 text-center"> <p class="mt-2 text-center">
Platí: {{ timetableDate.toLocaleDateString('pl-PL', { day: '2-digit' }) }}.{{ Kursuje: {{ timetableDate.toLocaleDateString('pl-PL', { day: '2-digit' }) }}.{{
romanMonthDigits[timetableDate.getMonth()] romanMonthDigits[timetableDate.getMonth()]
}}.{{ timetableDate.toLocaleDateString('pl-PL', { year: 'numeric' }) }} }}.{{ timetableDate.toLocaleDateString('pl-PL', { year: 'numeric' }) }}
</p> </p>
<p class="mt-2"> <p class="mt-2">
Elektrická lokomotiva ř. {{ globalStore.currentTimetableData!.headUnits[0] }}: normativ Lokomotywa elektryczna {{ globalStore.currentTimetableData!.headUnits[0] }}, waga:
hmotnosti: S {{ (globalStore.currentTimetableData!.mass / 1000).toFixed(0) }} tun. {{ (globalStore.currentTimetableData!.mass / 1000).toFixed(1) }} t, długość:
{{ globalStore.currentTimetableData!.length }} m
</p> </p>
<p> <p></p>
Vlak brzděn {{ globalStore.currentTimetableData!.mass > 500000 ? 'II' : 'I' }} způsobem brzdění.
</p>
<table class="table-fixed w-full border-collapse h-full"> <table class="table-fixed w-full border-collapse h-full">
<thead> <thead>
<tr> <tr>
<!-- Name --> <!-- Name -->
<th <th
width="300" width="250"
class="font-normal border border-black dark:border-white border-l-transparent" class="font-normal border border-black dark:border-white border-l-transparent"
> >
1 <MapPinIcon :size="20" class="mx-auto" />
</th> </th>
<!-- Info --> <!-- Info -->
<th width="50" class="font-normal border border-black dark:border-white">2</th> <th width="50" class="font-normal border border-black dark:border-white">
<CircleAlertIcon :size="20" class="mx-auto" />
</th>
<!-- Drive time --> <!-- Drive time -->
<th width="30" class="font-normal border border-black dark:border-white">3</th> <th width="30" class="font-normal border border-black dark:border-white">
<TimerIcon :size="20" class="mx-auto" />
</th>
<!-- Arrival --> <!-- Arrival -->
<th width="70" class="font-normal border border-black dark:border-white">5</th> <th width="70" class="font-normal border border-black dark:border-white">
<CalendarArrowUpIcon :size="20" class="mx-auto" />
</th>
<!-- Stop time --> <!-- Stop time -->
<th width="40" class="font-normal border border-black dark:border-white">6</th> <th width="40" class="font-normal border border-black dark:border-white">
<HandIcon :size="20" class="mx-auto" />
</th>
<!-- Departure --> <!-- Departure -->
<th width="70" class="font-normal border border-black dark:border-white">7</th> <th width="70" class="font-normal border border-black dark:border-white">
<CalendarArrowDownIcon :size="20" class="mx-auto" />
</th>
<!-- vMax --> <!-- vMax -->
<th <th
width="80" width="80"
class="font-normal border border-black dark:border-white border-r-transparent" class="font-normal border border-black dark:border-white border-r-transparent"
> >
8 <CircleGaugeIcon :size="20" class="mx-auto" />
</th> </th>
</tr> </tr>
</thead> </thead>
@@ -63,7 +72,7 @@
<tbody> <tbody>
<tr <tr
v-for="(row, i) in computedTimetableRows" v-for="(row, i) in computedTimetableRows"
:class="{ 'bg-slate-100 dark:bg-zinc-900': i % 2 == 0 }" :class="{ 'bg-slate-100 dark:bg-zinc-900 print:bg-gray-300': i % 2 == 0 }"
class="leading-none" class="leading-none"
> >
<td class="px-2 font-thin text-nowrap overflow-hidden overflow-ellipsis"> <td class="px-2 font-thin text-nowrap overflow-hidden overflow-ellipsis">
@@ -87,23 +96,8 @@
<td <td
class="border border-black dark:border-white border-t-transparent border-b-transparent text-right font-bold px-2" class="border border-black dark:border-white border-t-transparent border-b-transparent text-right font-bold px-2"
> >
<span v-if="row.stopType == 'pt'">+</span> <span v-if="row.stopType == 'pt'">+ </span>
{{ <span> {{ row.arrivalDateStr }} </span>
row.scheduledArrivalDate
?.toLocaleTimeString('pl-PL', {
hour: 'numeric',
minute: '2-digit'
})
.split(':')
.slice(
i > 0 &&
computedTimetableRows[i - 1].scheduledArrivalDate?.getHours() ==
row.scheduledArrivalDate.getHours()
? 1
: 0
)
.join(' ')
}}
</td> </td>
<td <td
@@ -113,32 +107,30 @@
</td> </td>
<td <td
class="border border-black dark:border-white border-t-transparent border-b-transparent text-right font-bold px-2" class="border border-black dark:border-white border-t-transparent border-b-transparent text-right font-bold px-2 relative"
> >
{{ <span
row.scheduledDepartureDate class="absolute right-[-3px] border-r-[5px] border-black"
?.toLocaleTimeString('pl-PL', { :class="{
hour: 'numeric', 'top-0 h-[calc(100%+1px)]':
minute: '2-digit' row.arrivalTracks == row.departureTracks && row.arrivalTracks == 2,
}) 'top-0 h-[calc(50%+1px)]': row.arrivalTracks > row.departureTracks,
.split(':') 'top-1/2 h-[calc(50%+1px)]': row.arrivalTracks < row.departureTracks
.slice( }"
i > 0 && ></span>
computedTimetableRows[i - 1].scheduledDepartureDate?.getHours() == {{ row.departureDateStr }}
row.scheduledDepartureDate.getHours()
? 1
: 0
)
.join(' ')
}}
</td> </td>
<td class="text-center font-bold"> <!-- v-if="
<span
v-if="
i == 0 || (i > 0 && computedTimetableRows[i - 1].departureSpeed != row.arrivalSpeed) i == 0 || (i > 0 && computedTimetableRows[i - 1].departureSpeed != row.arrivalSpeed)
" " -->
>{{ row.arrivalSpeed }} <td class="text-center font-bold">
<span v-if="i == 0 || computedTimetableRows[i - 1].departureSpeed != row.arrivalSpeed">
{{ i == 0 ? row.departureSpeed : row.arrivalSpeed }}
<span v-if="row.arrivalSpeed != row.departureSpeed">
/
{{ row.departureSpeed }}
</span>
</span> </span>
</td> </td>
</tr> </tr>
@@ -152,6 +144,18 @@ import { computed, ref } from 'vue';
import { useGlobalStore } from '../../stores/global.store'; import { useGlobalStore } from '../../stores/global.store';
import type { StopRowCZ, TimetablePathData } from '../../types/common.types'; import type { StopRowCZ, TimetablePathData } from '../../types/common.types';
import { useApiStore } from '../../stores/api.store'; import { useApiStore } from '../../stores/api.store';
import {
ArrowRightIcon,
CalendarArrowDownIcon,
CalendarArrowUpIcon,
CircleAlertIcon,
CircleGaugeIcon,
CircleHelpIcon,
HandIcon,
MapPinIcon,
TimerIcon,
UniversityIcon
} from 'lucide-vue-next';
const globalStore = useGlobalStore(); const globalStore = useGlobalStore();
const apiStore = useApiStore(); const apiStore = useApiStore();
@@ -182,32 +186,39 @@ const computedTimetableRows = computed(() => {
let lastDepartureTimestamp = 0; let lastDepartureTimestamp = 0;
let arrivalSpeed = 0, let arrivalSpeed = 0,
departureSpeed = 0; departureSpeed = 0,
arrivalTracks = 0,
departureTracks = 2;
if (currentPath.departureLineData) { if (currentPath.departureLineData) {
departureSpeed = Math.min(currentPath.departureLineData.routeSpeed, stockVmax); departureSpeed = Math.min(currentPath.departureLineData.routeSpeed, stockVmax);
arrivalSpeed = Math.min(currentPath.departureLineData.routeSpeed, stockVmax); arrivalSpeed = Math.min(currentPath.departureLineData.routeSpeed, stockVmax);
departureTracks = currentPath.departureLineData.routeTracks;
arrivalTracks = currentPath.departureLineData.routeTracks;
} }
const stopList = parseStopListString(timetableData.stopListString); const stopList = parseStopListString(timetableData.stopListString);
timetableDate.value = new Date(stopList[0].departureTimestamp); timetableDate.value = new Date(stopList[0].departureTimestamp);
for (const stop of stopList) { stopList.forEach((stop, i) => {
if (stop.arrivalLine && stop.arrivalLine == currentPath.arrivalLine) { if (stop.arrivalLine && stop.arrivalLine == currentPath.arrivalLine) {
if (currentPath.arrivalLineData) { if (currentPath.arrivalLineData) {
arrivalSpeed = Math.min(currentPath.arrivalLineData.routeSpeed, stockVmax); arrivalSpeed = Math.min(currentPath.arrivalLineData.routeSpeed, stockVmax);
arrivalTracks = currentPath.arrivalLineData.routeTracks;
} }
departureSpeed = arrivalSpeed; departureSpeed = arrivalSpeed;
departureTracks = arrivalTracks;
} }
if ( if (
stop.mainStop || stop.mainStop ||
(/^podg|po|pe$/.test(stop.stopNameRAW) && !/^sbl/i.test(stop.stopNameRAW)) (/^podg|po|pe$/.test(stop.stopNameRAW) && !/^sbl/i.test(stop.stopNameRAW))
) { ) {
let correctedDepartureSpeed = 0; let correctedDepartureSpeed = 0,
correctedDepartureTracks = 0;
const internalRouteInfo = stop.departureLine const internalRouteInfo = stop.departureLine
? currentPath.sceneryData?.routesInfo.find( ? currentPath.sceneryData?.routesInfo.find(
@@ -218,34 +229,76 @@ const computedTimetableRows = computed(() => {
if (internalRouteInfo) { if (internalRouteInfo) {
correctedDepartureSpeed = Math.min(internalRouteInfo.routeSpeed, stockVmax); correctedDepartureSpeed = Math.min(internalRouteInfo.routeSpeed, stockVmax);
departureSpeed = Math.min(internalRouteInfo.routeSpeed, stockVmax); departureSpeed = Math.min(internalRouteInfo.routeSpeed, stockVmax);
correctedDepartureTracks = internalRouteInfo.routeTracks;
departureTracks = internalRouteInfo.routeTracks;
if (stopRows.length == 0) { if (stopRows.length == 0) {
arrivalSpeed = departureSpeed; arrivalSpeed = departureSpeed;
arrivalTracks = departureTracks;
} }
} }
const scheduledArrivalDate = stop.arrivalTimestamp ? new Date(stop.arrivalTimestamp) : null;
const scheduledDepartureDate = stop.departureTimestamp
? new Date(stop.departureTimestamp)
: null;
let arrivalDateStr =
scheduledArrivalDate?.toLocaleTimeString('pl-PL', {
hour: 'numeric',
minute: '2-digit'
}) ?? '';
let departureDateStr =
scheduledDepartureDate?.toLocaleTimeString('pl-PL', {
hour: 'numeric',
minute: '2-digit'
}) ?? '';
if (
stopRows.length > 0 &&
stopRows[stopRows.length - 1]?.scheduledArrivalDate?.getHours() ==
scheduledArrivalDate?.getHours()
) {
arrivalDateStr = arrivalDateStr.split(':').slice(1).join(' ');
}
if (
stopRows[stopRows.length - 1]?.scheduledDepartureDate?.getHours() ==
scheduledDepartureDate?.getHours()
) {
departureDateStr = departureDateStr.split(':').slice(1).join(' ');
}
let rowData: StopRowCZ = { let rowData: StopRowCZ = {
isMain: stop.mainStop, isMain: stop.mainStop,
pointKm: stop.stopDistance.toFixed(3), pointKm: stop.stopDistance.toFixed(3),
pointName: stop.stopNameRAW, pointName: stop.stopNameRAW,
scheduledArrivalDate: stop.arrivalTimestamp ? new Date(stop.arrivalTimestamp) : null, scheduledArrivalDate,
scheduledDepartureDate: stop.departureTimestamp ? new Date(stop.departureTimestamp) : null, scheduledDepartureDate,
stopTime: stop.stopTime ? (stop.departureTimestamp - stop.arrivalTimestamp) / 60000 : 0, stopTime: stop.stopTime ? (stop.departureTimestamp - stop.arrivalTimestamp) / 60000 : 0,
stopType: stop.stopType, stopType: stop.stopType,
sceneryName: currentPath.sceneryName, sceneryName: currentPath.sceneryName,
driveTime: lastDepartureTimestamp ? stop.arrivalTimestamp - lastDepartureTimestamp : 0, driveTime: lastDepartureTimestamp ? stop.arrivalTimestamp - lastDepartureTimestamp : 0,
arrivalSpeed: arrivalSpeed, arrivalSpeed: arrivalSpeed,
departureSpeed: departureSpeed, departureSpeed: departureSpeed,
arrivalTracks,
departureTracks,
headUnits: timetableData.headUnits, headUnits: timetableData.headUnits,
stockVmax, stockVmax,
stockLength, stockLength,
stockMass stockMass,
arrivalDateStr,
departureDateStr
}; };
arrivalSpeed = correctedDepartureSpeed || arrivalSpeed; arrivalSpeed = correctedDepartureSpeed || arrivalSpeed;
arrivalTracks = correctedDepartureTracks || arrivalTracks;
if (stop.departureTimestamp) lastDepartureTimestamp = stop.departureTimestamp; if (stop.departureTimestamp) lastDepartureTimestamp = stop.departureTimestamp;
@@ -256,6 +309,8 @@ const computedTimetableRows = computed(() => {
// Reverse search for last scenery checkpoint // Reverse search for last scenery checkpoint
if (currentPath.departureLineData) { if (currentPath.departureLineData) {
for (let i = stopRows.length - 1; i >= 0; i--) { for (let i = stopRows.length - 1; i >= 0; i--) {
stopRows[i].departureTracks = currentPath.departureLineData.routeTracks;
stopRows[i].departureSpeed = Math.min( stopRows[i].departureSpeed = Math.min(
currentPath.departureLineData.routeSpeed, currentPath.departureLineData.routeSpeed,
stockVmax stockVmax
@@ -267,16 +322,19 @@ const computedTimetableRows = computed(() => {
stockVmax stockVmax
); );
stopRows[i].departureTracks = currentPath.departureLineData.routeTracks;
break; break;
} }
stopRows[i].arrivalSpeed = Math.min(currentPath.departureLineData.routeSpeed, stockVmax); stopRows[i].arrivalSpeed = Math.min(currentPath.departureLineData.routeSpeed, stockVmax);
stopRows[i].arrivalTracks = currentPath.departureLineData.routeTracks;
} }
} }
currentPath = timetablePath[++currentPathIndex]; currentPath = timetablePath[++currentPathIndex];
} }
} });
let timeTo = Date.now(); let timeTo = Date.now();
@@ -328,7 +386,7 @@ function parseStopListString(stopsString: string) {
arrivalLine, arrivalLine,
arrivalTimestamp: parseInt(arrivalTimestamp), arrivalTimestamp: parseInt(arrivalTimestamp),
stopNameRAW, stopNameRAW,
stopTime: stopTime ?? 0, stopTime: Number(stopTime ?? 0),
stopType: stopType ?? null, stopType: stopType ?? null,
mainStop: isMainStop == 'true', mainStop: isMainStop == 'true',
stopDistance: parseFloat(stopDistance), stopDistance: parseFloat(stopDistance),
@@ -338,5 +396,3 @@ function parseStopListString(stopsString: string) {
}); });
} }
</script> </script>
<style scoped></style>
@@ -3,14 +3,13 @@
class="overflow-auto p-1 bg-white print:bg-white dark:bg-zinc-950 print:text-black text-black dark:text-white min-h-full" class="overflow-auto p-1 bg-white print:bg-white dark:bg-zinc-950 print:text-black text-black dark:text-white min-h-full"
:class="{ dark: globalStore.darkMode }" :class="{ dark: globalStore.darkMode }"
> >
<TimetableContentCZ /> <TimetableContent />
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useGlobalStore } from '../../stores/global.store'; import { useGlobalStore } from '../../stores/global.store';
// import TimetableContent from '../Timetable/TimetableContent.vue'; import TimetableContent from '../Timetable/TimetableContent.vue';
import TimetableContentCZ from '../Timetable/TimetableContentCZ.vue';
const globalStore = useGlobalStore(); const globalStore = useGlobalStore();
</script> </script>
+5
View File
@@ -161,10 +161,15 @@ export interface StopRowCZ {
sceneryName: string; sceneryName: string;
arrivalSpeed: number; arrivalSpeed: number;
departureSpeed: number; departureSpeed: number;
arrivalTracks: number;
departureTracks: number;
headUnits: string[]; headUnits: string[];
stockVmax: number; stockVmax: number;
stockLength: number; stockLength: number;
stockMass: number; stockMass: number;
arrivalDateStr: string;
departureDateStr: string;
} }
export interface TimetablePathData { export interface TimetablePathData {