adds new default state images

This commit is contained in:
Christian Beutel
2024-03-11 00:08:02 +01:00
parent a2819f3b45
commit 02c82d3e46
25 changed files with 191 additions and 98 deletions

View File

@@ -13,7 +13,7 @@
beforeNavigate((n) => {
if (!$currentUser && isRouteProtected(n.to?.url?.pathname ?? "")) {
n.cancel();
goto("/login");
goto("/login?r="+n.to?.url?.pathname);
}
});
</script>

View File

@@ -108,6 +108,16 @@
id="trails"
class="flex flex-wrap justify-items-center gap-8 py-8 order-1 md:order-none"
>
{#if $trails.length == 0}
<div>
<img
style="max-width: 450px"
class="rounded-full aspect-square"
src="/imgs/default_thumbnail.webp"
alt="Empty State showing a wanderer going into the distance"
/>
</div>
{/if}
{#each { length: Math.min($trails.length, 4) } as _, i}
<a href="/trail/view/{$trails[i].id}">
<TrailCard trail={$trails[i]}></TrailCard></a
@@ -115,18 +125,33 @@
{/each}
</div>
<div class="max-w-md md:mx-auto space-y-8">
<h2 class="text-4xl md:text-5xl font-bold">
{$currentUser ? $_("trails-for-you") : $_("explore-some-trails")}
</h2>
<h5>
{$_("hero_section_1_text")}
</h5>
<a
class="inline-block btn-primary btn-large"
href="/trails"
data-sveltekit-preload-data="off"
role="button">{$_("explore")}</a
>
{#if $trails.length == 0}
<h2 class="text-4xl md:text-5xl font-bold">
{$_("hero_section_1_heading")}
</h2>
<h5>{$_("hero_section_1_text_alternative")}</h5>
<a
class="inline-block btn-primary btn-large"
href="/trail/edit/new"
data-sveltekit-preload-data="off"
role="button">{$_("new-trail")}</a
>
{:else}
<h2 class="text-4xl md:text-5xl font-bold">
{$currentUser
? $_("trails-for-you")
: $_("explore-some-trails")}
</h2>
<h5>
{$_("hero_section_1_text")}
</h5>
<a
class="inline-block btn-primary btn-large"
href="/trails"
data-sveltekit-preload-data="off"
role="button">{$_("explore")}</a
>
{/if}
</div>
</section>
<section

View File

@@ -11,6 +11,7 @@
import { object, string } from "yup";
import { theme } from "$lib/stores/theme_store";
import { _ } from "svelte-i18n";
import { page } from "$app/stores";
let loading: boolean = false;
const { form, errors, handleChange, handleSubmit } = createForm<User>({
@@ -20,14 +21,14 @@
password: "",
},
validationSchema: object<User>({
username: string().required("Required"),
password: string().required("Required"),
username: string().required($_("required")),
password: string().required($_("required")),
}),
onSubmit: async (newUser) => {
loading = true;
try {
await login(newUser);
goto(`/`);
goto($page.url.searchParams.get("r") ?? "/");
} catch (e) {
if (
e instanceof ClientResponseError &&
@@ -36,13 +37,13 @@
show_toast({
icon: "close",
type: "error",
text: "Wrong username or password.",
text: $_('wrong-username-or-password'),
});
} else {
show_toast({
icon: "close",
type: "error",
text: "Error during login.",
text: $_('error-during-login'),
});
}
} finally {
@@ -90,9 +91,9 @@
>
</div>
<span
>{$_('no-account')} <a
class="text-blue-500 underline"
href="/register">{$_('make-one')}</a
>{$_("no-account")}
<a class="text-blue-500 underline" href="/register"
>{$_("make-one")}</a
></span
>
</form>

View File

@@ -47,7 +47,7 @@
let showFilter: boolean = false;
let showMap: boolean = true;
let filter: TrailFilter;
const filter: TrailFilter = $page.data.filter;
onMount(async () => {
L = (await import("leaflet")).default;
@@ -130,20 +130,26 @@
const response = await r.json();
const trailItems = response.results[0].hits.map((t: Record<string, any>) => ({
text: t.name,
description: `Trail | ${t.location}`,
value: t,
icon: "route",
}));
const cityItems = response.results[1].hits.map((c: Record<string, any>) => ({
text: c.name,
description: `City | ${
country_codes[c["country code"] as keyof typeof country_codes]
}`,
value: c,
icon: "city",
}));
const trailItems = response.results[0].hits.map(
(t: Record<string, any>) => ({
text: t.name,
description: `Trail | ${t.location}`,
value: t,
icon: "route",
}),
);
const cityItems = response.results[1].hits.map(
(c: Record<string, any>) => ({
text: c.name,
description: `City | ${
country_codes[
c["country code"] as keyof typeof country_codes
]
}`,
value: c,
icon: "city",
}),
);
searchDropdownItems = [...trailItems, ...cityItems];
}
@@ -291,7 +297,7 @@
categories={$categories}
showTrailSearch={false}
showCitySearch={false}
bind:filter
{filter}
on:update={(e) => handleFilterUpdate(e.detail)}
></TrailFilterPanel>
</div>

View File

@@ -1,9 +1,27 @@
import type { TrailFilter } from "$lib/models/trail";
import { categories_index } from "$lib/stores/category_store";
import { trails } from "$lib/stores/trail_store";
import type { ServerLoad } from "@sveltejs/kit";
export const load: ServerLoad = async ({ params, locals, fetch }) => {
const filter: TrailFilter = {
q: "",
category: [],
difficulty: ["easy", "moderate", "difficult"],
near: {
radius: 2000,
},
distanceMin: 0,
distanceMax: 20000,
elevationGainMin: 0,
elevationGainMax: 4000,
sort: "created",
sortOrder: "+",
};
await categories_index(fetch)
trails.set([])
return { filter: filter }
};

View File

@@ -35,6 +35,10 @@
];
let activeTab = 0;
const thumbnail = $trail.photos.length
? getFileURL(trail, $trail.photos[$trail.thumbnail])
: "/imgs/default_thumbnail.webp";
onMount(() => {
lightboxDataSource = $trail.photos.map((p) => ({
src: getFileURL($trail, p),
@@ -83,7 +87,7 @@
<section class="relative h-80">
<img
class="w-full h-80 object-cover"
src={getFileURL($trail, $trail.photos[$trail.thumbnail])}
src={thumbnail}
alt=""
/>
<div

View File

@@ -6,11 +6,10 @@
import LogoTextTwoLineLight from "$lib/components/logo/logo_text_two_line_light.svelte";
import { theme } from "$lib/stores/theme_store";
import { show_toast } from "$lib/stores/toast_store";
import { users_create, type User, login } from "$lib/stores/user_store";
import { login, users_create, type User } from "$lib/stores/user_store";
import { createForm } from "$lib/vendor/svelte-form-lib";
import { object, string } from "yup";
import { _ } from "svelte-i18n";
import { object, string } from "yup";
let loading: boolean = false;
const { form, errors, handleChange, handleSubmit } = createForm<User>({
initialValues: {
@@ -20,11 +19,15 @@
password: "",
},
validationSchema: object<User>({
username: string().required("Required"),
email: string().email().required("Required"),
username: string()
.required($_("required"))
.matches(/^[\w][\w\.]*$/, { message: $_("invalid-username") }),
email: string()
.email($_("not-a-valid-email-address"))
.required($_("required")),
password: string()
.min(8, "Must be at least 8 characters long")
.required("Required"),
.min(8, $_("must-be-at-least-8-characters-long"))
.required($_("required")),
}),
onSubmit: async (newUser) => {
loading = true;
@@ -34,8 +37,9 @@
show_toast({
icon: "close",
type: "error",
text: "Error creating user.",
text: $_("error-creating-user"),
});
return;
} finally {
loading = false;
}
@@ -46,7 +50,7 @@
show_toast({
icon: "close",
type: "error",
text: "Error during login.",
text: $_("error-during-login"),
});
} finally {
loading = false;
@@ -56,7 +60,7 @@
</script>
<svelte:head>
<title>{$_('register')} | wanderer</title>
<title>{$_("register")} | wanderer</title>
</svelte:head>
<main class="flex justify-center">
<form

View File

@@ -10,7 +10,7 @@
import WaypointCard from "$lib/components/waypoint/waypoint_card.svelte";
import WaypointModal from "$lib/components/waypoint/waypoint_modal.svelte";
import { SummitLog } from "$lib/models/summit_log";
import { Trail, trailSchema } from "$lib/models/trail";
import { Trail } from "$lib/models/trail";
import { Waypoint } from "$lib/models/waypoint";
import { categories } from "$lib/stores/category_store";
import { summitLog } from "$lib/stores/summit_log_store";
@@ -37,6 +37,7 @@
import "leaflet/dist/leaflet.css";
import { onMount } from "svelte";
import { _ } from "svelte-i18n";
import { array, number, object, string } from "yup";
export let data: { trail: Trail };
@@ -55,6 +56,22 @@
let gpxFile: File | null = null;
const trailSchema = object<Trail>({
id: string().optional(),
name: string().required($_("required")),
location: string().optional(),
distance: number().optional(),
difficulty: string()
.oneOf(["easy", "moderate", "difficult"])
.optional(),
elevation_gain: number().optional(),
duration: number().optional(),
thumbnail: string().optional(),
photos: array(string()).optional(),
gpx: string().optional(),
description: string().optional(),
});
onMount(async () => {
L = (await import("leaflet")).default;
await import("leaflet-gpx");
@@ -457,9 +474,9 @@
label={$_("difficulty")}
bind:value={$form.difficulty}
items={[
{ text: $_('easy'), value: "easy" },
{ text: $_('moderate'), value: "moderate" },
{ text: $_('difficult'), value: "difficult" },
{ text: $_("easy"), value: "easy" },
{ text: $_("moderate"), value: "moderate" },
{ text: $_("difficult"), value: "difficult" },
]}
></Select>
{#if $form.expand.category}

View File

@@ -39,6 +39,10 @@
let lightbox: PhotoSwipeLightbox;
let lightboxDataSource: DataSource;
const thumbnail = $trail.photos.length
? getFileURL(trail, $trail.photos[$trail.thumbnail])
: "/imgs/default_thumbnail.webp";
onMount(async () => {
const L = (await import("leaflet")).default;
await import("leaflet-gpx");
@@ -134,7 +138,7 @@
<section class="relative h-80">
<img
class="w-full h-80"
src={getFileURL($trail, $trail.photos[$trail.thumbnail])}
src={thumbnail}
alt=""
/>
<div