adds trail export

This commit is contained in:
Christian Beutel
2024-05-05 15:46:17 +02:00
parent 930feda4d6
commit 756a9fa79f
18 changed files with 310 additions and 31 deletions

View File

@@ -9,17 +9,22 @@
} from "$lib/stores/list_store";
import { show_toast } from "$lib/stores/toast_store";
import { trails_delete } from "$lib/stores/trail_store";
import { getFileURL } from "$lib/util/file_util";
import { trail2gpx } from "$lib/util/gpx_util";
import { gpx } from "$lib/vendor/toGeoJSON/toGeoJSON";
import { _ } from "svelte-i18n";
import Dropdown, { type DropdownItem } from "../base/dropdown.svelte";
import ConfirmModal from "../confirm_modal.svelte";
import ListSelectModal from "../list/list_select_modal.svelte";
import { _ } from "svelte-i18n";
import TrailExportModal from "./trail_export_modal.svelte";
import JSZip from "jszip";
import { getFileURL, saveAs } from "$lib/util/file_util";
export let trail: Trail;
export let mode: "overview" | "map";
let openConfirmModal: () => void;
let openListSelectModal: () => void;
let openExportModal: () => void;
const dropdownItems: DropdownItem[] = [
mode == "overview"
@@ -34,7 +39,7 @@
...(trail.gpx
? [
{
text: $_("download-gpx"),
text: $_("export"),
value: "download",
icon: "download",
},
@@ -65,7 +70,7 @@
} else if (item.value == "print") {
goto(`/map/trail/${trail.id}/print`);
} else if (item.value == "download") {
downloadURI(getFileURL(trail, trail.gpx), trail.gpx!);
openExportModal();
} else if (item.value == "edit") {
goto(`/trail/edit/${trail.id}`);
} else if (item.value == "delete") {
@@ -73,13 +78,46 @@
}
}
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 exportTrail(exportSettings: {
fileFormat: "gpx" | "json";
photos: boolean;
summitLog: boolean;
}) {
try {
let fileData: string = await trail2gpx(trail);
if (exportSettings.fileFormat == "json") {
fileData = JSON.stringify(gpx(new DOMParser().parseFromString(fileData, "text/xml")));
}
const zip = new JSZip();
zip.file(`${trail.name}.${exportSettings.fileFormat}`, fileData);
if (exportSettings.photos) {
const photoFolder = zip.folder($_("photos"));
for (const photo of trail.photos) {
const photoURL = getFileURL(trail, photo);
const photoBlob = await fetch(photoURL).then((response) =>
response.blob(),
);
const photoData = new File([photoBlob], photo);
photoFolder?.file(photo, photoData, { base64: true });
}
}
if(exportSettings.summitLog) {
let summitLogString = ""
for (const summitLog of trail.expand.summit_logs) {
summitLogString += `${summitLog.date},${summitLog.text}\n`
}
zip.file(`${trail.name} - ${$_("summit-book")}.csv`, summitLogString)
}
const blob = await zip.generateAsync({ type: "blob" });
saveAs(blob, `${trail.name}.zip`);
} catch (e) {
console.error(e);
show_toast({
type: "error",
icon: "close",
text: $_("error-exporting-trail"),
});
}
}
async function deleteTrail() {
@@ -137,3 +175,7 @@
bind:openModal={openListSelectModal}
on:change={(e) => handleListSelection(e.detail)}
></ListSelectModal>
<TrailExportModal
bind:openModal={openExportModal}
on:export={(e) => exportTrail(e.detail)}
></TrailExportModal>

View File

@@ -0,0 +1,80 @@
<script lang="ts">
import Modal from "$lib/components/base/modal.svelte";
import { createEventDispatcher } from "svelte";
import { _ } from "svelte-i18n";
import Select from "../base/select.svelte";
export let openModal: (() => void) | undefined = undefined;
export let closeModal: (() => void) | undefined = undefined;
const dispatch = createEventDispatcher();
const fileFormats = [
{ text: "GPX", value: "gpx" },
{ text: "GeoJSON", value: "json" },
];
const exportSettings = {
fileFormat: "gpx",
photos: false,
summitLog: false,
};
function exportTrail() {
dispatch("export", exportSettings);
closeModal!();
}
</script>
<Modal
id="export-modal"
title="Export trail"
size="max-w-sm"
bind:openModal
bind:closeModal
>
<div slot="content">
<div class="mb-3">
<Select
bind:value={exportSettings.fileFormat}
items={fileFormats}
label={$_("file-format")}
></Select>
</div>
<div class="mb-2">
<input
id="include-photos-checkbox"
type="checkbox"
bind:checked={exportSettings.photos}
class="w-4 h-4 bg-input-background accent-primary border-input-border focus:ring-input-ring focus:ring-2"
/>
<label for="include-photos-checkbox" class="ms-2 text-sm"
>{$_("photos")}</label
>
</div>
<div class="mb-2">
<input
id="include-summit-log-checkbox"
type="checkbox"
bind:checked={exportSettings.summitLog}
class="w-4 h-4 bg-input-background accent-primary border-input-border focus:ring-input-ring focus:ring-2"
/>
<label for="include-summit-log-checkbox" class="ms-2 text-sm"
>{$_("summit-book")}</label
>
</div>
</div>
<div slot="footer" class="flex items-center gap-4">
<button class="btn-secondary" on:click={closeModal}
>{$_("cancel")}</button
>
<button
class="btn-primary"
type="button"
on:click={exportTrail}
name="save">{$_("export")}</button
>
</div></Modal
>