Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 104 additions & 56 deletions web/src/routes/lists/[[handle]]/[[id]]/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { afterNavigate, goto } from "$app/navigation";
import { browser } from "$app/environment";
import { page } from "$app/state";
import ActorSearch from "$lib/components/actor_search.svelte";
import type { DropdownItem } from "$lib/components/base/dropdown.svelte";
Expand All @@ -21,7 +22,6 @@
import {
lists_delete,
lists_search_filter,
lists_show,
} from "$lib/stores/list_store";
import { trails_show } from "$lib/stores/trail_store";
import { currentUser } from "$lib/stores/user_store";
Expand Down Expand Up @@ -56,18 +56,15 @@
let markers: M.Marker[] = $state([]);

let selectedList: List | null = $state(
untrack(() =>
page.params.handle && page.params.id ? data.lists.items[0] : null,
),
untrack(() => data.selectedList ?? null),
);
let selectedTrail: Trail | null = $state(null);
let applyingTrailHash = false;

let loading: boolean = $state(true);
let loadingNextPage: boolean = false;
let filterExpanded: boolean = $state(false);

let loadAllListsOnNextBack = false;

let userQuery = $state("");

let selectedTrailIndex = $derived(selectedTrail ? 0 : null);
Expand All @@ -76,16 +73,87 @@
(selectedTrail as Trail | null)?.expand?.waypoints_via_trail,
);

