adds lists and trails to profile
This commit is contained in:
@@ -1,10 +1,5 @@
|
||||
<script lang="ts">
|
||||
export let fullWidth: boolean = false;
|
||||
</script>
|
||||
|
||||
|
||||
<div
|
||||
class="skeleton-card relative rounded-2xl animate-pulse flex flex-col {fullWidth ? "w-full" : "sm:w-72 w-80"} p-4 bg-menu-background border border-input-border"
|
||||
class="skeleton-card relative rounded-2xl animate-pulse flex flex-col min-w-72 p-4 bg-menu-background border border-input-border"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<!-- Image placeholder -->
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="trail-card relative rounded-2xl border border-input-border sm:w-72 cursor-pointer"
|
||||
class="trail-card relative rounded-2xl border border-input-border min-w-72 cursor-pointer"
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
role="listitem"
|
||||
|
||||
@@ -126,7 +126,9 @@
|
||||
{#if loading}
|
||||
{#each { length: 12 } as _, index}
|
||||
{#if selectedDisplayOption === "cards"}
|
||||
<SkeletonCard></SkeletonCard>
|
||||
<div class="flex-1">
|
||||
<SkeletonCard></SkeletonCard>
|
||||
</div>
|
||||
{:else}
|
||||
<SkeletonListItem></SkeletonListItem>
|
||||
{/if}
|
||||
@@ -139,7 +141,7 @@
|
||||
{/if}
|
||||
{#each trails as trail}
|
||||
<a
|
||||
class="max-w-full"
|
||||
class="max-w-full flex-1"
|
||||
class:basis-full={selectedDisplayOption === "list"}
|
||||
href="/trail/view/{trail.id}"
|
||||
data-sveltekit-preload-data="off"
|
||||
|
||||
@@ -5,30 +5,29 @@ import { pb } from "$lib/pocketbase";
|
||||
import { getFileURL } from "$lib/util/file_util";
|
||||
import { util } from "$lib/vendor/svelte-form-lib/util";
|
||||
import * as M from "maplibre-gl";
|
||||
import { ClientResponseError } from "pocketbase";
|
||||
import { get, writable, type Writable } from "svelte/store";
|
||||
import { ClientResponseError, type ListResult } from "pocketbase";
|
||||
import { writable, type Writable } from "svelte/store";
|
||||
import { summit_logs_create, summit_logs_delete, summit_logs_update } from "./summit_log_store";
|
||||
import { waypoints_create, waypoints_delete, waypoints_update } from "./waypoint_store";
|
||||
import type { Hits, SearchResponse } from "meilisearch";
|
||||
|
||||
export const trails: Writable<Trail[]> = writable([])
|
||||
let trails: Trail[] = []
|
||||
export const trail: Writable<Trail> = writable(new Trail(""));
|
||||
|
||||
export const editTrail: Writable<Trail> = writable(new Trail(""));
|
||||
|
||||
export async function trails_index(perPage: number = 21, random: boolean = false, setStore: boolean = true, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {
|
||||
export async function trails_index(perPage: number = 21, random: boolean = false, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {
|
||||
const r = await f('/api/v1/trail?' + new URLSearchParams({
|
||||
"per-page": perPage.toString(),
|
||||
expand: "category,waypoints,summit_logs",
|
||||
sort: random ? "@random" : ""
|
||||
sort: random ? "@random" : "",
|
||||
}), {
|
||||
method: 'GET',
|
||||
})
|
||||
const response = await r.json()
|
||||
const response: ListResult<Trail> = await r.json()
|
||||
|
||||
if (r.ok) {
|
||||
if (setStore) {
|
||||
trails.set(response.items);
|
||||
}
|
||||
trails = response.items
|
||||
return response.items;
|
||||
} else {
|
||||
throw new ClientResponseError(response)
|
||||
@@ -43,7 +42,7 @@ export async function trails_search_filter(filter: TrailFilter, page: number = 1
|
||||
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();
|
||||
const result: { page: number, totalPages: number, hits: Hits<Record<string, any>> } = await r.json();
|
||||
|
||||
if (!r.ok) {
|
||||
throw new ClientResponseError(result)
|
||||
@@ -52,7 +51,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) {
|
||||
return { trails: [], ...result };
|
||||
return { items: [], ...result };
|
||||
}
|
||||
|
||||
r = await f('/api/v1/trail?' + new URLSearchParams({
|
||||
@@ -62,10 +61,10 @@ export async function trails_search_filter(filter: TrailFilter, page: number = 1
|
||||
}), {
|
||||
method: 'GET',
|
||||
})
|
||||
const response = await r.json()
|
||||
const response: ListResult<Trail> = await r.json()
|
||||
|
||||
if (r.ok) {
|
||||
return { trails: response.items, ...result };
|
||||
return { items: response.items, ...result };
|
||||
} else {
|
||||
throw new ClientResponseError(response)
|
||||
}
|
||||
@@ -96,9 +95,9 @@ export async function trails_search_bounding_box(northEast: M.LngLat, southWest:
|
||||
const trailIds = result.hits?.map((h: Record<string, any>) => h.id) ?? [];
|
||||
|
||||
if (trailIds.length == 0) {
|
||||
const currentTrails: Trail[] = get(trails);
|
||||
const currentTrails: Trail[] = trails;
|
||||
const comparison = compareObjectArrays<Trail>(currentTrails, []);
|
||||
|
||||
trails = [];
|
||||
return { trails: [], ...comparison }
|
||||
}
|
||||
|
||||
@@ -123,8 +122,8 @@ export async function trails_search_bounding_box(northEast: M.LngLat, southWest:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const comparison = compareObjectArrays<Trail>(get(trails), response.items)
|
||||
const comparison = compareObjectArrays<Trail>(trails, response.items)
|
||||
trails = response.items;
|
||||
|
||||
return { trails: response.items, ...comparison };
|
||||
} else {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
import Scene from "$lib/components/scene.svelte";
|
||||
import TrailCard from "$lib/components/trail/trail_card.svelte";
|
||||
import { categories } from "$lib/stores/category_store";
|
||||
import { trails } from "$lib/stores/trail_store";
|
||||
import { currentUser } from "$lib/stores/user_store";
|
||||
import { country_codes } from "$lib/util/country_code_util";
|
||||
import { Canvas } from "@threlte/core";
|
||||
|
||||
@@ -4,7 +4,7 @@ import { trails_index } from "$lib/stores/trail_store";
|
||||
import type { ServerLoad } from "@sveltejs/kit";
|
||||
|
||||
export const load: ServerLoad = async ({ params, locals, fetch }) => {
|
||||
const trails: Trail[] = await trails_index(20, true, false, fetch)
|
||||
const trails: Trail[] = await trails_index(20, true, fetch)
|
||||
await categories_index(fetch)
|
||||
|
||||
return {trails}
|
||||
|
||||
@@ -316,7 +316,7 @@
|
||||
<div class="px-4 mt-2" class:space-y-3={loading}>
|
||||
{#if loading}
|
||||
{#each { length: 3 } as _, index}
|
||||
<SkeletonCard fullWidth></SkeletonCard>
|
||||
<SkeletonCard></SkeletonCard>
|
||||
{/each}
|
||||
{:else}
|
||||
{#each data.lists.items as item, i}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { TrailFilter } from "$lib/models/trail";
|
||||
import { categories_index } from "$lib/stores/category_store";
|
||||
import { trails, trails_get_bounding_box, trails_get_filter_values } from "$lib/stores/trail_store";
|
||||
import { trails_get_bounding_box, trails_get_filter_values } from "$lib/stores/trail_store";
|
||||
import type { ServerLoad } from "@sveltejs/kit";
|
||||
|
||||
export const load: ServerLoad = async ({ params, locals, fetch }) => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { getFileURL } from "$lib/util/file_util.js";
|
||||
import { _ } from "svelte-i18n";
|
||||
export let data;
|
||||
</script>
|
||||
@@ -22,10 +23,40 @@
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<div class="space-y-4">
|
||||
<h4 class="text-xl font-semibold">
|
||||
{$_("list", { values: { n: 2 } })}
|
||||
</h4>
|
||||
<div class="flex gap-x-4 overflow-x-scroll">
|
||||
{#each data.lists as list}
|
||||
<a
|
||||
href="/lists?list={list.id}"
|
||||
class="relative w-64 h-48 rounded-xl overflow-hidden group shrink-0"
|
||||
>
|
||||
{#if list.avatar}
|
||||
<img
|
||||
class="w-full h-full object-cover transition-transform group-hover:scale-110"
|
||||
src={getFileURL(list, list.avatar)}
|
||||
alt="avatar"
|
||||
/>
|
||||
{:else}
|
||||
<div
|
||||
class="flex w-16 md:w-20 aspect-square shrink-0 items-center justify-center"
|
||||
>
|
||||
<i class="fa fa-table-list text-5xl"></i>
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
class="absolute bottom-0 w-full h-2/3 bg-gradient-to-b from-transparent to-black opacity-50"
|
||||
></div>
|
||||
<h5
|
||||
class="absolute bottom-4 left-4 font-semibold text-white"
|
||||
>
|
||||
{list.name}
|
||||
</h5>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="text-xl font-semibold">Timeline</h4>
|
||||
|
||||
8
web/src/routes/profile/[id]/+page.ts
Normal file
8
web/src/routes/profile/[id]/+page.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { lists_index } from "$lib/stores/list_store";
|
||||
import { type Load } from "@sveltejs/kit";
|
||||
|
||||
export const load: Load = async ({ params, fetch }) => {
|
||||
|
||||
const lists = await lists_index({ q: "", author: params.id, sort: "created", sortOrder: "-" }, 1, -1, fetch)
|
||||
return { lists: lists.items }
|
||||
};
|
||||
@@ -1,10 +1,9 @@
|
||||
import type { SummitLogFilter } from "$lib/models/summit_log";
|
||||
import { categories_index } from "$lib/stores/category_store";
|
||||
import { summit_logs_index } from "$lib/stores/summit_log_store";
|
||||
import { users_show } from "$lib/stores/user_store";
|
||||
import { error, type ServerLoad } from "@sveltejs/kit";
|
||||
import { error, type Load } from "@sveltejs/kit";
|
||||
|
||||
export const load: ServerLoad = async ({ params, locals, fetch }) => {
|
||||
export const load: Load = async ({ params, fetch }) => {
|
||||
|
||||
if(!params.id) {
|
||||
error(404, "Not found")
|
||||
|
||||
34
web/src/routes/profile/[id]/trails/+page.svelte
Normal file
34
web/src/routes/profile/[id]/trails/+page.svelte
Normal file
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import TrailList from "$lib/components/trail/trail_list.svelte";
|
||||
import { trails_search_filter } from "$lib/stores/trail_store";
|
||||
|
||||
export let data;
|
||||
|
||||
let loading = true;
|
||||
|
||||
$: pagination = {
|
||||
page: data.trails.page,
|
||||
totalPages: data.trails.totalPages,
|
||||
};
|
||||
|
||||
async function handleFilterUpdate() {
|
||||
loading = true;
|
||||
data.trails = await trails_search_filter(data.filter, pagination.page);
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
||||
async function paginate(page: number) {
|
||||
pagination.page = page;
|
||||
data.trails = await trails_search_filter(data.filter, page);
|
||||
}
|
||||
</script>
|
||||
|
||||
<TrailList
|
||||
{pagination}
|
||||
{loading}
|
||||
trails={data.trails.items}
|
||||
filter={data.filter}
|
||||
on:update={() => handleFilterUpdate()}
|
||||
on:pagination={(e) => paginate(e.detail)}
|
||||
></TrailList>
|
||||
30
web/src/routes/profile/[id]/trails/+page.ts
Normal file
30
web/src/routes/profile/[id]/trails/+page.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import type { TrailFilter } from "$lib/models/trail";
|
||||
import { trails_index, trails_search_filter } from "$lib/stores/trail_store";
|
||||
import { type Load } from "@sveltejs/kit";
|
||||
|
||||
export const load: Load = async ({ params, fetch }) => {
|
||||
const filter: TrailFilter = {
|
||||
q: "",
|
||||
category: [],
|
||||
difficulty: ["easy", "moderate", "difficult"],
|
||||
author: params.id,
|
||||
public: true,
|
||||
shared: true,
|
||||
near: {
|
||||
radius: 2000,
|
||||
},
|
||||
distanceMin: 0,
|
||||
distanceMax: 0,
|
||||
distanceLimit: 0,
|
||||
elevationGainMin: 0,
|
||||
elevationGainMax: 0,
|
||||
elevationGainLimit: 0,
|
||||
elevationLossMin: 0,
|
||||
elevationLossMax: 0,
|
||||
elevationLossLimit: 0,
|
||||
sort: "created",
|
||||
sortOrder: "+",
|
||||
};
|
||||
const trails = await trails_search_filter(filter, 1, fetch)
|
||||
return { trails, filter }
|
||||
};
|
||||
@@ -101,7 +101,7 @@
|
||||
for (const trail of trails) {
|
||||
const gpxData: string = await fetchGPX(trail);
|
||||
if (!trail.expand) {
|
||||
trail.expand = {};
|
||||
(trail as any).expand = {};
|
||||
}
|
||||
trail.expand.gpx_data = gpxData;
|
||||
const trailFolder = zip.folder(`${trail.name}`);
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
async function handleFilterUpdate() {
|
||||
loading = true;
|
||||
const response = await trails_search_filter(filter, pagination.page);
|
||||
trails = response.trails;
|
||||
trails = response.items;
|
||||
pagination.page = response.page;
|
||||
pagination.totalPages = response.totalPages;
|
||||
loading = false;
|
||||
@@ -37,7 +37,7 @@
|
||||
async function paginate(page: number) {
|
||||
pagination.page = page;
|
||||
const response = await trails_search_filter(filter, page);
|
||||
trails = response.trails;
|
||||
trails = response.items;
|
||||
$page.url.searchParams.set("page", page.toString());
|
||||
goto(`?${$page.url.searchParams.toString()}`);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Trail, TrailFilter } from "$lib/models/trail";
|
||||
import type { TrailFilter } from "$lib/models/trail";
|
||||
import { categories_index } from "$lib/stores/category_store";
|
||||
import { trails_get_filter_values, trails_search_filter } from "$lib/stores/trail_store";
|
||||
import { trails_get_filter_values } from "$lib/stores/trail_store";
|
||||
import type { ServerLoad } from "@sveltejs/kit";
|
||||
|
||||
export const load: ServerLoad = async ({ params, locals, url, fetch }) => {
|
||||
|
||||
Reference in New Issue
Block a user