Adjust display logic
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { ApiStationsBoard } from '@owlboard/owlboard-ts';
|
||||
import { formatUkTime, estClass, delayClassFromTimePair } from '$lib/utils/time';
|
||||
import { formatUkTime, estClass, delayClassFromTimePair, isRightTime } from '$lib/utils/time';
|
||||
import { fade, slide, fly } from 'svelte/transition';
|
||||
import { flip } from 'svelte/animate';
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</script>
|
||||
|
||||
<section class="departure-board">
|
||||
<div class="header">
|
||||
<div class="header container">
|
||||
<div class="header row">
|
||||
<div class="upper-header-blank"></div>
|
||||
<div class="upper-header-text">Arr</div>
|
||||
@@ -36,9 +36,14 @@
|
||||
<div
|
||||
class="service-block"
|
||||
animate:flip={{ duration: 400 }}
|
||||
transition:slide={{duration:300}}
|
||||
transition:slide={{ duration: 300 }}
|
||||
>
|
||||
<div
|
||||
class="service row"
|
||||
class:passing={service.wtp}
|
||||
class:nonPax={!service.ip}
|
||||
class:cancelled={service.c}
|
||||
>
|
||||
<div class="service row">
|
||||
<div class="cell id">{service.h}</div>
|
||||
<div class="cell orig">
|
||||
{#key service.og.t}
|
||||
@@ -50,7 +55,7 @@
|
||||
<div class="cell dest">
|
||||
{#key service.dt.t}<div transition:fade={{ duration: 300 }}>{service.dt.t}</div>{/key}
|
||||
</div>
|
||||
<div class="cell plt">
|
||||
<div class="cell plt" class:platsup={service.ps} class:platchange={service.pc}>
|
||||
{#key service.p}<div transition:fade={{ duration: 300 }}>{service.p || '-'}</div>{/key}
|
||||
</div>
|
||||
{#if service.wtp}
|
||||
@@ -58,35 +63,47 @@
|
||||
<div class="cell sch">
|
||||
{formatUkTime(service.wtp)}
|
||||
</div>
|
||||
<div class="cell act">
|
||||
{#key realPass}
|
||||
<div transition:fade={{ duration: 300 }}>
|
||||
<div
|
||||
class="cell act {estClass(service.atp, service.etp)} {delayClassFromTimePair(service.wtp, service.atp || service.etp)}"
|
||||
>
|
||||
{#if isRightTime(service.wtp, service.atp || service.etp)}
|
||||
RT
|
||||
{:else if service.c}
|
||||
CANC
|
||||
{:else}
|
||||
{realPass}
|
||||
</div>
|
||||
{/key}
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="cell sch">{formatUkTime(service.sta)}</div>
|
||||
<div class="cell act">
|
||||
{#key realArrival}
|
||||
<div transition:fade={{ duration: 300 }}>
|
||||
<div
|
||||
class="cell act {estClass(service.ata, service.eta)} {delayClassFromTimePair(service.sta, service.ata || service.eta)}"
|
||||
>
|
||||
{#if isRightTime(service.sta, service.ata || service.eta)}
|
||||
RT
|
||||
{:else if service.sta && service.c} CAN {:else}
|
||||
{realArrival}
|
||||
</div>
|
||||
{/key}
|
||||
{/if}
|
||||
</div>
|
||||
<div class="cell sch">{formatUkTime(service.std)}</div>
|
||||
<div class="cell act">
|
||||
{#key realDeparture}
|
||||
<div transition:fade={{ duration: 300 }}>
|
||||
<div class="cell act {estClass(service.atd, service.etd)} {delayClassFromTimePair(service.std, service.atd || service.etd)}">
|
||||
{#if isRightTime(service.std, service.atd || service.etd)}
|
||||
RT
|
||||
{:else if service.std && service.c} CANC {:else}
|
||||
{realDeparture}
|
||||
</div>
|
||||
{/key}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="operator row">{service.o}</div>
|
||||
{#if service?.cr?.r}
|
||||
{#if service.c}
|
||||
<div class="cancel-reason row" transition:slide={{ duration: 300 }}>{service.cr.r}</div>
|
||||
{:else}
|
||||
<div class="cancel-reason row" transition:slide={{ duration: 300 }}>
|
||||
Part of this service has been cancelled
|
||||
</div>
|
||||
{/if}
|
||||
{:else if service?.dr?.r}
|
||||
<div class="delay-reason row" transition:slide={{ duration: 300 }}>{service.dr.r}</div>
|
||||
{/if}
|
||||
@@ -104,6 +121,13 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header.container {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
background: var(--color-bg-dark);
|
||||
}
|
||||
|
||||
.row.header {
|
||||
font-weight: 875;
|
||||
}
|
||||
@@ -131,6 +155,17 @@
|
||||
font-variant-ligatures: additional-ligatures;
|
||||
}
|
||||
|
||||
.service.row.passing {
|
||||
font-style: italic;
|
||||
opacity: 0.25;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
.service.row.nonPax {
|
||||
opacity: 0.25;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
.service-block {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
@@ -142,52 +177,11 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.departure-board td {
|
||||
font-family: 'Inconsolata Variable', monospace;
|
||||
font-size: clamp(1rem, 0.475rem + 2.8vw, 1.35rem);
|
||||
font-variant-ligatures: additional-ligatures;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
thead,
|
||||
.cancel-row td,
|
||||
.delay-row td {
|
||||
letter-spacing: -0.15ch;
|
||||
}
|
||||
|
||||
thead {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
background: var(--color-bg-dark);
|
||||
}
|
||||
|
||||
abbr {
|
||||
text-decoration: none;
|
||||
border-bottom: none;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
tbody tr:first-child td {
|
||||
border-top: 5px solid transparent;
|
||||
}
|
||||
|
||||
/* Row Logic */
|
||||
.serviceCancelled {
|
||||
.service.cancelled {
|
||||
color: rgb(255, 131, 131);
|
||||
}
|
||||
|
||||
.servicePass td {
|
||||
opacity: 0.75;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
.serviceNonPassenger td {
|
||||
opacity: 0.5;
|
||||
font-weight: 290;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Special Row Styles */
|
||||
.operator.row,
|
||||
.delay-reason.row,
|
||||
@@ -200,11 +194,13 @@
|
||||
.cancel-reason.row {
|
||||
color: rgb(255, 131, 131);
|
||||
font-weight: 400;
|
||||
letter-spacing: -0.1ch;
|
||||
}
|
||||
|
||||
.delay-reason.row {
|
||||
color: var(--delay-orange);
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
letter-spacing: -0.1ch;
|
||||
}
|
||||
@media (min-width: 375px) {
|
||||
.operator.row,
|
||||
@@ -314,16 +310,12 @@
|
||||
font-stretch: 110%;
|
||||
}
|
||||
}
|
||||
.cell.plt.platSup {
|
||||
font-weight: 200;
|
||||
opacity: 0.3;
|
||||
.cell.plt.platsup {
|
||||
font-weight: 150;
|
||||
}
|
||||
.cell.plt.platChange {
|
||||
.cell.plt.platchange {
|
||||
animation: fast-pulse 2s ease-out infinite;
|
||||
}
|
||||
.service-row.serviceCancelled .plt-cell {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.pass-cell {
|
||||
text-align: center;
|
||||
font-stretch: 100%;
|
||||
@@ -343,6 +335,12 @@
|
||||
text-align: center;
|
||||
font-stretch: 72%;
|
||||
}
|
||||
.cell.act.delay-late {
|
||||
color: var(--delay-orange);
|
||||
}
|
||||
.cell.act.delay-early {
|
||||
color: var(--early-blue);
|
||||
}
|
||||
@media (min-width: 350px) {
|
||||
.cell.sch,
|
||||
.cell.act {
|
||||
@@ -367,21 +365,10 @@
|
||||
font-stretch: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* RT Logic */
|
||||
.time-cell.delay-rt span {
|
||||
display: none;
|
||||
}
|
||||
.time-cell.delay-rt::after {
|
||||
content: 'RT';
|
||||
}
|
||||
|
||||
.time-cell.delay-early {
|
||||
color: var(--early-blue);
|
||||
}
|
||||
|
||||
.time-cell.delay-late {
|
||||
color: var(--delay-orange);
|
||||
.cell.act.est {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* Time Types */
|
||||
@@ -390,7 +377,7 @@
|
||||
opacity: 0.75;
|
||||
font-weight: 350;
|
||||
}
|
||||
.cell.act {
|
||||
.cell.act.actual {
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ApiTrainsTrainDetails } from '@owlboard/owlboard-ts';
|
||||
|
||||
export const estClass = (act: any, est: any) => (act ? 'act' : 'est');
|
||||
export const estClass = (act: any, est: any) => (act ? 'actual' : 'estimate');
|
||||
|
||||
/**
|
||||
* Converts ISO/JSON time to UK-formatted HH:MM string, with optional (default off) seconds
|
||||
@@ -132,3 +132,23 @@ export function delayClassFromTimePair(sched: any, act: any): string {
|
||||
|
||||
return diff > 0 ? 'delay-late' : 'delay-early';
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a pair of times (string or Date) and returns true if service considered 'on-time'
|
||||
* @param sched Scheduled Time (string, Date)
|
||||
* @param act Actual Time (string, Date)
|
||||
*/
|
||||
export function isRightTime(
|
||||
sched: string | Date | undefined,
|
||||
act: string | Date | undefined
|
||||
): boolean {
|
||||
console.log(`Checking [sched: ${sched}, act: ${act}]`);
|
||||
if (!sched || !act) return false;
|
||||
|
||||
const s = new Date(sched).getTime();
|
||||
const a = new Date(act).getTime();
|
||||
|
||||
if (isNaN(s) || isNaN(a)) return false;
|
||||
|
||||
return Math.abs(a - s) < 60000;
|
||||
}
|
||||
|
||||
@@ -130,6 +130,10 @@
|
||||
<div class="service-list-wrapper">
|
||||
<StaffServicesGrid services={data.boardData.data.s} />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="no-service">
|
||||
No services at this location in the next three hours
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
@@ -145,6 +149,13 @@
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.no-service {
|
||||
display: block;
|
||||
margin: auto;
|
||||
max-width: 75%;
|
||||
font-family: 'URW Gothic', sans-serif;
|
||||
}
|
||||
|
||||
.time-data {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
Reference in New Issue
Block a user