Files
gpx.studio/website/src/lib/components/export/Export.svelte
T

201 lines
8.1 KiB
Svelte
Raw Normal View History

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 {
2026-10-08 09:24:15 +02:00
allFileIds,
2025-02-02 11:17:22 +01:00
exportAllFiles,
exportSelectedFiles,
2026-10-08 09:24:15 +02:00
selectedFileIds,
2025-02-02 11:17:22 +01:00
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';
2026-10-08 09:24:15 +02:00
import { engine, type ExportOptions } from '$lib/engine';
const selection = engine.selection;
const order = engine.order;
const files = engine.files;
2024-06-28 15:43:57 +02:00
2025-06-21 21:07:36 +02:00
let open = $derived(exportState.current !== ExportState.NONE);
2026-10-08 09:24:15 +02:00
let exportOptions: ExportOptions = $state({
2025-02-02 11:17:22 +01:00
time: true,
hr: true,
cad: true,
atemp: true,
power: true,
2026-10-08 09:24:15 +02:00
osm: false,
2025-06-21 21:07:36 +02:00
});
2026-10-08 09:24:15 +02:00
// the files that are exported
let fileIds: string[] = $derived.by(() => {
// the selection and the order change with the files
void $selection;
void $order;
void $files;
if (exportState.current === ExportState.SELECTION) {
return selectedFileIds();
} else if (exportState.current === ExportState.ALL) {
return allFileIds();
2025-10-19 13:51:56 +02:00
}
2026-10-08 09:24:15 +02:00
return [];
});
// the data that none of them has is not offered
let hide: Record<keyof ExportOptions, boolean> = $derived.by(() => {
const available = engine.exportableData(fileIds);
return {
time: !available.time,
hr: !available.hr,
cad: !available.cad,
atemp: !available.atemp,
power: !available.power,
osm: !available.osm,
};
2025-06-21 21:07:36 +02:00
});
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
2025-11-10 11:51:16 +01:00
class="w-full flex flex-col sm:flex-row items-center justify-center gap-1 sm:gap-2 border rounded-md p-2 bg-secondary"
2025-02-02 11:17:22 +01:00
>
2025-11-10 11:51:16 +01:00
<span class="w-12 shrink-0 text-center text-xl">⚠️</span>
<span class="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">
2026-03-25 21:53:10 +01:00
<Button
class="bg-support grow"
href="https://opencollective.com/gpxstudio"
target="_blank"
>
2025-06-21 21:07:36 +02:00
{i18n._('menu.support_button')}
2025-11-10 11:51:16 +01:00
<span>🙏</span>
2025-02-02 11:17:22 +01:00
</Button>
<Button
variant="outline"
class="grow"
2025-06-21 21:07:36 +02:00
onclick={() => {
2026-10-08 09:24:15 +02:00
// what is not offered is left out
const options = {
time: exportOptions.time && !hide.time,
hr: exportOptions.hr && !hide.hr,
cad: exportOptions.cad && !hide.cad,
atemp: exportOptions.atemp && !hide.atemp,
power: exportOptions.power && !hide.power,
osm: exportOptions.osm && !hide.osm,
};
2025-06-21 21:07:36 +02:00
if (exportState.current === ExportState.SELECTION) {
2026-10-08 09:24:15 +02:00
exportSelectedFiles(options);
2025-06-21 21:07:36 +02:00
} else if (exportState.current === ExportState.ALL) {
2026-10-08 09:24:15 +02:00
exportAllFiles(options);
2025-02-02 11:17:22 +01:00
}
open = false;
2025-06-21 21:07:36 +02:00
exportState.current = ExportState.NONE;
2025-02-02 11:17:22 +01:00
}}
>
2025-11-10 11:51:16 +01:00
<Download size="16" />
2026-10-08 09:24:15 +02:00
{#if fileIds.length === 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
2026-10-08 09:24:15 +02:00
class="flex flex-row items-center gap-1.5 {hide.osm ? 'hidden' : ''}"
2025-10-19 13:51:56 +02:00
>
2026-10-08 09:24:15 +02:00
<Checkbox id="export-osm" bind:checked={exportOptions.osm} />
<Label for="export-osm" class="flex flex-row items-center gap-1">
2025-10-19 13:51:56 +02:00
<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>