Adds import from URL
This commit is contained in:
@@ -1,9 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Snippet } from "svelte";
|
import type { Snippet } from "svelte";
|
||||||
import type { MouseEventHandler } from "svelte/elements";
|
import type { MouseEventHandler } from "svelte/elements";
|
||||||
import { createBubbler } from "svelte/legacy";
|
|
||||||
|
|
||||||
const bubble = createBubbler();
|
|
||||||
interface Props {
|
interface Props {
|
||||||
type?: "button" | "submit" | "reset" | null | undefined;
|
type?: "button" | "submit" | "reset" | null | undefined;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
@@ -14,6 +12,7 @@
|
|||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
tooltip?: string | undefined;
|
tooltip?: string | undefined;
|
||||||
|
form?: string;
|
||||||
id?: string | undefined;
|
id?: string | undefined;
|
||||||
children?: Snippet;
|
children?: Snippet;
|
||||||
onclick?: MouseEventHandler<HTMLButtonElement>;
|
onclick?: MouseEventHandler<HTMLButtonElement>;
|
||||||
@@ -30,6 +29,7 @@
|
|||||||
disabled = false,
|
disabled = false,
|
||||||
tooltip = undefined,
|
tooltip = undefined,
|
||||||
id = undefined,
|
id = undefined,
|
||||||
|
form,
|
||||||
children,
|
children,
|
||||||
onclick = undefined,
|
onclick = undefined,
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
@@ -44,6 +44,7 @@
|
|||||||
disabled={disabled || loading}
|
disabled={disabled || loading}
|
||||||
class:tooltip={(tooltip?.length ?? 0) > 0}
|
class:tooltip={(tooltip?.length ?? 0) > 0}
|
||||||
data-title={tooltip}
|
data-title={tooltip}
|
||||||
|
{form}
|
||||||
{onclick}
|
{onclick}
|
||||||
{type}
|
{type}
|
||||||
{id}
|
{id}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
import { browser } from "$app/environment";
|
import { browser } from "$app/environment";
|
||||||
import { page } from "$app/state";
|
import { page } from "$app/state";
|
||||||
import { Tween } from "svelte/motion";
|
import { Tween } from "svelte/motion";
|
||||||
|
import UrlImportModal from "./settings/url_import_modal.svelte";
|
||||||
|
|
||||||
let navBarItems = [
|
let navBarItems = [
|
||||||
{ text: "Home", value: "/" },
|
{ text: "Home", value: "/" },
|
||||||
@@ -28,6 +29,11 @@
|
|||||||
{ text: $_("logout"), value: "logout", icon: "right-from-bracket" },
|
{ text: $_("logout"), value: "logout", icon: "right-from-bracket" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const importDropdownItems = [
|
||||||
|
{ text: $_("from-file"), value: "file", icon: "file-import" },
|
||||||
|
{ text: $_("from-url"), value: "url", icon: "server" },
|
||||||
|
];
|
||||||
|
|
||||||
const indicatorPosition = new Tween(0, {
|
const indicatorPosition = new Tween(0, {
|
||||||
duration: 300,
|
duration: 300,
|
||||||
easing: cubicOut,
|
easing: cubicOut,
|
||||||
@@ -45,6 +51,8 @@
|
|||||||
|
|
||||||
let drawerOpen: boolean = $state(false);
|
let drawerOpen: boolean = $state(false);
|
||||||
|
|
||||||
|
let urlImportModal: UrlImportModal;
|
||||||
|
|
||||||
afterNavigate((e) => {
|
afterNavigate((e) => {
|
||||||
const routeId = e.to?.route.id;
|
const routeId = e.to?.route.id;
|
||||||
const navBarLinks = document.getElementById("nav-bar-links");
|
const navBarLinks = document.getElementById("nav-bar-links");
|
||||||
@@ -92,6 +100,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleImportDropdownClick(item: { text: string; value: any }) {
|
||||||
|
if (item.value == "file") {
|
||||||
|
goto(`/settings/export`);
|
||||||
|
} else if (item.value == "url") {
|
||||||
|
urlImportModal.openModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let user = $derived(browser ? $currentUser : pb.authStore.model);
|
let user = $derived(browser ? $currentUser : pb.authStore.model);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -132,8 +148,12 @@
|
|||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
<a href="/profile/{user.id}" style="width: calc(100% - 104px)">
|
<a href="/profile/{user.id}" style="width: calc(100% - 104px)">
|
||||||
<p class="text-sm overflow-hidden text-ellipsis">{user.username}</p>
|
<p class="text-sm overflow-hidden text-ellipsis">
|
||||||
<p class="text-sm text-gray-500 overflow-hidden text-ellipsis">
|
{user.username}
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="text-sm text-gray-500 overflow-hidden text-ellipsis"
|
||||||
|
>
|
||||||
{user.email}
|
{user.email}
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
@@ -182,9 +202,26 @@
|
|||||||
: 'moon'}"
|
: 'moon'}"
|
||||||
onclick={() => toggleTheme()}
|
onclick={() => toggleTheme()}
|
||||||
></button>
|
></button>
|
||||||
<a class="btn-primary btn-large" href="/trail/edit/new"
|
<div class="flex">
|
||||||
><i class="fa fa-plus mr-2"></i>{$_("new-trail")}</a
|
<a
|
||||||
>
|
class="btn-primary btn-large !rounded-r-none focus:ring-0"
|
||||||
|
href="/trail/edit/new"
|
||||||
|
><i class="fa fa-plus mr-2"></i>{$_("new-trail")}</a
|
||||||
|
>
|
||||||
|
<Dropdown
|
||||||
|
items={importDropdownItems}
|
||||||
|
onchange={(item) => handleImportDropdownClick(item)}
|
||||||
|
>
|
||||||
|
{#snippet children({ toggleMenu: openDropdown })}
|
||||||
|
<button
|
||||||
|
onclick={openDropdown}
|
||||||
|
class="bg-primary rounded-r-lg text-white min-h-12 hover:bg-primary-hover px-3"
|
||||||
|
aria-label="Open trail create dropdown"
|
||||||
|
><i class="fa fa-caret-down"></i></button
|
||||||
|
>
|
||||||
|
{/snippet}
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
{#if page.data.notifications}
|
{#if page.data.notifications}
|
||||||
<NotificationDropdown></NotificationDropdown>
|
<NotificationDropdown></NotificationDropdown>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -227,3 +264,5 @@
|
|||||||
onclick={() => (drawerOpen = !drawerOpen)}
|
onclick={() => (drawerOpen = !drawerOpen)}
|
||||||
></button>
|
></button>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<UrlImportModal bind:this={urlImportModal}></UrlImportModal>
|
||||||
|
|||||||
@@ -96,7 +96,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-x-2">
|
<div class="space-x-2">
|
||||||
<button aria-label="Dismiss all" onclick={dismissAllCompleted}
|
<button title={$_('clear-all')} aria-label="Dismiss all" onclick={dismissAllCompleted}
|
||||||
><i class="fa fa-ban"></i></button
|
><i class="fa fa-ban"></i></button
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
@@ -134,7 +134,7 @@
|
|||||||
></i>
|
></i>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xs basis-full min-w-0 break-all">
|
<p class="text-xs basis-full min-w-0 break-all mr-2">
|
||||||
{u.file.name}
|
{u.file.name}
|
||||||
</p>
|
</p>
|
||||||
{#if u.status == "error" || u.status == "cancelled"}
|
{#if u.status == "error" || u.status == "cancelled"}
|
||||||
|
|||||||
97
web/src/lib/components/settings/url_import_modal.svelte
Normal file
97
web/src/lib/components/settings/url_import_modal.svelte
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Modal from "$lib/components/base/modal.svelte";
|
||||||
|
import { trails_upload } from "$lib/stores/trail_store";
|
||||||
|
import {
|
||||||
|
processUploadQueue,
|
||||||
|
uploadStore,
|
||||||
|
type Upload,
|
||||||
|
} from "$lib/stores/upload_store.svelte";
|
||||||
|
import { validator } from "@felte/validator-zod";
|
||||||
|
import { createForm } from "felte";
|
||||||
|
import { _ } from "svelte-i18n";
|
||||||
|
import { z } from "zod";
|
||||||
|
import TextField from "../base/text_field.svelte";
|
||||||
|
import Button from "../base/button.svelte";
|
||||||
|
|
||||||
|
let modal: Modal;
|
||||||
|
|
||||||
|
let loading: boolean = false;
|
||||||
|
|
||||||
|
export function openModal() {
|
||||||
|
setFields("url", "")
|
||||||
|
setErrors("url", []);
|
||||||
|
loading = false;
|
||||||
|
modal.openModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { form, errors, setFields, setErrors } = createForm<{
|
||||||
|
url: string;
|
||||||
|
}>({
|
||||||
|
initialValues: { url: "" },
|
||||||
|
extend: validator({
|
||||||
|
schema: z.object({
|
||||||
|
url: z.string().min(1, "required").url("not-a-valid-url"),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
onSubmit: async (form) => {
|
||||||
|
try {
|
||||||
|
loading = true;
|
||||||
|
const r = await fetch("/api/v1/trail/download", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ url: form.url }),
|
||||||
|
});
|
||||||
|
if (!r.ok) {
|
||||||
|
throw new Error(`Failed to fetch file: ${r.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = await r.blob();
|
||||||
|
|
||||||
|
const fileName =
|
||||||
|
form.url.split("/").pop() ||
|
||||||
|
"url-import-file-" + new Date().getTime();
|
||||||
|
|
||||||
|
const file = new File([blob], fileName, { type: blob.type });
|
||||||
|
|
||||||
|
const u: Upload = {
|
||||||
|
file: file,
|
||||||
|
progress: 0,
|
||||||
|
status: "enqueued",
|
||||||
|
function: trails_upload,
|
||||||
|
};
|
||||||
|
uploadStore.enqueuedUploads.push(u);
|
||||||
|
|
||||||
|
await processUploadQueue();
|
||||||
|
loading = false;
|
||||||
|
modal.closeModal();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error:", error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
id="url-import-modal"
|
||||||
|
size="max-w-xl"
|
||||||
|
title={$_("from-url")}
|
||||||
|
bind:this={modal}
|
||||||
|
>
|
||||||
|
{#snippet content()}
|
||||||
|
<form id="url-import-form" use:form>
|
||||||
|
<TextField
|
||||||
|
name="url"
|
||||||
|
label="URL"
|
||||||
|
placeholder="https://..."
|
||||||
|
error={$errors.url}
|
||||||
|
></TextField>
|
||||||
|
</form>
|
||||||
|
{/snippet}
|
||||||
|
{#snippet footer()}
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<button class="btn-secondary" onclick={() => modal.closeModal()}
|
||||||
|
>{$_("cancel")}</button
|
||||||
|
>
|
||||||
|
<Button primary type="submit" form="url-import-form" {loading}>{$_("import")}</Button>
|
||||||
|
</div>
|
||||||
|
{/snippet}</Modal
|
||||||
|
>
|
||||||
@@ -157,7 +157,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="trail-info-panel mx-auto {mode == 'list'
|
class="trail-info-panel overflow-x-hidden mx-auto {mode == 'list'
|
||||||
? ''
|
? ''
|
||||||
: 'border border-input-border rounded-3xl'} h-full"
|
: 'border border-input-border rounded-3xl'} h-full"
|
||||||
class:overflow-y-scroll={mode !== "overview"}
|
class:overflow-y-scroll={mode !== "overview"}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
"change-password": "Passwort ändern",
|
"change-password": "Passwort ändern",
|
||||||
"changelog": "Änderungshistorie",
|
"changelog": "Änderungshistorie",
|
||||||
"chinese": "Chinesisch (vereinfacht)",
|
"chinese": "Chinesisch (vereinfacht)",
|
||||||
|
"clear-all": "",
|
||||||
"close": "Schließen",
|
"close": "Schließen",
|
||||||
"comment": "{n, plural, =1 {Kommentar} other {Kommentare}}",
|
"comment": "{n, plural, =1 {Kommentar} other {Kommentare}}",
|
||||||
"completed": "Abgeschlossen",
|
"completed": "Abgeschlossen",
|
||||||
@@ -121,6 +122,8 @@
|
|||||||
"following": "Folgt",
|
"following": "Folgt",
|
||||||
"forgot-your-password": "Passwort vergessen?",
|
"forgot-your-password": "Passwort vergessen?",
|
||||||
"french": "Französisch",
|
"french": "Französisch",
|
||||||
|
"from-file": "",
|
||||||
|
"from-url": "",
|
||||||
"german": "Deutsch",
|
"german": "Deutsch",
|
||||||
"get-position-from-exif": "Koordinaten aus EXIF Daten",
|
"get-position-from-exif": "Koordinaten aus EXIF Daten",
|
||||||
"grid": "Gitter",
|
"grid": "Gitter",
|
||||||
@@ -190,6 +193,7 @@
|
|||||||
"no-routes-added": "Keine Routen hinzugefügt",
|
"no-routes-added": "Keine Routen hinzugefügt",
|
||||||
"no-waypoints-yet": "Noch keine Wegpunkte",
|
"no-waypoints-yet": "Noch keine Wegpunkte",
|
||||||
"not-a-valid-email-address": "Keine gültige Email-Adresse",
|
"not-a-valid-email-address": "Keine gültige Email-Adresse",
|
||||||
|
"not-a-valid-url": "",
|
||||||
"not-completed": "Nicht abgeschlossen",
|
"not-completed": "Nicht abgeschlossen",
|
||||||
"notification-list-create": "{user} hat eine neue Liste erstellt",
|
"notification-list-create": "{user} hat eine neue Liste erstellt",
|
||||||
"notification-list-share": "{user} hat eine Liste mit Dir geteilt",
|
"notification-list-share": "{user} hat eine Liste mit Dir geteilt",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
"change-password": "Change password",
|
"change-password": "Change password",
|
||||||
"changelog": "Changelog",
|
"changelog": "Changelog",
|
||||||
"chinese": "Chinese (simplified)",
|
"chinese": "Chinese (simplified)",
|
||||||
|
"clear-all": "Clear all",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
"comment": "{n, plural, =1 {Comment} other {Comments}}",
|
"comment": "{n, plural, =1 {Comment} other {Comments}}",
|
||||||
"completed": "Completed",
|
"completed": "Completed",
|
||||||
@@ -121,6 +122,8 @@
|
|||||||
"following": "Following",
|
"following": "Following",
|
||||||
"forgot-your-password": "Forgot your password?",
|
"forgot-your-password": "Forgot your password?",
|
||||||
"french": "French",
|
"french": "French",
|
||||||
|
"from-file": "From file",
|
||||||
|
"from-url": "From URL",
|
||||||
"german": "German",
|
"german": "German",
|
||||||
"get-position-from-exif": "Get coordinates from EXIF data",
|
"get-position-from-exif": "Get coordinates from EXIF data",
|
||||||
"grid": "Grid",
|
"grid": "Grid",
|
||||||
@@ -190,6 +193,7 @@
|
|||||||
"no-routes-added": "No routes added",
|
"no-routes-added": "No routes added",
|
||||||
"no-waypoints-yet": "No waypoints yet",
|
"no-waypoints-yet": "No waypoints yet",
|
||||||
"not-a-valid-email-address": "Not a valid email address",
|
"not-a-valid-email-address": "Not a valid email address",
|
||||||
|
"not-a-valid-url": "Not a valid URL",
|
||||||
"not-completed": "Not completed",
|
"not-completed": "Not completed",
|
||||||
"notification-list-create": "{user} created a new list",
|
"notification-list-create": "{user} created a new list",
|
||||||
"notification-list-share": "{user} shared a list with you",
|
"notification-list-share": "{user} shared a list with you",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
"change-password": "Cambiar password",
|
"change-password": "Cambiar password",
|
||||||
"changelog": "Registro de cambios",
|
"changelog": "Registro de cambios",
|
||||||
"chinese": "Chinés (simplificado)",
|
"chinese": "Chinés (simplificado)",
|
||||||
|
"clear-all": "",
|
||||||
"close": "Cerrar",
|
"close": "Cerrar",
|
||||||
"comment": "{n, plural, one {}=1 {Comentario} other {Comentarios}}",
|
"comment": "{n, plural, one {}=1 {Comentario} other {Comentarios}}",
|
||||||
"completed": "Completado",
|
"completed": "Completado",
|
||||||
@@ -121,6 +122,8 @@
|
|||||||
"following": "Siguiendo",
|
"following": "Siguiendo",
|
||||||
"forgot-your-password": "¿Contraseña olvidada?",
|
"forgot-your-password": "¿Contraseña olvidada?",
|
||||||
"french": "Francés",
|
"french": "Francés",
|
||||||
|
"from-file": "",
|
||||||
|
"from-url": "",
|
||||||
"german": "Alemán",
|
"german": "Alemán",
|
||||||
"get-position-from-exif": "Obtener las coordenadas de los datos EXIF",
|
"get-position-from-exif": "Obtener las coordenadas de los datos EXIF",
|
||||||
"grid": "Cuadricula",
|
"grid": "Cuadricula",
|
||||||
@@ -190,6 +193,7 @@
|
|||||||
"no-routes-added": "Ninguna ruta añadida",
|
"no-routes-added": "Ninguna ruta añadida",
|
||||||
"no-waypoints-yet": "No Puntos de Interés todavía",
|
"no-waypoints-yet": "No Puntos de Interés todavía",
|
||||||
"not-a-valid-email-address": "Correo electrónico no válido",
|
"not-a-valid-email-address": "Correo electrónico no válido",
|
||||||
|
"not-a-valid-url": "",
|
||||||
"not-completed": "No completado",
|
"not-completed": "No completado",
|
||||||
"notification-list-create": "{user} ha creado una nueva lista",
|
"notification-list-create": "{user} ha creado una nueva lista",
|
||||||
"notification-list-share": "{user} ha compartido una nueva lista contigo",
|
"notification-list-share": "{user} ha compartido una nueva lista contigo",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
"change-password": "Changer de mot de passe",
|
"change-password": "Changer de mot de passe",
|
||||||
"changelog": "Journal des modifications",
|
"changelog": "Journal des modifications",
|
||||||
"chinese": "Chinois (simplifié)",
|
"chinese": "Chinois (simplifié)",
|
||||||
|
"clear-all": "",
|
||||||
"close": "Fermer",
|
"close": "Fermer",
|
||||||
"comment": "{n, plural, =1 {Commentaire} other {Commentaires}}",
|
"comment": "{n, plural, =1 {Commentaire} other {Commentaires}}",
|
||||||
"completed": "Terminé",
|
"completed": "Terminé",
|
||||||
@@ -121,6 +122,8 @@
|
|||||||
"following": "Following",
|
"following": "Following",
|
||||||
"forgot-your-password": "Mot de passe oublié ?",
|
"forgot-your-password": "Mot de passe oublié ?",
|
||||||
"french": "Français",
|
"french": "Français",
|
||||||
|
"from-file": "",
|
||||||
|
"from-url": "",
|
||||||
"german": "Allemand",
|
"german": "Allemand",
|
||||||
"get-position-from-exif": "Obtenir les coordonnées à partir des données EXIF",
|
"get-position-from-exif": "Obtenir les coordonnées à partir des données EXIF",
|
||||||
"grid": "Grille",
|
"grid": "Grille",
|
||||||
@@ -190,6 +193,7 @@
|
|||||||
"no-routes-added": "No routes added",
|
"no-routes-added": "No routes added",
|
||||||
"no-waypoints-yet": "No waypoints yet",
|
"no-waypoints-yet": "No waypoints yet",
|
||||||
"not-a-valid-email-address": "Adresse email invalide",
|
"not-a-valid-email-address": "Adresse email invalide",
|
||||||
|
"not-a-valid-url": "",
|
||||||
"not-completed": "Non terminés",
|
"not-completed": "Non terminés",
|
||||||
"notification-list-create": "{user} created a new list",
|
"notification-list-create": "{user} created a new list",
|
||||||
"notification-list-share": "{user} shared a list with you",
|
"notification-list-share": "{user} shared a list with you",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
"change-password": "Change password",
|
"change-password": "Change password",
|
||||||
"changelog": "Változás napló",
|
"changelog": "Változás napló",
|
||||||
"chinese": "Kínai (egyszerűsítve)",
|
"chinese": "Kínai (egyszerűsítve)",
|
||||||
|
"clear-all": "",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
"comment": "{n, plural, =1 {Megjegyzés} other {Megjegyzés}}",
|
"comment": "{n, plural, =1 {Megjegyzés} other {Megjegyzés}}",
|
||||||
"completed": "Teljesítve",
|
"completed": "Teljesítve",
|
||||||
@@ -121,6 +122,8 @@
|
|||||||
"following": "Following",
|
"following": "Following",
|
||||||
"forgot-your-password": "Forgot your password?",
|
"forgot-your-password": "Forgot your password?",
|
||||||
"french": "Francia",
|
"french": "Francia",
|
||||||
|
"from-file": "",
|
||||||
|
"from-url": "",
|
||||||
"german": "Német",
|
"german": "Német",
|
||||||
"get-position-from-exif": "Get coordinates from EXIF data",
|
"get-position-from-exif": "Get coordinates from EXIF data",
|
||||||
"grid": "Grid",
|
"grid": "Grid",
|
||||||
@@ -190,6 +193,7 @@
|
|||||||
"no-routes-added": "No routes added",
|
"no-routes-added": "No routes added",
|
||||||
"no-waypoints-yet": "No waypoints yet",
|
"no-waypoints-yet": "No waypoints yet",
|
||||||
"not-a-valid-email-address": "Érvénytelen e-mail cím",
|
"not-a-valid-email-address": "Érvénytelen e-mail cím",
|
||||||
|
"not-a-valid-url": "",
|
||||||
"not-completed": "Nem teljesített",
|
"not-completed": "Nem teljesített",
|
||||||
"notification-list-create": "{user} created a new list",
|
"notification-list-create": "{user} created a new list",
|
||||||
"notification-list-share": "{user} shared a list with you",
|
"notification-list-share": "{user} shared a list with you",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
"change-password": "Cambia password",
|
"change-password": "Cambia password",
|
||||||
"changelog": "Changelog",
|
"changelog": "Changelog",
|
||||||
"chinese": "Cinese (semplificato)",
|
"chinese": "Cinese (semplificato)",
|
||||||
|
"clear-all": "",
|
||||||
"close": "Chiudi",
|
"close": "Chiudi",
|
||||||
"comment": "{n, plural, =1 {Commento} other {Commenti}}",
|
"comment": "{n, plural, =1 {Commento} other {Commenti}}",
|
||||||
"completed": "Completato",
|
"completed": "Completato",
|
||||||
@@ -121,6 +122,8 @@
|
|||||||
"following": "Seguendo",
|
"following": "Seguendo",
|
||||||
"forgot-your-password": "Password dimenticata?",
|
"forgot-your-password": "Password dimenticata?",
|
||||||
"french": "Francese",
|
"french": "Francese",
|
||||||
|
"from-file": "",
|
||||||
|
"from-url": "",
|
||||||
"german": "Tedesco",
|
"german": "Tedesco",
|
||||||
"get-position-from-exif": "Ottieni posizione da dati EXIF",
|
"get-position-from-exif": "Ottieni posizione da dati EXIF",
|
||||||
"grid": "Griglia",
|
"grid": "Griglia",
|
||||||
@@ -190,6 +193,7 @@
|
|||||||
"no-routes-added": "Nessun percorso aggiunto",
|
"no-routes-added": "Nessun percorso aggiunto",
|
||||||
"no-waypoints-yet": "Ancora nessun punto d'interesse",
|
"no-waypoints-yet": "Ancora nessun punto d'interesse",
|
||||||
"not-a-valid-email-address": "Indirizzo email non valido",
|
"not-a-valid-email-address": "Indirizzo email non valido",
|
||||||
|
"not-a-valid-url": "",
|
||||||
"not-completed": "Non completato",
|
"not-completed": "Non completato",
|
||||||
"notification-list-create": "{user} ha creato una nuova lista",
|
"notification-list-create": "{user} ha creato una nuova lista",
|
||||||
"notification-list-share": "{user} ha condiviso una lista con te",
|
"notification-list-share": "{user} ha condiviso una lista con te",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
"change-password": "Wachtwoord wijzigen",
|
"change-password": "Wachtwoord wijzigen",
|
||||||
"changelog": "Wijzigingslog",
|
"changelog": "Wijzigingslog",
|
||||||
"chinese": "Versimpeld Chinees",
|
"chinese": "Versimpeld Chinees",
|
||||||
|
"clear-all": "",
|
||||||
"close": "Sluiten",
|
"close": "Sluiten",
|
||||||
"comment": "{n, plural, =1 {Opmerking} other {Opmerkingen}}",
|
"comment": "{n, plural, =1 {Opmerking} other {Opmerkingen}}",
|
||||||
"completed": "Voltooid",
|
"completed": "Voltooid",
|
||||||
@@ -121,6 +122,8 @@
|
|||||||
"following": "Following",
|
"following": "Following",
|
||||||
"forgot-your-password": "Forgot your password?",
|
"forgot-your-password": "Forgot your password?",
|
||||||
"french": "Frans",
|
"french": "Frans",
|
||||||
|
"from-file": "",
|
||||||
|
"from-url": "",
|
||||||
"german": "Duits",
|
"german": "Duits",
|
||||||
"get-position-from-exif": "Get coordinates from EXIF data",
|
"get-position-from-exif": "Get coordinates from EXIF data",
|
||||||
"grid": "Rooster",
|
"grid": "Rooster",
|
||||||
@@ -190,6 +193,7 @@
|
|||||||
"no-routes-added": "No routes added",
|
"no-routes-added": "No routes added",
|
||||||
"no-waypoints-yet": "No waypoints yet",
|
"no-waypoints-yet": "No waypoints yet",
|
||||||
"not-a-valid-email-address": "Het e-mailadres is ongeldig",
|
"not-a-valid-email-address": "Het e-mailadres is ongeldig",
|
||||||
|
"not-a-valid-url": "",
|
||||||
"not-completed": "Niet voltooid",
|
"not-completed": "Niet voltooid",
|
||||||
"notification-list-create": "{user} created a new list",
|
"notification-list-create": "{user} created a new list",
|
||||||
"notification-list-share": "{user} shared a list with you",
|
"notification-list-share": "{user} shared a list with you",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
"change-password": "Zmień hasło",
|
"change-password": "Zmień hasło",
|
||||||
"changelog": "Dziennik zmian",
|
"changelog": "Dziennik zmian",
|
||||||
"chinese": "Chiński (uproszczony)",
|
"chinese": "Chiński (uproszczony)",
|
||||||
|
"clear-all": "",
|
||||||
"close": "Zamknij",
|
"close": "Zamknij",
|
||||||
"comment": "{n, plural, =1 {Komentarz} other {Komentarze}}",
|
"comment": "{n, plural, =1 {Komentarz} other {Komentarze}}",
|
||||||
"completed": "Zakończono",
|
"completed": "Zakończono",
|
||||||
@@ -121,6 +122,8 @@
|
|||||||
"following": "Obserwowane",
|
"following": "Obserwowane",
|
||||||
"forgot-your-password": "Zapomniałeś hasła?",
|
"forgot-your-password": "Zapomniałeś hasła?",
|
||||||
"french": "Francuski",
|
"french": "Francuski",
|
||||||
|
"from-file": "",
|
||||||
|
"from-url": "",
|
||||||
"german": "Niemiecki",
|
"german": "Niemiecki",
|
||||||
"get-position-from-exif": "Odczytaj współrzędne z danych EXIF",
|
"get-position-from-exif": "Odczytaj współrzędne z danych EXIF",
|
||||||
"grid": "Siatka",
|
"grid": "Siatka",
|
||||||
@@ -190,6 +193,7 @@
|
|||||||
"no-routes-added": "No routes added",
|
"no-routes-added": "No routes added",
|
||||||
"no-waypoints-yet": "No waypoints yet",
|
"no-waypoints-yet": "No waypoints yet",
|
||||||
"not-a-valid-email-address": "Nieprawidłowy adres email",
|
"not-a-valid-email-address": "Nieprawidłowy adres email",
|
||||||
|
"not-a-valid-url": "",
|
||||||
"not-completed": "Nie dokończono",
|
"not-completed": "Nie dokończono",
|
||||||
"notification-list-create": "{user} utworzył(a) nową listę",
|
"notification-list-create": "{user} utworzył(a) nową listę",
|
||||||
"notification-list-share": "{user} udostępnił(a) tobie listę",
|
"notification-list-share": "{user} udostępnił(a) tobie listę",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
"change-password": "Mudar senha",
|
"change-password": "Mudar senha",
|
||||||
"changelog": "Registo de alterações",
|
"changelog": "Registo de alterações",
|
||||||
"chinese": "Chinês (simplificado)",
|
"chinese": "Chinês (simplificado)",
|
||||||
|
"clear-all": "",
|
||||||
"close": "Fechar",
|
"close": "Fechar",
|
||||||
"comment": "{n, plural, =1 {Comentário} other {Comentários}}",
|
"comment": "{n, plural, =1 {Comentário} other {Comentários}}",
|
||||||
"completed": "Completada",
|
"completed": "Completada",
|
||||||
@@ -121,6 +122,8 @@
|
|||||||
"following": "Following",
|
"following": "Following",
|
||||||
"forgot-your-password": "Forgot your password?",
|
"forgot-your-password": "Forgot your password?",
|
||||||
"french": "Francês",
|
"french": "Francês",
|
||||||
|
"from-file": "",
|
||||||
|
"from-url": "",
|
||||||
"german": "Alemão",
|
"german": "Alemão",
|
||||||
"get-position-from-exif": "Obter coordenadas dos dados EXIF",
|
"get-position-from-exif": "Obter coordenadas dos dados EXIF",
|
||||||
"grid": "Grelha",
|
"grid": "Grelha",
|
||||||
@@ -190,6 +193,7 @@
|
|||||||
"no-routes-added": "No routes added",
|
"no-routes-added": "No routes added",
|
||||||
"no-waypoints-yet": "No waypoints yet",
|
"no-waypoints-yet": "No waypoints yet",
|
||||||
"not-a-valid-email-address": "Não um endereço de e-mail válido",
|
"not-a-valid-email-address": "Não um endereço de e-mail válido",
|
||||||
|
"not-a-valid-url": "",
|
||||||
"not-completed": "Não preenchido",
|
"not-completed": "Não preenchido",
|
||||||
"notification-list-create": "{user} created a new list",
|
"notification-list-create": "{user} created a new list",
|
||||||
"notification-list-share": "{user} shared a list with you",
|
"notification-list-share": "{user} shared a list with you",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
"change-password": "更改密码",
|
"change-password": "更改密码",
|
||||||
"changelog": "变更日志",
|
"changelog": "变更日志",
|
||||||
"chinese": "中文(简体)",
|
"chinese": "中文(简体)",
|
||||||
|
"clear-all": "",
|
||||||
"close": "关闭",
|
"close": "关闭",
|
||||||
"comment": "{n, plural, =1 {评论} other {评论}}",
|
"comment": "{n, plural, =1 {评论} other {评论}}",
|
||||||
"completed": "已完成",
|
"completed": "已完成",
|
||||||
@@ -121,6 +122,8 @@
|
|||||||
"following": "Following",
|
"following": "Following",
|
||||||
"forgot-your-password": "忘记密码?",
|
"forgot-your-password": "忘记密码?",
|
||||||
"french": "法语",
|
"french": "法语",
|
||||||
|
"from-file": "",
|
||||||
|
"from-url": "",
|
||||||
"german": "德语",
|
"german": "德语",
|
||||||
"get-position-from-exif": "从EXIF数据获取坐标",
|
"get-position-from-exif": "从EXIF数据获取坐标",
|
||||||
"grid": "网格",
|
"grid": "网格",
|
||||||
@@ -190,6 +193,7 @@
|
|||||||
"no-routes-added": "No routes added",
|
"no-routes-added": "No routes added",
|
||||||
"no-waypoints-yet": "No waypoints yet",
|
"no-waypoints-yet": "No waypoints yet",
|
||||||
"not-a-valid-email-address": "无效电子邮箱地址",
|
"not-a-valid-email-address": "无效电子邮箱地址",
|
||||||
|
"not-a-valid-url": "",
|
||||||
"not-completed": "未完成",
|
"not-completed": "未完成",
|
||||||
"notification-list-create": "{user} created a new list",
|
"notification-list-create": "{user} created a new list",
|
||||||
"notification-list-share": "{user} shared a list with you",
|
"notification-list-share": "{user} shared a list with you",
|
||||||
|
|||||||
21
web/src/routes/api/v1/trail/download/+server.ts
Normal file
21
web/src/routes/api/v1/trail/download/+server.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { handleError } from "$lib/util/api_util";
|
||||||
|
import { type RequestEvent } from "@sveltejs/kit";
|
||||||
|
|
||||||
|
export async function POST(event: RequestEvent) {
|
||||||
|
const data = await event.request.json();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await event.fetch(data.url);
|
||||||
|
const blob = await response.blob();
|
||||||
|
|
||||||
|
const contentType = 'determine the content type here';
|
||||||
|
|
||||||
|
return new Response(blob, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': contentType,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
throw handleError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,37 +38,6 @@
|
|||||||
handleFileSelection(e.dataTransfer?.files);
|
handleFileSelection(e.dataTransfer?.files);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mockUpload(f: File, onProgess?: (progress: number) => void) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
console.log("here");
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
onProgess?.(10);
|
|
||||||
}, 400);
|
|
||||||
setTimeout(() => {
|
|
||||||
onProgess?.(30);
|
|
||||||
}, 500);
|
|
||||||
setTimeout(() => {
|
|
||||||
onProgess?.(50);
|
|
||||||
}, 800);
|
|
||||||
setTimeout(() => {
|
|
||||||
onProgess?.(70);
|
|
||||||
}, 1200);
|
|
||||||
setTimeout(() => {
|
|
||||||
onProgess?.(99);
|
|
||||||
}, 1300);
|
|
||||||
setTimeout(() => {
|
|
||||||
onProgess?.(100);
|
|
||||||
const random = Math.random();
|
|
||||||
if (random < 0.5) {
|
|
||||||
reject(false);
|
|
||||||
} else {
|
|
||||||
resolve(true);
|
|
||||||
}
|
|
||||||
}, 10000);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleFileSelection(files?: FileList | null) {
|
async function handleFileSelection(files?: FileList | null) {
|
||||||
if (!files) {
|
if (!files) {
|
||||||
files = (document.getElementById("file-input") as HTMLInputElement)
|
files = (document.getElementById("file-input") as HTMLInputElement)
|
||||||
|
|||||||
Reference in New Issue
Block a user