export options

This commit is contained in:
vcoppe
2024-07-23 11:20:31 +02:00
parent 1be9059e39
commit 75d9813fe0
13 changed files with 258 additions and 4279 deletions

View File

@@ -71,10 +71,7 @@
},
"devDependencies": {
"@types/geojson": "^7946.0.14",
"@types/jest": "^29.5.12",
"@types/node": "^20.14.6",
"jest": "^29.7.0",
"ts-jest": "^29.1.5",
"typescript": "^5.4.5"
}
},

View File

@@ -67,4 +67,4 @@
"tailwind-merge": "^2.3.0",
"tailwind-variants": "^0.2.1"
}
}
}

View File

@@ -1,24 +1,75 @@
<script lang="ts">
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 {
currentTool,
exportAllFiles,
exportSelectedFiles,
ExportState,
exportState
exportState,
gpxStatistics
} from '$lib/stores';
import { fileObservers } from '$lib/db';
import { Download } from 'lucide-svelte';
import {
Download,
Zap,
BrickWall,
HeartPulse,
Orbit,
Thermometer,
SquareActivity
} from 'lucide-svelte';
import { _ } from 'svelte-i18n';
import { selection } from './file-list/Selection';
import { get } from 'svelte/store';
import { GPXStatistics } from 'gpx';
import { ListRootItem } from './file-list/FileList';
let open = false;
let exportOptions: Record<string, boolean> = {
time: true,
surface: true,
hr: true,
cad: true,
atemp: true,
power: true
};
let hide: Record<string, boolean> = {
time: false,
surface: false,
hr: false,
cad: false,
atemp: false,
power: false
};
$: if ($exportState !== ExportState.NONE) {
open = true;
$currentTool = null;
let statistics = $gpxStatistics;
if ($exportState === ExportState.ALL) {
statistics = Array.from($fileObservers.values())
.map((file) => get(file)?.statistics)
.reduce((acc, cur) => {
if (cur !== undefined) {
acc.mergeWith(cur.getStatisticsFor(new ListRootItem()));
}
return acc;
}, new GPXStatistics());
}
hide.time = statistics.global.time.total === 0;
hide.hr = statistics.global.hr.count === 0;
hide.cad = statistics.global.cad.count === 0;
hide.atemp = statistics.global.atemp.count === 0;
hide.power = statistics.global.power.count === 0;
}
$: exclude = Object.keys(exportOptions).filter((key) => !exportOptions[key]);
</script>
<Dialog.Root
@@ -32,9 +83,11 @@
<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-2 border bg-background p-3 shadow-lg rounded-md"
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="flex flex-row items-center gap-4 border rounded-md p-2">
<div
class="w-full flex flex-row items-center justify-center gap-4 border rounded-md p-2 bg-accent"
>
<span>⚠️</span>
<span class="max-w-96 text-sm">
{$_('menu.support_message')}
@@ -50,9 +103,9 @@
class="grow"
on:click={() => {
if ($exportState === ExportState.SELECTION) {
exportSelectedFiles();
exportSelectedFiles(exclude);
} else if ($exportState === ExportState.ALL) {
exportAllFiles();
exportAllFiles(exclude);
}
open = false;
$exportState = ExportState.NONE;
@@ -66,6 +119,63 @@
{/if}
</Button>
</div>
<div class="w-full max-w-xl flex flex-col items-center gap-2">
<div class="w-full flex flex-row items-center gap-3">
<div class="grow">
<Separator />
</div>
<Label class="shrink-0">
{$_('menu.export_options')}
</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" />
{$_('quantities.time')}
</Label>
</div>
<div class="flex flex-row items-center gap-1.5">
<Checkbox id="export-surface" bind:checked={exportOptions.surface} />
<Label for="export-surface" class="flex flex-row items-center gap-1">
<BrickWall size="16" />
{$_('quantities.surface')}
</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" />
{$_('quantities.heartrate')}
</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" />
{$_('quantities.cadence')}
</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" />
{$_('quantities.temperature')}
</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" />
{$_('quantities.power')}
</Label>
</div>
</div>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>

View File

@@ -320,30 +320,30 @@ export function updateSelectionFromKey(down: boolean, shift: boolean) {
}
}
async function exportFiles(fileIds: string[]) {
async function exportFiles(fileIds: string[], exclude: string[]) {
for (let fileId of fileIds) {
let file = getFile(fileId);
if (file) {
exportFile(file);
exportFile(file, exclude);
await new Promise(resolve => setTimeout(resolve, 200));
}
}
}
export function exportSelectedFiles() {
export function exportSelectedFiles(exclude: string[]) {
let fileIds: string[] = [];
applyToOrderedSelectedItemsFromFile(async (fileId, level, items) => {
fileIds.push(fileId);
});
exportFiles(fileIds);
exportFiles(fileIds, exclude);
}
export function exportAllFiles() {
exportFiles(get(fileOrder));
export function exportAllFiles(exclude: string[]) {
exportFiles(get(fileOrder), exclude);
}
export function exportFile(file: GPXFile) {
let blob = new Blob([buildGPX(file)], { type: 'application/gpx+xml' });
export function exportFile(file: GPXFile, exclude: string[]) {
let blob = new Blob([buildGPX(file, exclude)], { type: 'application/gpx+xml' });
let url = URL.createObjectURL(blob);
let a = document.createElement('a');
a.href = url;

View File

@@ -20,6 +20,7 @@
"cut": "Cut",
"export": "Export...",
"export_all": "Export all...",
"export_options": "Export options",
"support_message": "The tool is free to use, but not free to run. Please consider supporting the website if you use it frequently. Thank you!",
"support_button": "Help keep the website free",
"download_file": "Download file",