adds loaders for trail cards and lists

This commit is contained in:
Christian Beutel
2024-12-02 20:21:25 +01:00
parent a5a7532559
commit 4d6657b64e
10 changed files with 150 additions and 76 deletions

View File

@@ -0,0 +1,14 @@
<div
class="skeleton-card relative rounded-2xl sm:w-72 animate-pulse flex flex-col w-80 p-4 bg-menu-background border border-input-border"
aria-hidden="true"
>
<!-- Image placeholder -->
<div class="h-48 bg-menu-item-background-focus rounded-md"></div>
<!-- Text placeholders -->
<div class="mt-4 space-y-3">
<div class="h-4 bg-menu-item-background-focus rounded w-3/4"></div>
<div class="h-4 bg-menu-item-background-focus rounded w-full"></div>
<div class="h-4 bg-menu-item-background-focus rounded w-1/2"></div>
</div>
</div>

View File

@@ -0,0 +1,16 @@
<div
class="skeleton-list-item animate-pulse flex items-center gap-4 p-4 bg-menu-background rounded-xl border border-input-border basis-full"
aria-hidden="true"
>
<!-- Avatar placeholder -->
<div class="h-28 w-28 bg-menu-item-background-focus rounded-xl shrink-0"></div>
<!-- Text placeholders -->
<div class="basis-full shrink-0 space-y-2">
<div class="h-4 bg-menu-item-background-focus rounded w-1/3"></div>
<div class="h-4 bg-menu-item-background-focus rounded w-1/5"></div>
<div class="h-4 bg-menu-item-background-focus rounded w-2/3"></div>
<div class="h-4 bg-menu-item-background-focus rounded w-1/2"></div>
</div>
</div>

View File