onMount(() => {
if (page.params.handle && page.params.id) {
// setCurrentList(data.lists[0]);
// only the requested list has been loaded at this point
// load all lists the next time the user presses the back button
loadAllListsOnNextBack = true;
function listHref(item: List) {
return `/lists/${handleFromRecordWithIRI(item)}/${item.id}`;
}

function currentListHref() {
if (!selectedList) {
return "/lists";
}
return listHref(selectedList);
}

$effect(() => {
const nextList = data.selectedList ?? null;
const id = page.params.id;
if (!id) {
selectedList = null;
return;
}
if (nextList?.id === id) {
selectedList = nextList;
}
});

$effect(() => {
if (!browser) {
return;
}
const hash = page.url.hash.replace(/^#/, "");
const list = selectedList;
untrack(() => {
void applyTrailHash(hash, list);
});
});

afterNavigate(() => {
if (page.params.id) {
document.getElementById("list-container")?.scrollTo({ top: 0 });
}
});

onMount(async () => {
if (lists.length === 0) {
const response = await lists_search_filter(filter, 1);
lists = response.items;
pagination.page = response.page;
pagination.totalPages = response.totalPages;
}
loading = false;
});

async function applyTrailHash(hash: string, list: List | null) {
if (!hash || !list) {
if (!hash) {
selectedTrail = null;
}
return;
}
if (selectedTrail?.id === hash || applyingTrailHash) {
return;
}
const trail = list.expand?.trails?.find((item) => item.id === hash);
if (!trail) {
selectedTrail = null;
return;
}
applyingTrailHash = true;
try {
selectedTrail = await trails_show(
trail.iri
? trail.iri.substring(trail.iri.length - 15)
: trail.id!,
handleFromRecordWithIRI(trail),
undefined,
true,
);
mapWithElevation?.unHighlightTrail(trail.id!);
} finally {
applyingTrailHash = false;
}
}

async function handleDropdownClick(item: DropdownItem) {
if (!selectedList) {
return;
Expand All @@ -104,47 +172,31 @@
return;
}
await lists_delete(selectedList);
await updateFilter();
selectedList = null;
await goto("/lists", { noScroll: true });
await updateFilter(false);
}

async function setCurrentList(item: List) {
const fullList = await lists_show(
item.id!,
handleFromRecordWithIRI(item),
fetch,
);
selectedList = fullList;
await goto(listHref(item), { noScroll: true, keepFocus: true });
document.getElementById("list-container")?.scrollTo({ top: 0 });
}

async function back() {
if (selectedTrail) {
selectedTrail = null;
} else if (selectedList) {
selectedList = null;
map?.flyTo({
animate: true,
zoom: 1,
center: [0, 0],
});
}
if (loadAllListsOnNextBack) {
await updateFilter(false);
loadAllListsOnNextBack = false;
if (selectedTrail && selectedList) {
await goto(currentListHref(), { noScroll: true, keepFocus: true });
return;
}
await goto("/lists", { noScroll: true, keepFocus: true });
}

async function selectTrail(trail: Trail) {
const fullTrail = await trails_show(
trail.iri ? trail.iri.substring(trail.iri.length - 15) : trail.id!,
handleFromRecordWithIRI(trail),
undefined,
true,
);
selectedTrail = fullTrail;

mapWithElevation?.unHighlightTrail(trail.id!);
if (!selectedList) {
return;
}
await goto(`${currentListHref()}#${trail.id}`, {
noScroll: true,
keepFocus: true,
});
window.scrollTo({ top: 0 });
}

Expand Down Expand Up @@ -185,13 +237,7 @@
loading = true;

if ((selectedList || selectedTrail) && resetMap) {
selectedList = null;
selectedTrail = null;
map?.flyTo({
animate: true,
zoom: 1,
center: [0, 0],
});
await goto("/lists", { noScroll: true, keepFocus: true });
}

pagination.page = 1;
Expand Down Expand Up @@ -347,13 +393,13 @@
<EmptyStateSearch width={356}></EmptyStateSearch>
{:else}
{#each lists as item, i}
<div
class="list-list-item"
onclick={() => setCurrentList(item)}
role="presentation"
<a
class="list-list-item block"
href={listHref(item)}
data-sveltekit-noscroll
>
<ListCard list={item}></ListCard>
</div>
</a>
{/each}
{/if}
</div>
Expand Down Expand Up @@ -387,7 +433,9 @@
activeTrail={selectedTrailIndex}
fitBounds="animate"
onselect={(trail) => {
selectedTrail = trail;
if (selectedList && trail.id !== selectedTrail?.id) {
selectTrail(trail);
}
}}
showInfoPopup={true}
showTerrain={true}
Expand Down
34 changes: 21 additions & 13 deletions web/src/routes/lists/[[handle]]/[[id]]/+page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { type ListFilter } from "$lib/models/list";
import { lists_search_filter, lists_show } from "$lib/stores/list_store";
import { APIError } from "$lib/util/api_util";
import { error, type Load, type NumericRange } from "@sveltejs/kit";
import type { AuthRecord } from "pocketbase";

export const load: Load = async ({ params, fetch, url }) => {
export const load: Load = async ({ params, fetch, parent }) => {
const filter: ListFilter = {
q: "",
author: "",
Expand All @@ -14,25 +15,32 @@ export const load: Load = async ({ params, fetch, url }) => {
sortOrder: "+",
};

let lists: Awaited<ReturnType<typeof lists_search_filter>>;
const parentData = await parent();
const user = (parentData as { user?: AuthRecord }).user;

let lists: Awaited<ReturnType<typeof lists_search_filter>> = {
items: [],
page: 1,
totalPages: 1,
hits: [],
};
if (browser) {
lists = await lists_search_filter(filter, 1, undefined, fetch, user);
}

let selectedList: Awaited<ReturnType<typeof lists_show>> | null = null;
if (params.handle && params.id) {
try {
const list = await lists_show(params.id, params.handle, fetch)

lists = { items: [list], page: 1, totalPages: 1, hits: [] }
selectedList = await lists_show(params.id, params.handle, fetch);
} catch (e) {
if (e instanceof APIError) {
error(e.status as NumericRange<400, 599>, {
message: e.status == 404 ? 'Not found' : e.message
message: e.status == 404 ? "Not found" : e.message,
});
}
throw e
throw e;
}
} else if (browser) {
lists = await lists_search_filter(filter, 1, undefined, fetch);
} else {
lists = { items: [], page: 1, totalPages: 1, hits: [] }
}

return { lists, filter }
};
return { lists, filter, selectedList };
};
4 changes: 2 additions & 2 deletions web/src/routes/map/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
const listItems = (r[1]?.hits || []).map((t: ListSearchResult) => ({
text: t.name,
description: `List, ${t.trails} ${$_("trail", { values: { n: t.trails } })}`,
value: t.id,
value: `@${t.author_name}${t.domain ? `@${t.domain}` : ""}/${t.id}`,
icon: "layer-group",
}));
const cityItems = (r[2]?.hits || []).map((c: LocationSearchResult) => ({
Expand All @@ -126,7 +126,7 @@
if (item.icon == "route") {
goto(`/map/trail/${item.value}`);
} else if (item.icon == "layer-group") {
goto(`/lists?list=${item.value}`);
goto(`/lists/${item.value}`);
} else {
map?.setCenter([item.value.lon, item.value.lat]);
map?.setZoom(14);
Expand Down
Loading