321 lines
8.6 KiB
Svelte
321 lines
8.6 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";
|
|
import { fade } from "svelte/transition";
|
|
|
|
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");
|
|
}
|
|
|
|
function checkLateEarly(originalTime: Date | undefined, comparedTime: Date | undefined, arr: string[]) {
|
|
if (originalTime !== undefined && comparedTime instanceof Date) {
|
|
if (originalTime < comparedTime) {
|
|
arr.push("late");
|
|
} else if (originalTime > comparedTime) {
|
|
arr.push("early");
|
|
}
|
|
}
|
|
}
|
|
|
|
checkLateEarly(service.sta, service.eta, arrArr);
|
|
checkLateEarly(service.sta, service.ata, arrArr);
|
|
checkLateEarly(service.std, service.etd, depArr);
|
|
checkLateEarly(service.std, service.atd, depArr);
|
|
|
|
return {
|
|
other: otherArr.join(" "),
|
|
arr: arrArr.join(" "),
|
|
dep: depArr.join(" "),
|
|
plat: platArr.join(" "),
|
|
};
|
|
}
|
|
|
|
function fmtTime(date: Date | string | undefined): string | false {
|
|
if (typeof date === "string") 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 in:fade={{duration:500}}>
|
|
<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(--secondary-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: left;
|
|
}
|
|
}
|
|
|
|
/* 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>
|