140 lines
3.6 KiB
Svelte
140 lines
3.6 KiB
Svelte
<script lang="ts">
|
|
import type { ApiTrainsTrainByHeadcode } from '@owlboard/owlboard-ts';
|
|
import { OwlClient, ApiError, ValidationError } from '$lib/owlClient';
|
|
import { slide } from 'svelte/transition';
|
|
import { quintOut} from 'svelte/easing';
|
|
import { formatUkTime } from '$lib/utils/time';
|
|
import TocStyle from '$lib/components/ui/TocStyle.svelte';
|
|
|
|
let { service }: { service: ApiTrainsTrainByHeadcode.TrainByHeadcodeResponse} = $props();
|
|
let isExpanded = $state(false);
|
|
let loadingDetails = $state(false)
|
|
let details = $state(null);
|
|
|
|
const toggleExpand = async (rid: string) => {
|
|
if (isExpanded) {
|
|
isExpanded = false;
|
|
return;
|
|
}
|
|
|
|
if (details) {
|
|
isExpanded = true;
|
|
return;
|
|
}
|
|
|
|
loadingDetails = true;
|
|
try {
|
|
const result = await OwlClient.trains.getByRid(service.r)
|
|
details = result.data;
|
|
isExpanded = true;
|
|
} catch (e) {
|
|
console.Error("Failde to load train details")
|
|
} finally {
|
|
loading = false;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
let OriginDepartureSummary = $derived(formatUkTime(service.od));
|
|
|
|
async function loadDetails(rid: string) {
|
|
if (details) return;
|
|
loadingDetails = true;
|
|
|
|
const result = await OwlClient.trains.getByRid(service.r)
|
|
details = result.data;
|
|
loadingDetails = false;
|
|
}
|
|
</script>
|
|
|
|
<div class="train-service">
|
|
<button class="summary" onclick={toggleExpand} type="button" aria-expanded={isExpanded}>
|
|
<div class="operator-summary">
|
|
<TocStyle toc={service.o} />
|
|
</div>
|
|
<div class="main-text-summary">
|
|
<div class="time-summary">
|
|
{OriginDepartureSummary}
|
|
</div>
|
|
<div class="location-summary">
|
|
{service.ot}
|
|
</div>
|
|
<div class="location-summary to-summary">
|
|
to
|
|
</div>
|
|
<div class="location-summary">
|
|
{service.dt}
|
|
</div>
|
|
<!-- Add arrow icon to signify drop-down -->
|
|
<!-- ADD LOADING STATE -->
|
|
</div>
|
|
</button>
|
|
{#if isExpanded && details}
|
|
<div transition:slide={{duration: 800, easing: quintOut}} class="detauls-content">
|
|
<!-- Here goes the data formatting! -->
|
|
{JSON.stringify(details)}
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
<style>
|
|
.train-service {
|
|
background-color: var(--color-accent);
|
|
width: 100%;
|
|
border-radius: 4px;
|
|
box-shadow: var(--shadow-std);
|
|
overflow: hidden;
|
|
font-family: 'URW Gothic', sans-serif;
|
|
transition: 0.2s all;
|
|
filter: brightness(1.1);
|
|
}
|
|
|
|
.train-service:hover {
|
|
filter:brightness(1.5);
|
|
}
|
|
|
|
.summary {
|
|
display: flex;
|
|
align-items: center;
|
|
width: 100%;
|
|
padding: 0.75rem;
|
|
min-height: 48px;
|
|
border: none;
|
|
background: transparent;
|
|
cursor: pointer;
|
|
text-align: left;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.operator-summary {
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.main-text-summary {
|
|
display: flex;
|
|
flex-grow: 1;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.time-summary {
|
|
font-size: 1.1rem;
|
|
font-weight: 700;
|
|
color: var(--color-brand);
|
|
}
|
|
|
|
.location-summary {
|
|
text-transform: uppercase;
|
|
font-weight: 500;
|
|
font-size: 1.1rem;
|
|
letter-spacing: 0.02em;
|
|
color: var(--color-title);
|
|
}
|
|
|
|
.to-summary {
|
|
font-size: 0.8rem;
|
|
font-style: oblique;
|
|
text-transform: lowercase;
|
|
}
|
|
</style> |