mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-08-31 15:43:25 +00:00
export dialog progress
This commit is contained in:
8
website/package-lock.json
generated
8
website/package-lock.json
generated
@@ -10,7 +10,7 @@
|
||||
"dependencies": {
|
||||
"@internationalized/date": "^3.5.4",
|
||||
"@mapbox/mapbox-gl-geocoder": "^5.0.2",
|
||||
"bits-ui": "^0.21.10",
|
||||
"bits-ui": "^0.21.11",
|
||||
"chart.js": "^4.4.3",
|
||||
"clsx": "^2.1.1",
|
||||
"dexie": "^4.0.7",
|
||||
@@ -1911,9 +1911,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/bits-ui": {
|
||||
"version": "0.21.10",
|
||||
"resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-0.21.10.tgz",
|
||||
"integrity": "sha512-KuweEOKO0Rr8XX87dQh46G9mG0bZSmTqNxj5qBazz4OTQC+oPKui04/wP/ISsCOSGFomaRydTULqh4p+nsyc2g==",
|
||||
"version": "0.21.11",
|
||||
"resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-0.21.11.tgz",
|
||||
"integrity": "sha512-pFS/9z1qLaPZwb+9Tm0YS4iBp+ClsJBARMZWFOjv0lGCYpzAN7lx4eNk3SbSB5QMBUKwoVjr9Rai71ROq3RD1Q==",
|
||||
"dependencies": {
|
||||
"@internationalized/date": "^3.5.1",
|
||||
"@melt-ui/svelte": "0.76.2",
|
||||
|
@@ -45,7 +45,7 @@
|
||||
"dependencies": {
|
||||
"@internationalized/date": "^3.5.4",
|
||||
"@mapbox/mapbox-gl-geocoder": "^5.0.2",
|
||||
"bits-ui": "^0.21.10",
|
||||
"bits-ui": "^0.21.11",
|
||||
"chart.js": "^4.4.3",
|
||||
"clsx": "^2.1.1",
|
||||
"dexie": "^4.0.7",
|
||||
@@ -61,4 +61,4 @@
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"tailwind-variants": "^0.2.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
77
website/src/lib/components/Export.svelte
Normal file
77
website/src/lib/components/Export.svelte
Normal file
@@ -0,0 +1,77 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Dialog } from 'bits-ui';
|
||||
import {
|
||||
currentTool,
|
||||
exportAllFiles,
|
||||
exportSelectedFiles,
|
||||
ExportState,
|
||||
exportState
|
||||
} from '$lib/stores';
|
||||
import { fileObservers } from '$lib/db';
|
||||
import { Cloud, Download } from 'lucide-svelte';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { selection } from './file-list/Selection';
|
||||
|
||||
let open = false;
|
||||
|
||||
$: if ($exportState !== ExportState.NONE) {
|
||||
open = true;
|
||||
$currentTool = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root
|
||||
bind:open
|
||||
onOpenChange={(isOpen) => {
|
||||
if (!isOpen) {
|
||||
$exportState = ExportState.NONE;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<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"
|
||||
>
|
||||
<div class="flex flex-col items-center gap-2 rounded border p-2">
|
||||
<div class="flex flex-row items-center gap-2 text-sm">
|
||||
<span>⚠️</span>
|
||||
<span class="text-center max-w-96">
|
||||
{$_('menu.support_message')}
|
||||
</span>
|
||||
<span>⚠️</span>
|
||||
</div>
|
||||
<Button class="bg-support w-fit" href="https://ko-fi.com/gpxstudio">
|
||||
{$_('menu.support_button')}
|
||||
<span class="ml-2">🙏</span>
|
||||
</Button>
|
||||
</div>
|
||||
<div class="flex flex-row gap-2 justify-center">
|
||||
<Button
|
||||
variant="outline"
|
||||
on:click={() => {
|
||||
if ($exportState === ExportState.SELECTION) {
|
||||
exportSelectedFiles();
|
||||
} else if ($exportState === ExportState.ALL) {
|
||||
exportAllFiles();
|
||||
}
|
||||
open = false;
|
||||
$exportState = ExportState.NONE;
|
||||
}}
|
||||
>
|
||||
<Download size="16" class="mr-1" />
|
||||
{#if $fileObservers.size === 1 || ($exportState === ExportState.SELECTION && $selection.size === 1)}
|
||||
{$_('menu.download_file')}
|
||||
{:else}
|
||||
{$_('menu.download_files')}
|
||||
{/if}
|
||||
</Button>
|
||||
<Button variant="outline">
|
||||
<Cloud size="16" class="mr-1" />
|
||||
{$_('menu.save_drive')}
|
||||
</Button>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</Dialog.Portal>
|
||||
</Dialog.Root>
|
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import * as Menubar from '$lib/components/ui/menubar/index.js';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import Logo from './Logo.svelte';
|
||||
import Shortcut from './Shortcut.svelte';
|
||||
import Logo from '$lib/components/Logo.svelte';
|
||||
import Shortcut from '$lib/components/Shortcut.svelte';
|
||||
import {
|
||||
Plus,
|
||||
Copy,
|
||||
@@ -44,8 +44,6 @@
|
||||
|
||||
import {
|
||||
map,
|
||||
exportAllFiles,
|
||||
exportSelectedFiles,
|
||||
triggerFileInput,
|
||||
createFile,
|
||||
loadFiles,
|
||||
@@ -55,7 +53,9 @@
|
||||
hideSelection,
|
||||
anyHidden,
|
||||
editMetadata,
|
||||
editStyle
|
||||
editStyle,
|
||||
exportState,
|
||||
ExportState
|
||||
} from '$lib/stores';
|
||||
import {
|
||||
copied,
|
||||
@@ -70,6 +70,8 @@
|
||||
import { anySelectedLayer } from '$lib/components/layer-control/utils';
|
||||
import { defaultOverlays } from '$lib/assets/layers';
|
||||
import LayerControlSettings from '$lib/components/layer-control/LayerControlSettings.svelte';
|
||||
import { allowedPastes, ListFileItem, ListTrackItem } from '$lib/components/file-list/FileList';
|
||||
import Export from '$lib/components/Export.svelte';
|
||||
|
||||
import { resetMode, setMode, systemPrefersMode } from 'mode-watcher';
|
||||
|
||||
@@ -77,7 +79,6 @@
|
||||
import { languages } from '$lib/languages';
|
||||
import { goto } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { allowedPastes, ListFileItem, ListTrackItem } from './file-list/FileList';
|
||||
|
||||
const {
|
||||
distanceUnits,
|
||||
@@ -164,12 +165,18 @@
|
||||
<Shortcut key="D" ctrl={true} />
|
||||
</Menubar.Item>
|
||||
<Menubar.Separator />
|
||||
<Menubar.Item on:click={exportSelectedFiles} disabled={$selection.size == 0}>
|
||||
<Menubar.Item
|
||||
on:click={() => ($exportState = ExportState.SELECTION)}
|
||||
disabled={$selection.size == 0}
|
||||
>
|
||||
<Download size="16" class="mr-1" />
|
||||
{$_('menu.export')}
|
||||
<Shortcut key="S" ctrl={true} />
|
||||
</Menubar.Item>
|
||||
<Menubar.Item on:click={exportAllFiles} disabled={$fileObservers.size == 0}>
|
||||
<Menubar.Item
|
||||
on:click={() => ($exportState = ExportState.ALL)}
|
||||
disabled={$fileObservers.size == 0}
|
||||
>
|
||||
<Download size="16" class="mr-1" />
|
||||
{$_('menu.export_all')}
|
||||
<Shortcut key="S" ctrl={true} shift={true} />
|
||||
@@ -452,6 +459,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Export />
|
||||
<LayerControlSettings bind:open={layerSettingsOpen} />
|
||||
|
||||
<svelte:window
|
||||
@@ -478,9 +486,11 @@
|
||||
}
|
||||
} else if ((e.key === 's' || e.key == 'S') && (e.metaKey || e.ctrlKey)) {
|
||||
if (e.shiftKey) {
|
||||
exportAllFiles();
|
||||
} else {
|
||||
exportSelectedFiles();
|
||||
if ($fileObservers.size > 0) {
|
||||
$exportState = ExportState.ALL;
|
||||
}
|
||||
} else if ($selection.size > 0) {
|
||||
$exportState = ExportState.SELECTION;
|
||||
}
|
||||
e.preventDefault();
|
||||
} else if ((e.key === 'z' || e.key == 'Z') && (e.metaKey || e.ctrlKey)) {
|
||||
|
@@ -312,26 +312,26 @@ export function updateSelectionFromKey(down: boolean, shift: boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
export function exportSelectedFiles() {
|
||||
get(selection).forEach(async (item) => {
|
||||
if (item instanceof ListFileItem) {
|
||||
let file = getFile(item.getFileId());
|
||||
if (file) {
|
||||
exportFile(file);
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
}
|
||||
async function exportFiles(fileIds: string[]) {
|
||||
for (let fileId of fileIds) {
|
||||
let file = getFile(fileId);
|
||||
if (file) {
|
||||
exportFile(file);
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function exportSelectedFiles() {
|
||||
let fileIds: string[] = [];
|
||||
applyToOrderedSelectedItemsFromFile(async (fileId, level, items) => {
|
||||
fileIds.push(fileId);
|
||||
});
|
||||
exportFiles(fileIds);
|
||||
}
|
||||
|
||||
export function exportAllFiles() {
|
||||
get(fileObservers).forEach(async (file) => {
|
||||
let f = get(file);
|
||||
if (f) {
|
||||
exportFile(f.file);
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
}
|
||||
});
|
||||
exportFiles(get(fileOrder));
|
||||
}
|
||||
|
||||
export function exportFile(file: GPXFile) {
|
||||
@@ -398,6 +398,13 @@ export function showSelection() {
|
||||
export const editMetadata = writable(false);
|
||||
export const editStyle = writable(false);
|
||||
|
||||
export enum ExportState {
|
||||
NONE,
|
||||
SELECTION,
|
||||
ALL
|
||||
}
|
||||
export const exportState = writable<ExportState>(ExportState.NONE);
|
||||
|
||||
let stravaCookies: any = null;
|
||||
function refreshStravaCookies() {
|
||||
/*
|
||||
|
@@ -17,6 +17,11 @@
|
||||
"cut": "Cut",
|
||||
"export": "Export...",
|
||||
"export_all": "Export all...",
|
||||
"support_message": "The tool is free to use, but not free to run. Please consider supporting the website if you use it frequently.",
|
||||
"support_button": "Help keep the website free",
|
||||
"download_file": "Download file",
|
||||
"download_files": "Download files",
|
||||
"save_drive": "Save to Google Drive",
|
||||
"edit": "Edit",
|
||||
"undo": "Undo",
|
||||
"redo": "Redo",
|
||||
|
Reference in New Issue
Block a user