@@ -355,6 +355,7 @@
);
epc?.showProfile();
}
showWaypoints();
flyToBounds();
}
@@ -367,6 +368,7 @@
if (showElevation) {
epc?.hideProfile();
}
hideWaypoints();
}
function addStartEndMarkers(
@@ -418,6 +420,26 @@
layers[id]?.startMarker?.togglePopup();
}
function showWaypoints() {
if (!map) {
return;
}
for (const waypoint of trails[activeTrail]?.expand.waypoints ?? []) {
const marker = createMarkerFromWaypoint(waypoint);
marker.addTo(map);
markers.push(marker);
}
}
function hideWaypoints() {
if (!map) {
return;
}
for (const m of markers) {
m.remove()
}
}
onMount(async () => {
const initialState = {
lng: 0,
@@ -465,7 +487,7 @@
(s) => s.text === localStorage.getItem("layer"),
);
if(preferredMapStyleIndex == -1) {
if (preferredMapStyleIndex == -1) {
preferredMapStyleIndex = 0;
}
@@ -567,7 +589,7 @@
addTrailLayer(t, t.id ?? i.toString(), data?.at(i));
});
if (showTerrain && $page.data.settings?.terrain) {
if (showTerrain && $page.data.settings?.terrain && !map?.getSource("terrain")) {
map!.addSource("terrain", {
type: "raster-dem",
url: $page.data.settings.terrain,
@@ -600,11 +622,7 @@
dispatch("init", map);
});
for (const waypoint of trails[activeTrail]?.expand.waypoints ?? []) {
const marker = createMarkerFromWaypoint(waypoint);
marker.addTo(map);
markers.push(marker);
}
showWaypoints();
});
onDestroy(() => {

View File

@@ -7,6 +7,8 @@
import EmptyStateSearch from "../empty_states/empty_state_search.svelte";
import TrailCard from "./trail_card.svelte";
import TrailListItem from "./trail_list_item.svelte";
import SkeletonCard from "../base/skeleton_card.svelte";
import SkeletonListItem from "../base/skeleton_list_item.svelte";
export let filter: TrailFilter | null = null;
export let trails: Trail[];
@@ -15,6 +17,8 @@
totalPages: 1,
};
export let loading: boolean = false;
const displayOptions: SelectItem[] = [
{ text: $_("card", { values: { n: 2 } }), value: "cards" },
{ text: $_("list", { values: { n: 1 } }), value: "list" },
@@ -58,7 +62,7 @@
}
function setSort() {
if(!filter) {
if (!filter) {
return;
}
localStorage.setItem("sort", filter.sort);
@@ -66,7 +70,7 @@
}
function setSortOrder() {
if(!filter) {
if (!filter) {
return;
}
if (filter.sortOrder === "+") {
@@ -119,25 +123,35 @@
</div>
<div id="trails" class="flex items-start flex-wrap gap-8 py-8 max-w-full">
{#if trails.length == 0}
<div class="flex flex-col basis-full items-center">
<EmptyStateSearch width={356}></EmptyStateSearch>
</div>
{/if}
{#each trails as trail}
<a
class="max-w-full"
class:basis-full={selectedDisplayOption === "list"}
href="/trail/view/{trail.id}"
data-sveltekit-preload-data="off"
>
{#if loading}
{#each { length: 12 } as _, index}
{#if selectedDisplayOption === "cards"}
<TrailCard {trail}></TrailCard>
<SkeletonCard></SkeletonCard>
{:else}
<TrailListItem {trail}></TrailListItem>
<SkeletonListItem></SkeletonListItem>
{/if}
</a>
{/each}
{/each}
{:else}
{#if trails.length == 0}
<div class="flex flex-col basis-full items-center">
<EmptyStateSearch width={356}></EmptyStateSearch>
</div>
{/if}
{#each trails as trail}
<a
class="max-w-full"
class:basis-full={selectedDisplayOption === "list"}
href="/trail/view/{trail.id}"
data-sveltekit-preload-data="off"
>
{#if selectedDisplayOption === "cards"}
<TrailCard {trail}></TrailCard>
{:else}
<TrailListItem {trail}></TrailListItem>
{/if}
</a>
{/each}
{/if}
</div>
<Pagination
page={pagination.page}

View File

@@ -26,7 +26,7 @@ export async function trails_index(perPage: number = 21, random: boolean = false
const response = await r.json()
if (r.ok) {
if(setStore) {
if (setStore) {
trails.set(response.items);
}
return response.items;
@@ -40,7 +40,7 @@ export async function trails_search_filter(filter: TrailFilter, page: number = 1
let r = await f("/api/v1/search/trails", {
method: "POST",
body: JSON.stringify({ q: filter.q, options: { filter: filterText, sort: [`${filter.sort}:${filter.sortOrder == "+" ? "asc" : "desc"}`], hitsPerPage: 21, page: page } }),
body: JSON.stringify({ q: filter.q, options: { filter: filterText, sort: [`${filter.sort}:${filter.sortOrder == "+" ? "asc" : "desc"}`], hitsPerPage: 12, page: page } }),
});
const result = await r.json();
@@ -52,8 +52,7 @@ export async function trails_search_filter(filter: TrailFilter, page: number = 1
const trailIds = result.hits.map((h: Record<string, any>) => h.id);
if (trailIds.length == 0) {
trails.set([]);
return [];
return { trails: [], ...result };
}
r = await f('/api/v1/trail?' + new URLSearchParams({
@@ -66,8 +65,7 @@ export async function trails_search_filter(filter: TrailFilter, page: number = 1
const response = await r.json()
if (r.ok) {
trails.set(response.items);
return result;
return { trails: response.items, ...result };
} else {
throw new ClientResponseError(response)
}
@@ -85,7 +83,7 @@ export async function trails_search_bounding_box(northEast: M.LngLat, southWest:
method: "POST",
body: JSON.stringify({
q: "", options: {
limit: 400,
limit: 100,
filter: [
`_geoBoundingBox([${northEast.lat}, ${northEast.lng}], [${southWest.lat}, ${southWest.lng}])`,
filterText
@@ -99,8 +97,9 @@ export async function trails_search_bounding_box(northEast: M.LngLat, southWest:
if (trailIds.length == 0) {
const currentTrails: Trail[] = get(trails);
trails.set([]);
return compareObjectArrays<Trail>(currentTrails, []);
const comparison = compareObjectArrays<Trail>(currentTrails, []);
return { trails: [], ...comparison }
}
r = await fetch('/api/v1/trail?' + new URLSearchParams({
@@ -127,11 +126,7 @@ export async function trails_search_bounding_box(northEast: M.LngLat, southWest:
const comparison = compareObjectArrays<Trail>(get(trails), response.items)
if (comparison.added.length || comparison.deleted.length || comparison.updated.length) {
trails.set(response.items);
}
return comparison;
return { trails: response.items, ...comparison };
} else {
throw new ClientResponseError(response)
}