Skip to content

Commit

Permalink
frontend: stream journeys to frontend and add loading spinner
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeName-Anti committed Mar 6, 2025
1 parent 7c02041 commit f2ef343
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 19 deletions.
72 changes: 72 additions & 0 deletions frontend/src/components/Loader.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<span class="loader"></span>

<style>
/* https://cssloaders.github.io/ */
.loader {
animation: rotate 1s infinite;
height: 50px;
width: 50px;
}
.loader:before,
.loader:after {
border-radius: 50%;
content: "";
display: block;
height: 20px;
width: 20px;
}
.loader:before {
animation: ball1 1s infinite;
background-color: var(--text);
box-shadow: 30px 0 0 var(--accent);
margin-bottom: 10px;
}
.loader:after {
animation: ball2 1s infinite;
background-color: var(--accent);
box-shadow: 30px 0 0 var(--text);
}
@keyframes rotate {
0% {
transform: rotate(0deg) scale(0.8);
}
50% {
transform: rotate(360deg) scale(1.2);
}
100% {
transform: rotate(720deg) scale(0.8);
}
}
@keyframes ball1 {
0% {
box-shadow: 30px 0 0 var(--accent);
}
50% {
box-shadow: 0 0 0 var(--accent);
margin-bottom: 0;
transform: translate(15px, 15px);
}
100% {
box-shadow: 30px 0 0 var(--accent);
margin-bottom: 10px;
}
}
@keyframes ball2 {
0% {
box-shadow: 30px 0 0 var(--text);
}
50% {
box-shadow: 0 0 0 var(--text);
margin-top: -20px;
transform: translate(15px, 15px);
}
100% {
box-shadow: 30px 0 0 var(--text);
margin-top: 0;
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import type { Journey } from "$models/connection";
import { DateTime } from "luxon";
import { env } from "$env/dynamic/private";

export const load: PageServerLoad = async ({ params, url }): Promise<{ journeys: Journey[] }> => {
const journeys = await loadJourneys(
export const load: PageServerLoad = async ({ params, url }): Promise<{ journeys: Promise<Journey[]> }> => {
const journeys = loadJourneys(
params.evaNumber,
params.type,
url.searchParams.get("startDate") ?? DateTime.now().set({ second: 0, millisecond: 0 }).toISO()
Expand Down
44 changes: 27 additions & 17 deletions frontend/src/routes/(root)/[evaNumber=int]/[type=type]/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
<script lang="ts">
import { onMount } from "svelte";
import type { PageProps } from "./$types";
import Filter from "$components/timetable/filter/Filter.svelte";
import type { Connection, Journey } from "$models/connection";
import ConnectionComponent from "$components/timetable/ConnectionComponent.svelte";
import WingTrain from "$components/timetable/WingTrain.svelte";
import Loader from "$components/Loader.svelte";
let { data }: PageProps = $props();
let currentFilter = $state(["*"]);
const matchesFilter = (journey: Journey) => {
if (currentFilter.length === 0) return true;
if (currentFilter.includes("*")) return true;
Expand All @@ -18,26 +21,33 @@
return currentFilter.includes(firstConnection?.lineInformation?.type ?? "");
};
const allowedProducts = (): string[] => {
const products = data?.station?.products || [];
const allowedProducts = (journeys: Journey[] | undefined): string[] => {
const products = data.station?.products || [];
const types = data?.journeys
?.flatMap((journey) => journey.connections.map((conn) => conn.lineInformation?.type))
const types = journeys!
.flatMap((journey) => journey.connections.map((conn) => conn.lineInformation?.type))
.filter(Boolean);
return products.filter((product) => types.includes(product));
};
</script>

<div class="scrollbar-track-sky-300 container mx-auto flex flex-1 flex-col divide-y-2 md:divide-y-0">
{#each data.journeys as journey}
{#if !matchesFilter(journey)}{:else if journey.connections.length > 1}
<WingTrain {journey} />
{:else}
<ConnectionComponent connection={journey.connections[0]} renderInformation={true} renderBorder={true} />
{/if}
{/each}
</div>

<div class="sticky bottom-0 mt-auto w-full">
<Filter allowedProducts={allowedProducts()} bind:selected={currentFilter} />
</div>
{#await data.journeys}
<div class="mx-auto flex-1">
<Loader />
</div>
{:then journeys}
<div class="scrollbar-track-sky-300 container mx-auto flex flex-1 flex-col divide-y-2 md:divide-y-0">
{#each journeys as journey}
{#if !matchesFilter(journey)}{:else if journey.connections.length > 1}
<WingTrain {journey} />
{:else}
<ConnectionComponent connection={journey.connections[0]} renderInformation={true} renderBorder={true} />
{/if}
{/each}
</div>

<div class="sticky bottom-0 mt-auto w-full">
<Filter allowedProducts={allowedProducts(journeys)} bind:selected={currentFilter} />
</div>
{/await}

0 comments on commit f2ef343

Please sign in to comment.