adds new default state images
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 }
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user