2024-06-28 15:43:57 +02:00
|
|
|
<script lang="ts">
|
2025-02-02 11:17:22 +01:00
|
|
|
import { Button } from '$lib/components/ui/button';
|
|
|
|
|
import { Label } from '$lib/components/ui/label';
|
|
|
|
|
import { Checkbox } from '$lib/components/ui/checkbox';
|
|
|
|
|
import { Separator } from '$lib/components/ui/separator';
|
|
|
|
|
import { Dialog } from 'bits-ui';
|
|
|
|
|
import {
|
|
|
|
|
exportAllFiles,
|
|
|
|
|
exportSelectedFiles,
|
|
|
|
|
ExportState,
|
|
|
|
|
exportState,
|
2025-06-21 21:07:36 +02:00
|
|
|
} from '$lib/components/export/utils.svelte';
|
2025-10-17 23:54:45 +02:00
|
|
|
import { currentTool } from '$lib/components/toolbar/tools';
|
2025-02-02 11:17:22 +01:00
|
|
|
import {
|
|
|
|
|
Download,
|
|
|
|
|
Zap,
|
|
|
|
|
Earth,
|
|
|
|
|
HeartPulse,
|
|
|
|
|
Orbit,
|
|
|
|
|
Thermometer,
|
|
|
|
|
SquareActivity,
|
2025-06-21 21:07:36 +02:00
|
|
|
} from '@lucide/svelte';
|
|
|
|
|
import { i18n } from '$lib/i18n.svelte';
|
2025-02-02 11:17:22 +01:00
|
|
|
import { GPXStatistics } from 'gpx';
|
2025-10-05 19:34:05 +02:00
|
|
|
import { ListRootItem } from '$lib/components/file-list/file-list';
|
2025-10-17 23:54:45 +02:00
|
|
|
import { fileStateCollection } from '$lib/logic/file-state';
|
|
|
|
|
import { selection } from '$lib/logic/selection';
|
2025-10-19 13:51:56 +02:00
|
|
|
import { gpxStatistics } from '$lib/logic/statistics';
|
|
|
|
|
import { get } from 'svelte/store';
|
2024-06-28 15:43:57 +02:00
|
|
|
|
2025-06-21 21:07:36 +02:00
|
|
|
let open = $derived(exportState.current !== ExportState.NONE);
|
|
|
|
|
let exportOptions: Record<string, boolean> = $state({
|
2025-02-02 11:17:22 +01:00
|
|
|
time: true,
|
|
|
|
|
hr: true,
|
|
|
|
|
cad: true,
|
|
|
|
|
atemp: true,
|
|
|
|
|
power: true,
|
|
|
|
|
extensions: false,
|
2025-06-21 21:07:36 +02:00
|
|
|
});
|
|
|
|
|
let hide: Record<string, boolean> = $derived.by(() => {
|
2025-10-19 13:51:56 +02:00
|
|
|
if (exportState.current === ExportState.NONE) {
|
|
|
|
|
return {
|
|
|
|
|
time: false,
|
|
|
|
|
hr: false,
|
|
|
|
|
cad: false,
|
|
|
|
|
atemp: false,
|
|
|
|
|
power: false,
|
|
|
|
|
extensions: false,
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
let statistics = $gpxStatistics;
|
|
|
|
|
if (exportState.current === ExportState.ALL) {
|
|
|
|
|
statistics = Array.from(get(fileStateCollection).values())
|
|
|
|
|
.map((file) => file.statistics)
|
|
|
|
|
.reduce((acc, cur) => {
|
|
|
|
|
if (cur !== undefined) {
|
|
|
|
|
acc.mergeWith(cur.getStatisticsFor(new ListRootItem()));
|
|
|
|
|
}
|
|
|
|
|
return acc;
|
|
|
|
|
}, new GPXStatistics());
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
time: statistics.global.time.total === 0,
|
|
|
|
|
hr: statistics.global.hr.count === 0,
|
|
|
|
|
cad: statistics.global.cad.count === 0,
|
|
|
|
|
atemp: statistics.global.atemp.count === 0,
|
|
|
|
|
power: statistics.global.power.count === 0,
|
|
|
|
|
extensions: Object.keys(statistics.global.extensions).length === 0,
|
|
|
|
|
};
|
|
|
|
|
}
|
2025-06-21 21:07:36 +02:00
|
|
|
});
|
|
|
|
|
let exclude = $derived(Object.keys(exportOptions).filter((key) => !exportOptions[key]));
|
2024-07-23 11:20:31 +02:00
|
|
|
|
2025-06-21 21:07:36 +02:00
|
|
|
$effect(() => {
|
|
|
|
|
if (open) {
|
2025-10-17 23:54:45 +02:00
|
|
|
currentTool.set(null);
|
2025-06-21 21:07:36 +02:00
|
|
|
}
|
|
|
|
|
});
|
2024-06-28 15:43:57 +02:00
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<Dialog.Root
|
2025-02-02 11:17:22 +01:00
|
|
|
bind:open
|
|
|
|
|
onOpenChange={(isOpen) => {
|
|
|
|
|
if (!isOpen) {
|
2025-06-21 21:07:36 +02:00
|
|
|
exportState.current = ExportState.NONE;
|
2025-02-02 11:17:22 +01:00
|
|
|
}
|
|
|
|
|
}}
|
2024-06-28 15:43:57 +02:00
|
|
|
>
|
2025-02-02 11:17:22 +01:00
|
|
|
<Dialog.Trigger class="hidden" />
|
|
|
|
|
<Dialog.Portal>
|
|
|
|
|
<Dialog.Content
|
|
|
|
|
class="fixed left-[50%] top-[50%] z-50 w-fit max-w-full translate-x-[-50%] translate-y-[-50%] flex flex-col items-center gap-3 border bg-background p-3 shadow-lg rounded-md"
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
class="w-full flex flex-row items-center justify-center gap-4 border rounded-md p-2 bg-secondary"
|
|
|
|
|
>
|
|
|
|
|
<span>⚠️</span>
|
|
|
|
|
<span class="max-w-[80%] text-sm">
|
2025-06-21 21:07:36 +02:00
|
|
|
{i18n._('menu.support_message')}
|
2025-02-02 11:17:22 +01:00
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="w-full flex flex-row flex-wrap gap-2">
|
|
|
|
|
<Button class="bg-support grow" href="https://ko-fi.com/gpxstudio" target="_blank">
|
2025-06-21 21:07:36 +02:00
|
|
|
{i18n._('menu.support_button')}
|
2025-02-02 11:17:22 +01:00
|
|
|
<span class="ml-2">🙏</span>
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
class="grow"
|
2025-06-21 21:07:36 +02:00
|
|
|
onclick={() => {
|
|
|
|
|
if (exportState.current === ExportState.SELECTION) {
|
2025-02-02 11:17:22 +01:00
|
|
|
exportSelectedFiles(exclude);
|
2025-06-21 21:07:36 +02:00
|
|
|
} else if (exportState.current === ExportState.ALL) {
|
2025-02-02 11:17:22 +01:00
|
|
|
exportAllFiles(exclude);
|
|
|
|
|
}
|
|
|
|
|
open = false;
|
2025-06-21 21:07:36 +02:00
|
|
|
exportState.current = ExportState.NONE;
|
2025-02-02 11:17:22 +01:00
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Download size="16" class="mr-1" />
|
2025-10-17 23:54:45 +02:00
|
|
|
{#if $fileStateCollection.size === 1 || (exportState.current === ExportState.SELECTION && $selection.size === 1)}
|
2025-06-21 21:07:36 +02:00
|
|
|
{i18n._('menu.download_file')}
|
2025-02-02 11:17:22 +01:00
|
|
|
{:else}
|
2025-06-21 21:07:36 +02:00
|
|
|
{i18n._('menu.download_files')}
|
2025-02-02 11:17:22 +01:00
|
|
|
{/if}
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
class="w-full max-w-xl flex flex-col items-center gap-2 {Object.values(hide).some(
|
|
|
|
|
(v) => !v
|
|
|
|
|
)
|
|
|
|
|
? ''
|
|
|
|
|
: 'hidden'}"
|
|
|
|
|
>
|
|
|
|
|
<div class="w-full flex flex-row items-center gap-3">
|
|
|
|
|
<div class="grow">
|
|
|
|
|
<Separator />
|
|
|
|
|
</div>
|
|
|
|
|
<Label class="shrink-0">
|
2025-06-21 21:07:36 +02:00
|
|
|
{i18n._('menu.export_options')}
|
2025-02-02 11:17:22 +01:00
|
|
|
</Label>
|
|
|
|
|
<div class="grow">
|
|
|
|
|
<Separator />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-row flex-wrap justify-center gap-x-6 gap-y-2">
|
|
|
|
|
<div class="flex flex-row items-center gap-1.5 {hide.time ? 'hidden' : ''}">
|
|
|
|
|
<Checkbox id="export-time" bind:checked={exportOptions.time} />
|
|
|
|
|
<Label for="export-time" class="flex flex-row items-center gap-1">
|
|
|
|
|
<Zap size="16" />
|
2025-06-21 21:07:36 +02:00
|
|
|
{i18n._('quantities.time')}
|
2025-02-02 11:17:22 +01:00
|
|
|
</Label>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-row items-center gap-1.5 {hide.hr ? 'hidden' : ''}">
|
|
|
|
|
<Checkbox id="export-heartrate" bind:checked={exportOptions.hr} />
|
|
|
|
|
<Label for="export-heartrate" class="flex flex-row items-center gap-1">
|
|
|
|
|
<HeartPulse size="16" />
|
2025-06-21 21:07:36 +02:00
|
|
|
{i18n._('quantities.heartrate')}
|
2025-02-02 11:17:22 +01:00
|
|
|
</Label>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-row items-center gap-1.5 {hide.cad ? 'hidden' : ''}">
|
|
|
|
|
<Checkbox id="export-cadence" bind:checked={exportOptions.cad} />
|
|
|
|
|
<Label for="export-cadence" class="flex flex-row items-center gap-1">
|
|
|
|
|
<Orbit size="16" />
|
2025-06-21 21:07:36 +02:00
|
|
|
{i18n._('quantities.cadence')}
|
2025-02-02 11:17:22 +01:00
|
|
|
</Label>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-row items-center gap-1.5 {hide.atemp ? 'hidden' : ''}">
|
|
|
|
|
<Checkbox id="export-temperature" bind:checked={exportOptions.atemp} />
|
|
|
|
|
<Label for="export-temperature" class="flex flex-row items-center gap-1">
|
|
|
|
|
<Thermometer size="16" />
|
2025-06-21 21:07:36 +02:00
|
|
|
{i18n._('quantities.temperature')}
|
2025-02-02 11:17:22 +01:00
|
|
|
</Label>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-row items-center gap-1.5 {hide.power ? 'hidden' : ''}">
|
|
|
|
|
<Checkbox id="export-power" bind:checked={exportOptions.power} />
|
|
|
|
|
<Label for="export-power" class="flex flex-row items-center gap-1">
|
|
|
|
|
<SquareActivity size="16" />
|
2025-06-21 21:07:36 +02:00
|
|
|
{i18n._('quantities.power')}
|
2025-02-02 11:17:22 +01:00
|
|
|
</Label>
|
|
|
|
|
</div>
|
2025-10-19 13:51:56 +02:00
|
|
|
<div
|
|
|
|
|
class="flex flex-row items-center gap-1.5 {hide.extensions ? 'hidden' : ''}"
|
|
|
|
|
>
|
|
|
|
|
<Checkbox id="export-extensions" bind:checked={exportOptions.extensions} />
|
|
|
|
|
<Label for="export-extensions" class="flex flex-row items-center gap-1">
|
|
|
|
|
<Earth size="16" />
|
|
|
|
|
{i18n._('quantities.osm_extensions')}
|
|
|
|
|
</Label>
|
|
|
|
|
</div>
|
2025-02-02 11:17:22 +01:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</Dialog.Content>
|
|
|
|
|
</Dialog.Portal>
|
2024-06-28 15:43:57 +02:00
|
|
|
</Dialog.Root>
|