adds i18n
This commit is contained in:
@@ -22,7 +22,11 @@
|
||||
trails_update,
|
||||
} from "$lib/stores/trail_store";
|
||||
import { waypoint } from "$lib/stores/waypoint_store";
|
||||
import { formatMeters, formatTimeHHMM } from "$lib/util/format_util";
|
||||
import {
|
||||
formatDistance,
|
||||
formatElevation,
|
||||
formatTimeHHMM,
|
||||
} from "$lib/util/format_util";
|
||||
import { createMarkerFromWaypoint } from "$lib/util/leaflet_util";
|
||||
import "$lib/vendor/leaflet-elevation/src/index.css";
|
||||
import { createForm } from "$lib/vendor/svelte-form-lib";
|
||||
@@ -32,6 +36,7 @@
|
||||
import "leaflet.awesome-markers/dist/leaflet.awesome-markers.css";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import { onMount } from "svelte";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
export let data: { trail: Trail };
|
||||
|
||||
@@ -350,15 +355,21 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title
|
||||
>{$form.id ? `${$form.name} | ${$_("edit")}` : $_("new-trail")} | wanderer</title
|
||||
>
|
||||
</svelte:head>
|
||||
|
||||
<main class="grid grid-cols-1 md:grid-cols-[400px_1fr]">
|
||||
<form
|
||||
id="trail-form"
|
||||
class="overflow-y-auto overflow-x-hidden flex flex-col gap-4 px-8 order-1 md:order-none mt-8 md:mt-0"
|
||||
on:submit={handleSubmit}
|
||||
>
|
||||
<h3 class="text-xl font-semibold">Pick a trail</h3>
|
||||
<h3 class="text-xl font-semibold">{$_("pick-a-trail")}</h3>
|
||||
<button class="btn-primary" type="button" on:click={openFileBrowser}
|
||||
>Upload GPX</button
|
||||
>{$_("upload-gpx")}</button
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
@@ -369,17 +380,18 @@
|
||||
on:change={handleFileSelection}
|
||||
/>
|
||||
<hr class="border-separator" />
|
||||
<h3 class="text-xl font-semibold">Basic Info</h3>
|
||||
<h3 class="text-xl font-semibold">{$_("basic-info")}</h3>
|
||||
<div class="flex gap-4 justify-around">
|
||||
<div class="flex flex-col items-center">
|
||||
<span>Distance</span>
|
||||
<span class="font-medium">{formatMeters($form.distance)}</span>
|
||||
<span>{$_('distance')}</span>
|
||||
<span class="font-medium">{formatDistance($form.distance)}</span
|
||||
>
|
||||
<input type="hidden" name="distance" value={$form.distance} />
|
||||
</div>
|
||||
<div class="flex flex-col items-center">
|
||||
<span>Elevation gain</span>
|
||||
<span>{$_("elevation-gain")}</span>
|
||||
<span class="font-medium"
|
||||
>{formatMeters($form.elevation_gain)}</span
|
||||
>{formatElevation($form.elevation_gain)}</span
|
||||
>
|
||||
<input
|
||||
type="hidden"
|
||||
@@ -388,7 +400,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col items-center">
|
||||
<span>Est. duration</span>
|
||||
<span>{$_("est-duration")}</span>
|
||||
<span class="font-medium">{formatTimeHHMM($form.duration)}</span
|
||||
>
|
||||
<input type="hidden" name="duration" value={$form.duration} />
|
||||
@@ -398,33 +410,34 @@
|
||||
</div>
|
||||
<TextField
|
||||
name="name"
|
||||
label="Name"
|
||||
label={$_("name")}
|
||||
on:change={handleChange}
|
||||
error={$errors.name}
|
||||
bind:value={$form.name}
|
||||
></TextField>
|
||||
<TextField
|
||||
name="location"
|
||||
label="Location"
|
||||
label={$_("location")}
|
||||
error={$errors.location}
|
||||
bind:value={$form.location}
|
||||
></TextField>
|
||||
<Textarea
|
||||
name="description"
|
||||
label="Describe your trail"
|
||||
label={$_("describe-your-trail")}
|
||||
bind:value={$form.description}
|
||||
></Textarea>
|
||||
{#if $form.expand.category}
|
||||
<Select
|
||||
name="category"
|
||||
label="Category"
|
||||
label={$_("category")}
|
||||
bind:value={$form.expand.category.id}
|
||||
items={$categories.map((c) => ({ text: c.name, value: c.id }))}
|
||||
></Select>
|
||||
{/if}
|
||||
<Toggle name="public" label="Public" bind:value={$form.public}></Toggle>
|
||||
<Toggle name="public" label={$_("public")} bind:value={$form.public}
|
||||
></Toggle>
|
||||
<hr class="border-separator" />
|
||||
<h3 class="text-xl font-semibold">Waypoints</h3>
|
||||
<h3 class="text-xl font-semibold">{$_("waypoints")}</h3>
|
||||
<ul>
|
||||
{#each $form.expand.waypoints ?? [] as waypoint, i}
|
||||
<li on:mouseenter={() => openMarkerPopup(waypoint)}>
|
||||
@@ -441,10 +454,10 @@
|
||||
class="btn-secondary"
|
||||
type="button"
|
||||
on:click={beforeWaypointModalOpen}
|
||||
><i class="fa fa-plus mr-2"></i>Add Waypoint</button
|
||||
><i class="fa fa-plus mr-2"></i>{$_("add-waypoint")}</button
|
||||
>
|
||||
<hr class="border-separator" />
|
||||
<h3 class="text-xl font-semibold">Photos</h3>
|
||||
<h3 class="text-xl font-semibold">{$_("photos")}</h3>
|
||||
<div class="flex gap-4 max-w-full overflow-x-auto shrink-0">
|
||||
<button
|
||||
class="btn-secondary h-32 w-32 m-2 shrink-0 grow-0 basis-auto"
|
||||
@@ -471,7 +484,7 @@
|
||||
{/each}
|
||||
</div>
|
||||
<hr class="border-separator" />
|
||||
<h3 class="text-xl font-semibold">Summit Book</h3>
|
||||
<h3 class="text-xl font-semibold">{$_('summit-book')}</h3>
|
||||
<ul>
|
||||
{#each $form.expand.summit_logs ?? [] as log, i}
|
||||
<li>
|
||||
@@ -487,7 +500,7 @@
|
||||
class="btn-secondary"
|
||||
type="button"
|
||||
on:click={beforeSummitLogModalOpen}
|
||||
><i class="fa fa-plus mr-2"></i>Add Entry</button
|
||||
><i class="fa fa-plus mr-2"></i>{$_("add-entry")}</button
|
||||
>
|
||||
<hr class="border-separator" />
|
||||
<Button
|
||||
@@ -495,7 +508,7 @@
|
||||
large={true}
|
||||
type="submit"
|
||||
extraClasses="mb-2"
|
||||
{loading}>Save Trail</Button
|
||||
{loading}>{$_("save-trail")}</Button
|
||||
>
|
||||
</form>
|
||||
<div class="rounded-xl" id="map"></div>
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import type { DropdownItem } from "$lib/components/base/dropdown.svelte";
|
||||
import Dropdown from "$lib/components/base/dropdown.svelte";
|
||||
import ConfirmModal from "$lib/components/confirm_modal.svelte";
|
||||
import ListSelectModal from "$lib/components/list/list_select_modal.svelte";
|
||||
import SummitLogCard from "$lib/components/summit_log/summit_log_card.svelte";
|
||||
import Tabs from "$lib/components/tabs.svelte";
|
||||
import TrailDropdown from "$lib/components/trail/trail_dropdown.svelte";
|
||||
import WaypointCard from "$lib/components/waypoint/waypoint_card.svelte";
|
||||
import type { List } from "$lib/models/list";
|
||||
import {
|
||||
lists_add_trail,
|
||||
lists_index,
|
||||
lists_remove_trail,
|
||||
} from "$lib/stores/list_store";
|
||||
import { show_toast } from "$lib/stores/toast_store";
|
||||
import { trail, trails_delete } from "$lib/stores/trail_store";
|
||||
import { trail } from "$lib/stores/trail_store";
|
||||
import { currentUser } from "$lib/stores/user_store";
|
||||
import { getFileURL } from "$lib/util/file_util";
|
||||
import { formatMeters, formatTimeHHMM } from "$lib/util/format_util";
|
||||
import {
|
||||
formatDistance,
|
||||
formatElevation,
|
||||
formatTimeHHMM,
|
||||
} from "$lib/util/format_util";
|
||||
import { createMarkerFromWaypoint } from "$lib/util/leaflet_util";
|
||||
import "$lib/vendor/leaflet-elevation/src/index.css";
|
||||
import type { Icon, Map, Marker } from "leaflet";
|
||||
@@ -26,9 +20,15 @@
|
||||
import type { DataSource } from "photoswipe";
|
||||
import PhotoSwipeLightbox from "photoswipe/lightbox";
|
||||
import "photoswipe/style.css";
|
||||
import { onMount, tick } from "svelte";
|
||||
import { onMount } from "svelte";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
const tabs = ["Description", "Waypoints", "Photos", "Summit book"];
|
||||
const tabs = [
|
||||
$_("description"),
|
||||
$_("waypoints"),
|
||||
$_("photos"),
|
||||
$_("summit-book"),
|
||||
];
|
||||
|
||||
let map: Map;
|
||||
|
||||
@@ -39,20 +39,6 @@
|
||||
let lightbox: PhotoSwipeLightbox;
|
||||
let lightboxDataSource: DataSource;
|
||||
|
||||
let openConfirmModal: () => void;
|
||||
let openListSelectModal: () => void;
|
||||
|
||||
const dropdownItems: DropdownItem[] = [
|
||||
{ text: "Show on map", value: "map", icon: "map" },
|
||||
{ text: "Directions", value: "direction", icon: "car" },
|
||||
...($trail.gpx
|
||||
? [{ text: "Download GPX", value: "download", icon: "download" }]
|
||||
: []),
|
||||
{ text: "Add to list", value: "list", icon: "bookmark" },
|
||||
{ text: "Edit", value: "edit", icon: "pen" },
|
||||
{ text: "Delete", value: "delete", icon: "trash" },
|
||||
];
|
||||
|
||||
onMount(async () => {
|
||||
const L = (await import("leaflet")).default;
|
||||
await import("leaflet-gpx");
|
||||
@@ -132,74 +118,16 @@
|
||||
lightbox?.loadAndOpen(idx, lightboxDataSource);
|
||||
}
|
||||
|
||||
async function handleDropdownClick(item: { text: string; value: any }) {
|
||||
if (item.value == "map") {
|
||||
goto(`/map/trail/${$trail.id!}`);
|
||||
} else if (item.value == "list") {
|
||||
openListSelectModal();
|
||||
} else if (item.value == "direction") {
|
||||
window
|
||||
.open(
|
||||
`https://www.google.com/maps/dir/Current+Location/${$trail.lat},${$trail.lon}`,
|
||||
"_blank",
|
||||
)
|
||||
?.focus();
|
||||
} else if (item.value == "download") {
|
||||
downloadURI(getFileURL($trail, $trail.gpx), $trail.gpx!);
|
||||
} else if (item.value == "edit") {
|
||||
goto(`/trail/edit/${$trail.id}`);
|
||||
} else if (item.value == "delete") {
|
||||
openConfirmModal();
|
||||
}
|
||||
}
|
||||
|
||||
function downloadURI(uri: string, name: string) {
|
||||
var link = document.createElement("a");
|
||||
link.setAttribute("download", name);
|
||||
link.href = uri;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
}
|
||||
|
||||
async function deleteTrail() {
|
||||
trails_delete($trail).then(() => history.back());
|
||||
}
|
||||
|
||||
async function toggleMapFullScreen() {
|
||||
goto(`/map/trail/${$trail.id!}`);
|
||||
}
|
||||
|
||||
async function handleListSelection(list: List) {
|
||||
try {
|
||||
if (list.trails?.includes($trail.id!)) {
|
||||
await lists_remove_trail(list, $trail);
|
||||
show_toast({
|
||||
type: "success",
|
||||
icon: "check",
|
||||
text: `Removed trail from "${list.name}"`,
|
||||
});
|
||||
} else {
|
||||
await lists_add_trail(list, $trail);
|
||||
show_toast({
|
||||
type: "success",
|
||||
icon: "check",
|
||||
text: `Added trail to "${list.name}"`,
|
||||
});
|
||||
}
|
||||
await lists_index();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
show_toast({
|
||||
type: "error",
|
||||
icon: "close",
|
||||
text: "Error adding trail to list.",
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{$trail.name} | {$_("trail", { values: { n: 1 } })} | wanderer</title
|
||||
>
|
||||
</svelte:head>
|
||||
|
||||
<div
|
||||
class="trail-panel max-w-5xl mx-auto border border-input-border rounded-3xl overflow-hidden"
|
||||
>
|
||||
@@ -225,17 +153,7 @@
|
||||
</h3>
|
||||
</div>
|
||||
{#if $currentUser && $currentUser.id == $trail.author}
|
||||
<Dropdown
|
||||
items={dropdownItems}
|
||||
on:change={(e) => handleDropdownClick(e.detail)}
|
||||
let:toggleMenu={openDropdown}
|
||||
><button
|
||||
class="rounded-full bg-white text-black hover:bg-gray-200 focus:ring-4 ring-gray-100/50 transition-colors h-12 w-12"
|
||||
on:click={openDropdown}
|
||||
>
|
||||
<i class="fa fa-ellipsis-vertical"></i>
|
||||
</button></Dropdown
|
||||
>
|
||||
<TrailDropdown trail={$trail} mode="overview"></TrailDropdown>
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
@@ -243,26 +161,26 @@
|
||||
class="grid grid-cols-2 sm:grid-cols-4 gap-y-4 justify-around py-8 border-b border-input-border"
|
||||
>
|
||||
<div class="flex flex-col items-center">
|
||||
<span>Distance</span>
|
||||
<span>{$_("distance")}</span>
|
||||
<span class="font-semibold text-lg"
|
||||
>{formatMeters($trail.distance)}</span
|
||||
>{formatDistance($trail.distance)}</span
|
||||
>
|
||||
</div>
|
||||
<div class="flex flex-col items-center">
|
||||
<span>Elevation gain</span>
|
||||
<span>{$_("elevation-gain")}</span>
|
||||
<span class="font-semibold text-lg"
|
||||
>{formatMeters($trail.elevation_gain)}</span
|
||||
>{formatElevation($trail.elevation_gain)}</span
|
||||
>
|
||||
</div>
|
||||
<div class="flex flex-col items-center">
|
||||
<span>Est. duration</span>
|
||||
<span>{$_("est-duration")}</span>
|
||||
<span class="font-semibold text-lg"
|
||||
>{formatTimeHHMM($trail.duration)}</span
|
||||
>
|
||||
</div>
|
||||
{#if $trail.expand.category}
|
||||
<div class="flex flex-col items-center">
|
||||
<span>Category</span>
|
||||
<span>{$_("category")}</span>
|
||||
<span class="font-semibold text-lg"
|
||||
>{$trail.expand.category.name}</span
|
||||
>
|
||||
@@ -334,15 +252,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<ConfirmModal
|
||||
text="Do you really want to delete this trail? This action cannot be undone."
|
||||
bind:openModal={openConfirmModal}
|
||||
on:confirm={deleteTrail}
|
||||
></ConfirmModal>
|
||||
<ListSelectModal
|
||||
bind:openModal={openListSelectModal}
|
||||
on:change={(e) => handleListSelection(e.detail)}
|
||||
></ListSelectModal>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user