feat: add loading state to view
Some checks failed
TrafficCue CI / check (push) Failing after 57s
TrafficCue CI / build (push) Successful in 1m38s
TrafficCue CI / build-android (push) Successful in 15m1s

This commit is contained in:
2025-09-16 18:22:48 +02:00
parent 222216f172
commit 28796ee267
7 changed files with 105 additions and 14 deletions

View File

@ -0,0 +1,75 @@
<div class="progress-bar indeterminate bg-card/50 backdrop-blur-md">
<div class="short-bar"></div>
<div class="long-bar"></div>
</div>
<style>
@keyframes progressbarindeterminateshort {
0% {
left: -40%;
}
75% {
left: 120%;
}
100% {
left: 120%;
}
}
@keyframes progressbarindeterminatelong {
0% {
left: -90%;
}
37.5% {
left: -90%;
}
100% {
left: 100%;
}
}
.progress-bar {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
top: 0;
left: 0;
right: 0;
min-height: 5px;
position: absolute;
border-radius: 1.5px;
overflow: hidden !important;
}
.progress-bar > .short-bar {
background-color: var(--accent);
width: 40%;
height: 100%;
left: -40%;
border-radius: 2.5px;
position: absolute;
display: inline-block;
-webkit-animation: progressbarindeterminateshort 2s ease-in-out infinite;
-moz-animation: progressbarindeterminateshort 2s ease-in-out infinite;
-o-animation: progressbarindeterminateshort 2s ease-in-out infinite;
animation: progressbarindeterminateshort 2s ease-in-out infinite;
}
.progress-bar > .long-bar {
background-color: var(--accent);
width: 60%;
height: 100%;
left: -90%;
border-radius: 2.5px;
position: absolute;
display: inline-block;
-webkit-animation: progressbarindeterminatelong 2s ease-in-out infinite;
-moz-animation: progressbarindeterminatelong 2s ease-in-out infinite;
-o-animation: progressbarindeterminatelong 2s ease-in-out infinite;
animation: progressbarindeterminatelong 2s ease-in-out infinite;
}
</style>

View File

@ -24,6 +24,7 @@
import LoadingSidebar from "./sidebar/LoadingSidebar.svelte";
import { Tween } from "svelte/motion";
import { quintOut } from "svelte/easing";
import Progressbar from "../Progressbar.svelte";
const views: Record<string, string> = {
main: "MainSidebar",
@ -134,10 +135,6 @@
return () => value;
}
// TODO: implement loading state
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let loading = $state(false);
let searchText = $derived.by(debounce(() => searchbar.text, 300));
let searchResults: Feature[] = $state([]);
let mobileView = $derived(window.innerWidth < 768 || routing.currentTrip);
@ -149,10 +146,10 @@
return;
}
if (searchText.length > 0) {
loading = true;
view.loading = true;
search(searchText, 0, 0).then((results) => {
searchResults = results;
loading = false;
view.loading = false;
view.switch("search", {
results: searchResults,
query: searchText,
@ -211,6 +208,10 @@
</div>
{/if}
{#if view.loading}
<Progressbar />
{/if}
{#if routing.currentTrip}
<InRouteSidebar />
{:else}

View File

@ -27,6 +27,7 @@
import InternetAccess from "../info/InternetAccess.svelte";
import RestaurantInfo from "../info/RestaurantInfo.svelte";
import { m } from "$lang/messages";
import { onMount } from "svelte";
// let { feature }: { feature: Feature } = $props();
@ -81,9 +82,16 @@
);
});
}
onMount(() => {
view.loading = true;
})
</script>
{#await fetchPOI(lat, lng, 20)}
{#await fetchPOI(lat, lng, 20).then(r => {
view.loading = false;
return r;
})}
<SidebarHeader
onback={() => {
pin.liftPin();

View File

@ -4,19 +4,20 @@
import { fetchNearbyPOI, type OverpassElement } from "$lib/services/Overpass";
import { location } from "../location.svelte";
import { map, pin } from "../map.svelte";
import { view } from "../view.svelte";
import SidebarHeader from "./SidebarHeader.svelte";
let { tags }: { tags?: string } = $props();
let pois: OverpassElement[] = $state([]);
let loading = $state(true);
$effect(() => {
if (!tags) {
loading = false;
view.loading = false;
pois = [];
return;
}
view.loading = true;
fetchNearbyPOI(location.lat, location.lng, tags.split(","), 500).then(
(results) => {
pois = results.elements.sort((a, b) => {
@ -30,7 +31,7 @@
);
return distA - distB;
});
loading = false;
view.loading = false;
},
);
});
@ -60,7 +61,7 @@
{/if}
</SidebarHeader>
{#if loading}
{#if view.loading}
<div class="text-sm text-muted-foreground">{m.loading()}</div>
{:else}
<div class="flex flex-col gap-2 p-2">

View File

@ -69,6 +69,7 @@
</div>
<Button
onclick={async () => {
view.loading = true;
console.log(fromLocation, toLocation);
const FROM: WorldLocation =
fromLocation == "current"
@ -103,6 +104,7 @@
}
drawAllRoutes(routes);
zoomToPoints(FROM, TO, map.value!);
view.loading = false;
}}>{m["sidebar.route.calculate"]()}</Button
>

View File

@ -2,9 +2,9 @@
import { onMount } from "svelte";
import SidebarHeader from "../SidebarHeader.svelte";
import { m } from "$lang/messages";
import { view } from "../../view.svelte";
let licenses: License[] = $state([]);
let loading = $state(true);
interface License {
name: string;
@ -20,15 +20,16 @@
}
onMount(async () => {
view.loading = true;
const res = await fetch("/licenses.json");
licenses = await res.json();
loading = false;
view.loading = false;
});
</script>
<SidebarHeader>{m["sidebar.about.licenses"]()}</SidebarHeader>
{#if loading}
{#if view.loading}
<p>Loading...</p>
{:else if licenses.length == 0}
<p>No licenses found.</p>

View File

@ -6,9 +6,11 @@ export interface View {
}
export const view = $state({
loading: false,
current: { type: getOnboardingView("main") } as View,
history: [] as View[],
back: () => {
view.loading = false;
if (view.history.length > 0) {
view.current = view.history.pop()!;
} else {
@ -19,6 +21,7 @@ export const view = $state({
if (view.current.type !== to) {
view.history.push(view.current);
}
view.loading = false;
view.current = { type: to, props } as View;
},
});