adds trail difficulty property
This commit is contained in:
@@ -29,6 +29,7 @@ func indexRecord(r *models.Record, client *meilisearch.Client) error {
|
|||||||
"distance": r.GetFloat("distance"),
|
"distance": r.GetFloat("distance"),
|
||||||
"elevation_gain": r.GetFloat("elevation_gain"),
|
"elevation_gain": r.GetFloat("elevation_gain"),
|
||||||
"duration": r.GetFloat("duration"),
|
"duration": r.GetFloat("duration"),
|
||||||
|
"difficulty": r.Get("difficulty"),
|
||||||
"category": r.Get("category"),
|
"category": r.Get("category"),
|
||||||
"completed": len(r.GetStringSlice("summit_logs")) > 0,
|
"completed": len(r.GetStringSlice("summit_logs")) > 0,
|
||||||
"created": r.GetDateTime("created"),
|
"created": r.GetDateTime("created"),
|
||||||
|
|||||||
56
db/migrations/1710073788_updated_trails.go
Normal file
56
db/migrations/1710073788_updated_trails.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
|
"github.com/pocketbase/pocketbase/daos"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
"github.com/pocketbase/pocketbase/models/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(db dbx.Builder) error {
|
||||||
|
dao := daos.New(db);
|
||||||
|
|
||||||
|
collection, err := dao.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add
|
||||||
|
new_difficulty := &schema.SchemaField{}
|
||||||
|
json.Unmarshal([]byte(`{
|
||||||
|
"system": false,
|
||||||
|
"id": "dywtnynw",
|
||||||
|
"name": "difficulty",
|
||||||
|
"type": "select",
|
||||||
|
"required": false,
|
||||||
|
"presentable": false,
|
||||||
|
"unique": false,
|
||||||
|
"options": {
|
||||||
|
"maxSelect": 1,
|
||||||
|
"values": [
|
||||||
|
"easy",
|
||||||
|
"moderate",
|
||||||
|
"difficult"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`), new_difficulty)
|
||||||
|
collection.Schema.AddField(new_difficulty)
|
||||||
|
|
||||||
|
return dao.SaveCollection(collection)
|
||||||
|
}, func(db dbx.Builder) error {
|
||||||
|
dao := daos.New(db);
|
||||||
|
|
||||||
|
collection, err := dao.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove
|
||||||
|
collection.Schema.RemoveField("dywtnynw")
|
||||||
|
|
||||||
|
return dao.SaveCollection(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -32,27 +32,36 @@ services:
|
|||||||
build: ./db
|
build: ./db
|
||||||
environment:
|
environment:
|
||||||
<<: *cenv
|
<<: *cenv
|
||||||
|
depends_on:
|
||||||
|
bootstrap:
|
||||||
|
condition: service_completed_successfully
|
||||||
ports:
|
ports:
|
||||||
- "8090:8090"
|
- "8090:8090"
|
||||||
networks:
|
networks:
|
||||||
- wanderer
|
- wanderer
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/pb_data:/pb_data
|
- wanderer-db:/pb_data
|
||||||
|
|
||||||
web:
|
web:
|
||||||
build: ./web
|
build: ./web
|
||||||
environment:
|
environment:
|
||||||
|
<<: *cenv
|
||||||
|
MEILI_API_TOKEN:
|
||||||
ORIGIN: http://localhost:8080
|
ORIGIN: http://localhost:8080
|
||||||
PUBLIC_MEILISEARCH_URL: http://search:7700
|
|
||||||
PUBLIC_MEILISEARCH_API_TOKEN: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhcGlLZXlVaWQiOiIyMjk3NDg3Yy0zMjFlLTQ5MmEtYmRiNS1iZmYwZGYzZjc2NTYiLCJzZWFyY2hSdWxlcyI6eyJ0cmFpbHMiOnsiZmlsdGVyIjoicHVibGljPXRydWUifSwiY2l0aWVzNTAwIjp7fX0sImV4cCI6bnVsbH0.CuIlkiWAec8TGyZI5X37JTjQvcnvFAFZAuA4xpbXJ8o
|
|
||||||
PUBLIC_POCKETBASE_URL: http://db:8090
|
PUBLIC_POCKETBASE_URL: http://db:8090
|
||||||
ports:
|
ports:
|
||||||
- "8080:3000"
|
- "8080:3000"
|
||||||
|
depends_on:
|
||||||
|
bootstrap:
|
||||||
|
condition: service_completed_successfully
|
||||||
networks:
|
networks:
|
||||||
- wanderer
|
- wanderer
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
wanderer-db:
|
||||||
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
wanderer:
|
wanderer:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ def init_indices():
|
|||||||
client.create_index('trails', {'primaryKey': 'id'})
|
client.create_index('trails', {'primaryKey': 'id'})
|
||||||
|
|
||||||
client.index('trails').update_settings({
|
client.index('trails').update_settings({
|
||||||
'sortableAttributes': ['name', 'distance', 'elevation_gain', 'created',],
|
'sortableAttributes': ['name', 'distance', 'elevation_gain', 'difficulty', 'created',],
|
||||||
'filterableAttributes': ['category', 'distance', 'elevation_gain', 'completed', '_geo', 'public', 'author']
|
'filterableAttributes': ['category', 'difficulty', 'distance', 'elevation_gain', 'completed', '_geo', 'public', 'author']
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,22 +11,11 @@
|
|||||||
import RadioGroup from "../base/radio_group.svelte";
|
import RadioGroup from "../base/radio_group.svelte";
|
||||||
import Search, { type SearchItem } from "../base/search.svelte";
|
import Search, { type SearchItem } from "../base/search.svelte";
|
||||||
import Slider from "../base/slider.svelte";
|
import Slider from "../base/slider.svelte";
|
||||||
|
import type { SelectItem } from "../base/select.svelte";
|
||||||
|
|
||||||
export let categories: Category[];
|
export let categories: Category[];
|
||||||
export let filterExpanded: boolean = true;
|
export let filterExpanded: boolean = true;
|
||||||
export let filter: TrailFilter = {
|
export let filter: TrailFilter;
|
||||||
q: "",
|
|
||||||
category: [],
|
|
||||||
near: {
|
|
||||||
radius: 2000,
|
|
||||||
},
|
|
||||||
distanceMin: 0,
|
|
||||||
distanceMax: 20000,
|
|
||||||
elevationGainMin: 0,
|
|
||||||
elevationGainMax: 4000,
|
|
||||||
sort: "created",
|
|
||||||
sortOrder: "+",
|
|
||||||
};
|
|
||||||
export let showTrailSearch: boolean = true;
|
export let showTrailSearch: boolean = true;
|
||||||
export let showCitySearch: boolean = true;
|
export let showCitySearch: boolean = true;
|
||||||
|
|
||||||
@@ -38,6 +27,12 @@
|
|||||||
{ text: $_("no-preference"), value: "no_preference" },
|
{ text: $_("no-preference"), value: "no_preference" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const difficultyItems: SelectItem[] = [
|
||||||
|
{ text: $_("easy"), value: "easy" },
|
||||||
|
{ text: $_("moderate"), value: "moderate" },
|
||||||
|
{ text: $_("difficult"), value: "difficult" },
|
||||||
|
];
|
||||||
|
|
||||||
let searchDropdownItems: SearchItem[] = [];
|
let searchDropdownItems: SearchItem[] = [];
|
||||||
|
|
||||||
let citySearchQuery: string = "";
|
let citySearchQuery: string = "";
|
||||||
@@ -59,6 +54,19 @@
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setDifficultyFilter(difficulty: "easy" | "moderate" | "difficult") {
|
||||||
|
const difficultyIndex = filter.difficulty.findIndex(
|
||||||
|
(d) => d == difficulty,
|
||||||
|
);
|
||||||
|
if (difficultyIndex !== -1) {
|
||||||
|
filter.difficulty.splice(difficultyIndex, 1);
|
||||||
|
} else {
|
||||||
|
filter.difficulty.push(difficulty);
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
function setCompletedFilter(item: RadioItem) {
|
function setCompletedFilter(item: RadioItem) {
|
||||||
switch (item.value) {
|
switch (item.value) {
|
||||||
case "no_preference":
|
case "no_preference":
|
||||||
@@ -150,6 +158,24 @@
|
|||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
<hr class="my-4 border-separator" />
|
<hr class="my-4 border-separator" />
|
||||||
|
<p class="text-sm font-medium pb-4">{$_("difficulty")}</p>
|
||||||
|
{#each difficultyItems as difficulty, i}
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<input
|
||||||
|
id="{difficulty.value}-checkbox"
|
||||||
|
type="checkbox"
|
||||||
|
checked={filter.difficulty.includes(difficulty.value)}
|
||||||
|
value={difficulty.value}
|
||||||
|
class="w-4 h-4 bg-input-background accent-primary border-input-border focus:ring-input-ring focus:ring-2"
|
||||||
|
on:change={() => setDifficultyFilter(difficulty.value)}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
for="{difficulty.value}-checkbox"
|
||||||
|
class="ms-2 text-sm">{difficulty.text}</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
<hr class="my-4 border-separator" />
|
||||||
{#if showCitySearch}
|
{#if showCitySearch}
|
||||||
<p class="text-sm font-medium pb-4">{$_("near")}</p>
|
<p class="text-sm font-medium pb-4">{$_("near")}</p>
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Trail, TrailFilter } from "$lib/models/trail";
|
import type { Trail, TrailFilter } from "$lib/models/trail";
|
||||||
import { createEventDispatcher, onMount } from "svelte";
|
import { createEventDispatcher, onMount } from "svelte";
|
||||||
|
import { _ } from "svelte-i18n";
|
||||||
|
import Pagination from "../base/pagination.svelte";
|
||||||
import Select, { type SelectItem } from "../base/select.svelte";
|
import Select, { type SelectItem } from "../base/select.svelte";
|
||||||
import EmptyStateSearch from "../empty_states/empty_state_search.svelte";
|
import EmptyStateSearch from "../empty_states/empty_state_search.svelte";
|
||||||
import TrailCard from "./trail_card.svelte";
|
import TrailCard from "./trail_card.svelte";
|
||||||
import TrailListItem from "./trail_list_item.svelte";
|
import TrailListItem from "./trail_list_item.svelte";
|
||||||
import { _ } from "svelte-i18n";
|
|
||||||
import Pagination from "../base/pagination.svelte";
|
|
||||||
import TextField from "../base/text_field.svelte";
|
|
||||||
|
|
||||||
export let filter: TrailFilter;
|
export let filter: TrailFilter;
|
||||||
export let trails: Trail[];
|
export let trails: Trail[];
|
||||||
@@ -28,6 +27,7 @@
|
|||||||
const sortOptions: SelectItem[] = [
|
const sortOptions: SelectItem[] = [
|
||||||
{ text: $_("alphabetical"), value: "name" },
|
{ text: $_("alphabetical"), value: "name" },
|
||||||
{ text: $_("creation-date"), value: "created" },
|
{ text: $_("creation-date"), value: "created" },
|
||||||
|
{ text: $_("difficulty"), value: "difficulty" },
|
||||||
{ text: $_("distance"), value: "distance" },
|
{ text: $_("distance"), value: "distance" },
|
||||||
{ text: $_("elevation-gain"), value: "elevation_gain" },
|
{ text: $_("elevation-gain"), value: "elevation_gain" },
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -28,10 +28,13 @@
|
|||||||
"delete-trail-confirm": "Möchtest du diese Route wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.",
|
"delete-trail-confirm": "Möchtest du diese Route wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||||
"describe-your-trail": "Beschreibe deine Route",
|
"describe-your-trail": "Beschreibe deine Route",
|
||||||
"description": "Beschreibung",
|
"description": "Beschreibung",
|
||||||
|
"difficult": "Schwierig",
|
||||||
|
"difficulty": "Schwierigkeit",
|
||||||
"directions": "Wegbeschreibung",
|
"directions": "Wegbeschreibung",
|
||||||
"display-as": "Anzeigen als",
|
"display-as": "Anzeigen als",
|
||||||
"distance": "Distanz",
|
"distance": "Distanz",
|
||||||
"download-gpx": "GPX herunterladen",
|
"download-gpx": "GPX herunterladen",
|
||||||
|
"easy": "Einfach",
|
||||||
"edit": "Bearbeiten",
|
"edit": "Bearbeiten",
|
||||||
"edit-entry": "Eintrag bearbeiten",
|
"edit-entry": "Eintrag bearbeiten",
|
||||||
"edit-list": "Liste bearbeiten",
|
"edit-list": "Liste bearbeiten",
|
||||||
@@ -61,6 +64,7 @@
|
|||||||
"make-thumbnail": "Thumbnail festlegen",
|
"make-thumbnail": "Thumbnail festlegen",
|
||||||
"map": "Karte",
|
"map": "Karte",
|
||||||
"metric": "Metrisch",
|
"metric": "Metrisch",
|
||||||
|
"moderate": "Mittel",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"near": "Nahe",
|
"near": "Nahe",
|
||||||
"new-list": "Neue Liste",
|
"new-list": "Neue Liste",
|
||||||
|
|||||||
@@ -28,10 +28,13 @@
|
|||||||
"delete-trail-confirm": "Do you really want to delete this trail? This action cannot be undone.",
|
"delete-trail-confirm": "Do you really want to delete this trail? This action cannot be undone.",
|
||||||
"describe-your-trail": "Describe your trail",
|
"describe-your-trail": "Describe your trail",
|
||||||
"description": "Description",
|
"description": "Description",
|
||||||
|
"difficult": "Difficult",
|
||||||
|
"difficulty": "Difficulty",
|
||||||
"directions": "Directions",
|
"directions": "Directions",
|
||||||
"display-as": "Display as",
|
"display-as": "Display as",
|
||||||
"distance": "Distance",
|
"distance": "Distance",
|
||||||
"download-gpx": "Download GPX",
|
"download-gpx": "Download GPX",
|
||||||
|
"easy": "Easy",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"edit-entry": "Edit Entry",
|
"edit-entry": "Edit Entry",
|
||||||
"edit-list": "Edit List",
|
"edit-list": "Edit List",
|
||||||
@@ -61,6 +64,7 @@
|
|||||||
"make-thumbnail": "Make thumbnail",
|
"make-thumbnail": "Make thumbnail",
|
||||||
"map": "Map",
|
"map": "Map",
|
||||||
"metric": "Metric",
|
"metric": "Metric",
|
||||||
|
"moderate": "Moderate",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"near": "Near",
|
"near": "Near",
|
||||||
"new-list": "New List",
|
"new-list": "New List",
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { env } from '$env/dynamic/public'
|
import { env } from '$env/dynamic/private'
|
||||||
|
|
||||||
import { MeiliSearch } from 'meilisearch'
|
import { MeiliSearch } from 'meilisearch'
|
||||||
import { pb } from './pocketbase'
|
import { pb } from './pocketbase'
|
||||||
|
|
||||||
export function createInstance() {
|
export function createInstance() {
|
||||||
if (pb.authStore.model) {
|
if (pb.authStore.model) {
|
||||||
return new MeiliSearch({ host: env.PUBLIC_MEILISEARCH_URL, apiKey: pb.authStore.model.token })
|
return new MeiliSearch({ host: env.MEILI_URL, apiKey: pb.authStore.model.token })
|
||||||
}
|
}
|
||||||
return new MeiliSearch({ host: env.PUBLIC_MEILISEARCH_URL, apiKey: env.PUBLIC_MEILISEARCH_API_TOKEN })
|
return new MeiliSearch({ host: env.MEILI_URL, apiKey: env.MEILI_API_TOKEN })
|
||||||
}
|
}
|
||||||
|
|
||||||
export function regenerateInstance() {
|
export function regenerateInstance() {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class Trail {
|
|||||||
distance?: number;
|
distance?: number;
|
||||||
elevation_gain?: number;
|
elevation_gain?: number;
|
||||||
duration?: number;
|
duration?: number;
|
||||||
|
difficulty?: "easy"|"moderate"|"difficult"
|
||||||
lat?: number;
|
lat?: number;
|
||||||
lon?: number;
|
lon?: number;
|
||||||
thumbnail: number;
|
thumbnail: number;
|
||||||
@@ -38,6 +39,7 @@ class Trail {
|
|||||||
distance?: number,
|
distance?: number,
|
||||||
elevation_gain?: number,
|
elevation_gain?: number,
|
||||||
duration?: number,
|
duration?: number,
|
||||||
|
difficulty?: "easy"|"moderate"|"difficult",
|
||||||
lat?:number,
|
lat?:number,
|
||||||
lon?: number,
|
lon?: number,
|
||||||
thumbnail?: number,
|
thumbnail?: number,
|
||||||
@@ -59,6 +61,7 @@ class Trail {
|
|||||||
this.distance = params?.distance;
|
this.distance = params?.distance;
|
||||||
this.elevation_gain = params?.elevation_gain;
|
this.elevation_gain = params?.elevation_gain;
|
||||||
this.duration = params?.duration;
|
this.duration = params?.duration;
|
||||||
|
this.difficulty = params?.difficulty ?? "easy";
|
||||||
this.lat = params?.lat;
|
this.lat = params?.lat;
|
||||||
this.lon = params?.lon;
|
this.lon = params?.lon;
|
||||||
this.thumbnail = params?.thumbnail ?? 0;
|
this.thumbnail = params?.thumbnail ?? 0;
|
||||||
@@ -93,6 +96,7 @@ const trailSchema = object<Trail>({
|
|||||||
interface TrailFilter {
|
interface TrailFilter {
|
||||||
q: string,
|
q: string,
|
||||||
category: string[],
|
category: string[],
|
||||||
|
difficulty: ("easy" | "moderate" | "difficult")[]
|
||||||
near: {
|
near: {
|
||||||
lat?: number,
|
lat?: number,
|
||||||
lon?: number,
|
lon?: number,
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ export async function trails_index(data: { perPage: number, random?: boolean, f:
|
|||||||
export async function trails_search_filter(filter: TrailFilter, page: number = 1, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {
|
export async function trails_search_filter(filter: TrailFilter, page: number = 1, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {
|
||||||
let filterText: string = `distance >= ${filter.distanceMin} AND distance <= ${filter.distanceMax} AND elevation_gain >= ${filter.elevationGainMin} AND elevation_gain <= ${filter.elevationGainMax}`;
|
let filterText: string = `distance >= ${filter.distanceMin} AND distance <= ${filter.distanceMax} AND elevation_gain >= ${filter.elevationGainMin} AND elevation_gain <= ${filter.elevationGainMax}`;
|
||||||
|
|
||||||
|
filterText += ` AND difficulty IN [${filter.difficulty.join(",")}]`
|
||||||
|
|
||||||
if (filter.category.length > 0) {
|
if (filter.category.length > 0) {
|
||||||
filterText += ` AND category IN [${filter.category.join(",")}]`;
|
filterText += ` AND category IN [${filter.category.join(",")}]`;
|
||||||
}
|
}
|
||||||
@@ -45,12 +47,20 @@ export async function trails_search_filter(filter: TrailFilter, page: number = 1
|
|||||||
if (filter.near.lat && filter.near.lon) {
|
if (filter.near.lat && filter.near.lon) {
|
||||||
filterText += ` AND _geoRadius(${filter.near.lat}, ${filter.near.lon}, ${filter.near.radius})`
|
filterText += ` AND _geoRadius(${filter.near.lat}, ${filter.near.lon}, ${filter.near.radius})`
|
||||||
}
|
}
|
||||||
|
if (filter.near.lat && filter.near.lon) {
|
||||||
|
filterText += ` AND _geoRadius(${filter.near.lat}, ${filter.near.lon}, ${filter.near.radius})`
|
||||||
|
}
|
||||||
let r = await f("/api/v1/search/trails", {
|
let r = await f("/api/v1/search/trails", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({ q: filter.q, options: { filter: filterText, hitsPerPage: 20, page: page } }),
|
body: JSON.stringify({ q: filter.q, options: { filter: filterText, hitsPerPage: 20, page: page } }),
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await r.json();
|
const result = await r.json();
|
||||||
|
|
||||||
|
if (!r.ok) {
|
||||||
|
throw new ClientResponseError(result)
|
||||||
|
}
|
||||||
|
|
||||||
const trailIds = result.hits.map((h: Record<string, any>) => h.id);
|
const trailIds = result.hits.map((h: Record<string, any>) => h.id);
|
||||||
|
|
||||||
if (trailIds.length == 0) {
|
if (trailIds.length == 0) {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { regenerateInstance } from "$lib/meilisearch";
|
|
||||||
import { pb } from "$lib/pocketbase";
|
import { pb } from "$lib/pocketbase";
|
||||||
import { ClientResponseError } from "pocketbase";
|
import { ClientResponseError } from "pocketbase";
|
||||||
import { writable, type Writable } from "svelte/store";
|
import { writable, type Writable } from "svelte/store";
|
||||||
@@ -38,7 +37,6 @@ export async function login(user: User) {
|
|||||||
|
|
||||||
if (r.ok) {
|
if (r.ok) {
|
||||||
pb.authStore.loadFromCookie(document.cookie)
|
pb.authStore.loadFromCookie(document.cookie)
|
||||||
regenerateInstance()
|
|
||||||
} else {
|
} else {
|
||||||
throw new ClientResponseError(await r.json())
|
throw new ClientResponseError(await r.json())
|
||||||
}
|
}
|
||||||
@@ -47,7 +45,6 @@ export async function login(user: User) {
|
|||||||
|
|
||||||
export async function logout() {
|
export async function logout() {
|
||||||
pb.authStore.clear();
|
pb.authStore.clear();
|
||||||
regenerateInstance()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function users_update(id: string, user: User | { [K in keyof User]?: User[K] } | FormData) {
|
export async function users_update(id: string, user: User | { [K in keyof User]?: User[K] } | FormData) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export const load: Load = async ({ params, fetch }) => {
|
|||||||
const filter: TrailFilter = {
|
const filter: TrailFilter = {
|
||||||
q: "",
|
q: "",
|
||||||
category: [],
|
category: [],
|
||||||
|
difficulty: ["easy", "moderate", "difficult"],
|
||||||
near: {
|
near: {
|
||||||
radius: 2000,
|
radius: 2000,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -452,6 +452,16 @@
|
|||||||
label={$_("describe-your-trail")}
|
label={$_("describe-your-trail")}
|
||||||
bind:value={$form.description}
|
bind:value={$form.description}
|
||||||
></Textarea>
|
></Textarea>
|
||||||
|
<Select
|
||||||
|
name="difficulty"
|
||||||
|
label={$_("difficulty")}
|
||||||
|
bind:value={$form.difficulty}
|
||||||
|
items={[
|
||||||
|
{ text: $_('easy'), value: "easy" },
|
||||||
|
{ text: $_('moderate'), value: "moderate" },
|
||||||
|
{ text: $_('difficult'), value: "difficult" },
|
||||||
|
]}
|
||||||
|
></Select>
|
||||||
{#if $form.expand.category}
|
{#if $form.expand.category}
|
||||||
<Select
|
<Select
|
||||||
name="category"
|
name="category"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export const load: ServerLoad = async ({ params, locals, url, fetch }) => {
|
|||||||
const filter: TrailFilter = {
|
const filter: TrailFilter = {
|
||||||
q: "",
|
q: "",
|
||||||
category: [],
|
category: [],
|
||||||
|
difficulty: ["easy", "moderate", "difficult"],
|
||||||
near: {
|
near: {
|
||||||
radius: 2000,
|
radius: 2000,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user