347 lines
7.9 KiB
Svelte
347 lines
7.9 KiB
Svelte
<script lang="ts">
|
|
import Reason from '$lib/raw-fetchers/reason.svelte';
|
|
import { tocs as tocMap } from '$lib/stores/tocMap';
|
|
|
|
import type { TrainServices, ServiceLocation } from '@owlboard/ts-types';
|
|
|
|
export let services: TrainServices[];
|
|
export let click: Function;
|
|
|
|
function detail(event: any, rid: string, uid: string, tid: string) {
|
|
const target = event.target;
|
|
click(rid, uid, tid);
|
|
}
|
|
|
|
async function formatLocations(locations: ServiceLocation[]): Promise<string> {
|
|
let tiplocs: string[] = [];
|
|
for (const location of locations) {
|
|
tiplocs.push(location.tiploc);
|
|
}
|
|
return tiplocs.join(' & ');
|
|
}
|
|
|
|
async function classGenerator(service: TrainServices) {
|
|
// This function needs updating next
|
|
let otherArr: string[] = [];
|
|
let arrArr: string[] = [];
|
|
let depArr: string[] = [];
|
|
let platArr: string[] = [];
|
|
|
|
if (service.isCancelled) {
|
|
otherArr.push('canc');
|
|
}
|
|
if (service.serviceIsSupressed) {
|
|
otherArr.push('nonPass');
|
|
}
|
|
if (service.platformIsHidden) {
|
|
platArr.push('nonPass');
|
|
}
|
|
|
|
if (service.sta !== undefined) {
|
|
if (service.eta !== undefined) {
|
|
if (service.sta < service.eta) {
|
|
arrArr.push('late');
|
|
}
|
|
} else if (service.ata !== undefined) {
|
|
if (service.sta < service.ata) {
|
|
arrArr.push('late');
|
|
}
|
|
}
|
|
if (service.eta !== undefined) {
|
|
if (service.sta > service.eta) {
|
|
arrArr.push('early');
|
|
}
|
|
} else if (service.ata !== undefined) {
|
|
if (service.sta > service.ata) {
|
|
arrArr.push('early');
|
|
}
|
|
}
|
|
}
|
|
|
|
if (service.std !== undefined) {
|
|
if (service.etd !== undefined) {
|
|
if (service.std < service.etd) {
|
|
depArr.push('late');
|
|
}
|
|
} else if (service.atd !== undefined) {
|
|
if (service.std < service.atd) {
|
|
depArr.push('late');
|
|
}
|
|
}
|
|
if (service.etd !== undefined) {
|
|
if (service.std > service.etd) {
|
|
depArr.push('early');
|
|
}
|
|
} else if (service.atd !== undefined) {
|
|
if (service.std > service.atd) {
|
|
depArr.push('early');
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
other: otherArr.join(' '),
|
|
arr: arrArr.join(' '),
|
|
dep: depArr.join(' '),
|
|
plat: platArr.join(' ')
|
|
};
|
|
}
|
|
|
|
function fmtTime(date: Date | string | undefined): string | false {
|
|
if (date === 'RT' || date === "CANC" || date === "LATE") return date;
|
|
if (date instanceof Date) {
|
|
const hours = date.getHours().toString().padStart(2, '0');
|
|
const minutes = date.getMinutes().toString().padStart(2, '0');
|
|
return `${hours}:${minutes}`;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<p class="smallScreen">Your display is too small to view this data</p>
|
|
<p class="smallScreen">Try rotating your device</p>
|
|
<table>
|
|
<tr>
|
|
<th class="id">ID</th>
|
|
<th class="from">From</th>
|
|
<th class="to">To</th>
|
|
<th class="plat">Plat</th>
|
|
<th class="time arrsch">Sch</th>
|
|
<th class="time arrexp">Exp</th>
|
|
<th class="time depsch">Sch</th>
|
|
<th class="time depexp">Exp</th>
|
|
</tr>
|
|
<tr>
|
|
<th class="other" colspan="4" />
|
|
<th class="timepair" colspan="2">Arrival</th>
|
|
<th class="timepair" colspan="2">Departure</th>
|
|
</tr>
|
|
{#each services as service}
|
|
<tr
|
|
class="dataRow"
|
|
on:click={(event) => detail(event, service.rid, service.uid, service.trainid)}
|
|
on:keypress={(event) => detail(event, service.rid, service.uid, service.trainid)}
|
|
>
|
|
{#await classGenerator(service) then classes}
|
|
<!-- HEADCODE -->
|
|
<td class="id">{service.trainid}</td>
|
|
<!-- ORIGIN -->
|
|
<td class="loc from {classes.other}">{#await formatLocations(service.origin) then origin}{origin}{/await}</td>
|
|
<!-- DESTINATION -->
|
|
<td class="loc to {classes.other}">{#await formatLocations(service.destination) then dest}<span class="locName">{dest}</span>{/await}</td>
|
|
<!-- PLATFORM -->
|
|
<td class="plat {classes.other} {classes.plat}">{service.platform || '-'}</td>
|
|
<!-- SCHEDULED ARR -->
|
|
<td class="time schTime {classes.other}">{fmtTime(service?.sta) || '-'}</td>
|
|
<!-- EXPECTED/ACTUAL ARR -->
|
|
<td class="time {classes.other} {classes.arr}">{fmtTime(service.eta) || fmtTime(service.ata) || '-'}</td>
|
|
<!-- SCHEDULED DEP -->
|
|
<td class="time schTime {classes.other}">{fmtTime(service.std) || '-'}</td>
|
|
<!-- EXPECTED/ACTUAL DEP -->
|
|
<td class="time {classes.other} {classes.dep}">{fmtTime(service.etd) || fmtTime(service.atd) || '-'}</td>
|
|
{/await}
|
|
</tr>
|
|
<tr>
|
|
<td colspan="1" />
|
|
<td class="tableTxt" colspan="7">
|
|
{#if service.destination?.[0] && service.destination[0].via}<span class="via">{service.destination[0].via}</span><br />{/if}
|
|
{tocMap.get(service.operatorCode.toLowerCase()) || service.operatorCode}
|
|
{#if service.length} | {service.length} carriages{/if}
|
|
{#if service.delayReason}
|
|
<br />
|
|
<span class="delayTxt">
|
|
<Reason type={'delay'} code={service.delayReason} />
|
|
</span>
|
|
{/if}
|
|
{#if service.cancelReason}
|
|
<br />
|
|
<span class="cancTxt">
|
|
<Reason type={'cancel'} code={service.cancelReason} />
|
|
</span>
|
|
{/if}
|
|
</td>
|
|
</tr>
|
|
{/each}
|
|
</table>
|
|
|
|
<style>
|
|
table {
|
|
table-layout: fixed;
|
|
width: 100%;
|
|
max-width: 875px;
|
|
margin: auto;
|
|
padding: 0px;
|
|
color: white;
|
|
}
|
|
|
|
th {
|
|
font-size: 12px;
|
|
margin: 0px;
|
|
}
|
|
|
|
.dataRow {
|
|
font-family: ubuntu, monospace;
|
|
vertical-align: top;
|
|
cursor: pointer;
|
|
font-size: 16px;
|
|
line-height: 1;
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
/* Table Columns */
|
|
.id {
|
|
width: 8%;
|
|
}
|
|
.from {
|
|
width: 14%;
|
|
}
|
|
.to {
|
|
width: 14%;
|
|
}
|
|
.plat {
|
|
width: 6%;
|
|
}
|
|
.time {
|
|
width: 9%;
|
|
}
|
|
|
|
td.id {
|
|
color: lightblue;
|
|
text-align: left;
|
|
padding-left: 2px;
|
|
}
|
|
td.from,
|
|
td.to {
|
|
color: yellow;
|
|
}
|
|
|
|
td.to {
|
|
text-align: right;
|
|
}
|
|
td.from,
|
|
th.from {
|
|
text-align: left;
|
|
}
|
|
td.time {
|
|
font-size: 15px;
|
|
vertical-align: top;
|
|
}
|
|
.tableTxt {
|
|
text-align: left;
|
|
padding-left: 2px;
|
|
color: var(--second-text-color);
|
|
vertical-align: top;
|
|
font-size: 12px;
|
|
padding-bottom: 10px;
|
|
}
|
|
.delayTxt {
|
|
color: var(--main-warning-color);
|
|
}
|
|
.cancTxt {
|
|
color: var(--main-alert-color);
|
|
}
|
|
.via {
|
|
color: yellow;
|
|
padding-left: 0px;
|
|
}
|
|
/* Handle small screens */
|
|
.smallScreen {
|
|
display: none;
|
|
margin: 20px;
|
|
}
|
|
@media screen and (max-width: 335px) {
|
|
th {
|
|
font-size: 10px;
|
|
}
|
|
.dataRow {
|
|
font-size: 12px;
|
|
}
|
|
td.time {
|
|
font-size: 12px;
|
|
}
|
|
.tableTxt {
|
|
font-size: 10px;
|
|
}
|
|
}
|
|
@media screen and (max-width: 279px) {
|
|
table {
|
|
display: none;
|
|
}
|
|
.smallScreen {
|
|
display: block;
|
|
}
|
|
}
|
|
|
|
/* Handle Large Screens */
|
|
@media screen and (min-width: 375px) {
|
|
.dataRow {
|
|
font-size: 18px;
|
|
}
|
|
td.time {
|
|
font-size: 16px;
|
|
}
|
|
}
|
|
@media screen and (min-width: 450px) {
|
|
.dataRow {
|
|
font-size: 20px;
|
|
}
|
|
td.time {
|
|
font-size: 19px;
|
|
}
|
|
.tableTxt {
|
|
font-size: 14px;
|
|
}
|
|
td.to,
|
|
td.from,
|
|
th.to,
|
|
th.from {
|
|
text-align: center;
|
|
}
|
|
}
|
|
|
|
/* Conditional Classes */
|
|
.loc.canc,
|
|
.canc {
|
|
color: grey;
|
|
text-decoration: line-through;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.nonPass {
|
|
opacity: 0.4;
|
|
}
|
|
|
|
.late {
|
|
animation: pulse-late 1.5s linear infinite;
|
|
}
|
|
|
|
.canc.time {
|
|
animation: pulse-cancel 1.5s linear infinite;
|
|
}
|
|
|
|
.early {
|
|
animation: pulse-early 1.5s linear infinite;
|
|
}
|
|
|
|
/* Animation Definitions */
|
|
@keyframes pulse-late {
|
|
50% {
|
|
color: var(--main-warning-color);
|
|
}
|
|
}
|
|
|
|
@keyframes pulse-cancel {
|
|
50% {
|
|
color: var(--main-alert-color);
|
|
}
|
|
}
|
|
|
|
@keyframes pulse-early {
|
|
50% {
|
|
color: rgb(136, 164, 255);
|
|
}
|
|
}
|
|
</style>
|