Files
web-pwa/src/lib/components/ui/TrainService.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>