adds trail sort on map

This commit is contained in:
Christian Beutel
2025-07-10 17:53:29 +02:00
parent 68f36dbf0c
commit d21df88be2
3 changed files with 80 additions and 14 deletions

View File

@@ -92,7 +92,7 @@ export async function trails_search_filter(filter: TrailFilter, page: number = 1
}
export async function trails_search_bounding_box(northEast: M.LngLat, southWest: M.LngLat, filter?: TrailFilter, page: number = 1, includePolyline: boolean = true) {
export async function trails_search_bounding_box(northEast: M.LngLat, southWest: M.LngLat, filter: TrailFilter, page: number = 1, includePolyline: boolean = true) {
const user = get(currentUser)
let filterText: string = "";
@@ -110,6 +110,7 @@ export async function trails_search_bounding_box(northEast: M.LngLat, southWest:
`_geoBoundingBox([${northEast.lat}, ${northEast.lng}], [${southWest.lat}, ${southWest.lng}])`,
filterText
],
sort: [`${filter.sort}:${filter.sortOrder == "+" ? "asc" : "desc"}`,],
attributesToRetrieve: [...defaultTrailSearchAttributes, ...(includePolyline ? ["polyline"] : [])],
hitsPerPage: 500,
page: page
@@ -527,9 +528,9 @@ function buildFilterText(user: AuthRecord, filter: TrailFilter, includeGeo: bool
if (filter.public !== undefined || filter.private !== undefined || filter.shared !== undefined) {
filterText += " AND ("
const showPublic = filter.public === undefined || filter.public === true;
const showPrivate = filter.private === undefined || filter.private === true;
const showShared = filter.shared !== undefined && filter.shared === true;
const showPublic = filter.public === undefined || filter.public === true;
const showPrivate = filter.private === undefined || filter.private === true;
const showShared = filter.shared !== undefined && filter.shared === true;
if (showPublic === true) {
filterText += "(public = TRUE";
@@ -551,7 +552,7 @@ function buildFilterText(user: AuthRecord, filter: TrailFilter, includeGeo: bool
}
}
filterText += ")";
}

View File

@@ -5,6 +5,8 @@
import Search, {
type SearchItem,
} from "$lib/components/base/search.svelte";
import type { SelectItem } from "$lib/components/base/select.svelte";
import Select from "$lib/components/base/select.svelte";
import SkeletonCard from "$lib/components/base/skeleton_card.svelte";
import EmptyStateSearch from "$lib/components/empty_states/empty_state_search.svelte";
import MapWithElevationMaplibre from "$lib/components/trail/map_with_elevation_maplibre.svelte";
@@ -54,6 +56,18 @@
totalPages: 1,
};
const sortOptions: SelectItem[] = [
{ text: $_("name"), value: "name" },
{ text: $_("distance"), value: "distance" },
{ text: $_("duration"), value: "duration" },
{ text: $_("difficulty"), value: "difficulty" },
{ text: $_("elevation-gain"), value: "elevation_gain" },
{ text: $_("elevation-loss"), value: "elevation_loss" },
{ text: $_("likes"), value: "like_count" },
{ text: $_("creation-date"), value: "created" },
{ text: $_("date"), value: "date" },
];
export const snapshot: Snapshot<TrailFilter> = {
capture: () => filter,
restore: (value) => {
@@ -126,6 +140,8 @@
pagination.page = 1;
loading = true;
}
console.log(filter);
const trailsInBox = await trails_search_bounding_box(
northEast,
southWest,
@@ -146,6 +162,27 @@
mapWithElevation?.unHighlightCluster();
}
function setSort() {
if (!filter) {
return;
}
localStorage.setItem("sort", filter.sort);
handleFilterUpdate();
}
function setSortOrder() {
if (!filter) {
return;
}
if (filter.sortOrder === "+") {
filter.sortOrder = "-";
} else {
filter.sortOrder = "+";
}
localStorage.setItem("sort_order", filter.sortOrder);
handleFilterUpdate();
}
async function handleFilterUpdate() {
if (!map) {
return;
@@ -222,7 +259,10 @@
maxBoundingBox.min_lat == maxBoundingBox.max_lat
) {
map?.setZoom(12);
map?.setCenter([maxBoundingBox.min_lon, maxBoundingBox.min_lat]);
map?.setCenter([
maxBoundingBox.min_lon,
maxBoundingBox.min_lat,
]);
} else {
const boundingBox: M.LngLatBoundsLike = [
[maxBoundingBox.min_lon, maxBoundingBox.max_lat],
@@ -288,7 +328,7 @@
class="flex flex-col items-stretch gap-4 px-3 md:px-8 overflow-y-scroll"
onscroll={onListScroll}
>
<div class="sticky top-0 z-10 bg-background pb-4 space-y-4">
<div class="sticky top-0 z-10 bg-background pb-4">
<div class="flex items-center gap-2 md:gap-4">
<Search
extraClasses="w-full"
@@ -297,12 +337,6 @@
placeholder="{$_('search-for-trails-places')}..."
items={searchDropdownItems}
></Search>
<button
aria-label="Open filter"
class="btn-icon"
onclick={() => (showFilter = !showFilter)}
><i class="fa fa-sliders"></i></button
>
<button
aria-label="Toggle map"
class="btn-icon md:hidden"
@@ -314,6 +348,28 @@
></i></button
>
</div>
<div class="flex items-center gap-2 mt-2 mb-4">
<Select
bind:value={filter.sort}
items={sortOptions}
onchange={setSort}
></Select>
<button
aria-label="Change sort order"
id="sort-order-btn"
class="btn-icon"
class:rotated={filter.sortOrder == "-"}
onclick={() => setSortOrder()}
><i class="fa fa-arrow-up"></i></button
>
<div class="basis-full"></div>
<button
aria-label="Open filter"
class="btn-icon"
onclick={() => (showFilter = !showFilter)}
><i class="fa fa-sliders"></i></button
>
</div>
{#if showFilter}
<div in:slide out:slide>
<TrailFilterPanel
@@ -345,6 +401,8 @@
<TrailCard
{trail}
fullWidth={true}
hovered={false}
selected={false}
onmouseenter={() =>
handleTrailCardMouseEnter(trail)}
onmouseleave={() =>
@@ -384,4 +442,11 @@
height: calc(100vh - 124px);
}
}
#sort-order-btn {
transition: transform 0.5s ease;
}
:global(.rotated) {
transform: rotate(180deg);
}
</style>

View File

@@ -30,7 +30,7 @@ export const load: ServerLoad = async ({ params, locals, fetch }) => {
elevationLossMax: filterValues.max_elevation_loss,
elevationLossLimit: filterValues.max_elevation_gain,
sort: "created",
sortOrder: "+",
sortOrder: "-",
};
await categories_index(fetch)