mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-10-17 16:42:28 +00:00
fix popups
This commit is contained in:
1 parent
017d8521d6
commit
543fecadb8
25 files changed
+1242
-225
No files matched your search
@@ -5,15 +5,15 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import * as Select from '$lib/components/ui/select';
|
||||
import { i18n } from '$lib/i18n.svelte';
|
||||
import { ListWaypointItem } from '$lib/components/file-list/file-list';
|
||||
import Help from '$lib/components/Help.svelte';
|
||||
import { onDestroy, onMount, untrack } from 'svelte';
|
||||
import { getURLForLanguage } from '$lib/utils';
|
||||
import { MapPin, CircleX, Save } from '@lucide/svelte';
|
||||
import { getSymbolKey, symbols } from '$lib/assets/symbols';
|
||||
import { selection } from '$lib/logic/selection';
|
||||
import { engine } from '$lib/engine';
|
||||
import { selectionSize } from '$lib/selection-helpers';
|
||||
import { getElevation } from '$lib/utils';
|
||||
import { selectedWaypoint } from './waypoint';
|
||||
import { fileActions } from '$lib/logic/file-actions';
|
||||
import { map } from '$lib/components/map/map';
|
||||
import { mapCursor, MapCursorState } from '$lib/logic/map-cursor';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
@@ -31,7 +31,9 @@
|
||||
let latitude = $state(0);
|
||||
let symbolKey = $derived(getSymbolKey(sym));
|
||||
|
||||
let canCreate = $derived($selection.size > 0);
|
||||
const { selection } = engine;
|
||||
|
||||
let canCreate = $derived(selectionSize($selection) > 0);
|
||||
|
||||
let sortedSymbols = $derived(
|
||||
Object.entries(symbols).sort((a, b) => {
|
||||
@@ -58,24 +60,24 @@
|
||||
|
||||
$effect(() => {
|
||||
if ($selectedWaypoint) {
|
||||
const wpt = $selectedWaypoint[0];
|
||||
const wpt = $selectedWaypoint.waypoint;
|
||||
untrack(() => {
|
||||
name = wpt.name ?? '';
|
||||
description = wpt.desc ?? '';
|
||||
if (wpt.cmt !== undefined && wpt.cmt !== wpt.desc) {
|
||||
description += '\n\n' + wpt.cmt;
|
||||
}
|
||||
link = wpt.link?.attributes?.href ?? '';
|
||||
link = wpt.link?.href ?? '';
|
||||
sym = wpt.sym ?? '';
|
||||
longitude = parseFloat(wpt.getLongitude().toFixed(6));
|
||||
latitude = parseFloat(wpt.getLatitude().toFixed(6));
|
||||
longitude = parseFloat(wpt.lng.toFixed(6));
|
||||
latitude = parseFloat(wpt.lat.toFixed(6));
|
||||
});
|
||||
} else {
|
||||
untrack(reset);
|
||||
}
|
||||
});
|
||||
|
||||
function createOrUpdateWaypoint() {
|
||||
async function createOrUpdateWaypoint() {
|
||||
if (typeof latitude === 'string') {
|
||||
latitude = parseFloat(latitude);
|
||||
}
|
||||
@@ -85,22 +87,25 @@
|
||||
latitude = parseFloat(latitude.toFixed(6));
|
||||
longitude = parseFloat(longitude.toFixed(6));
|
||||
|
||||
fileActions.addOrUpdateWaypoint(
|
||||
{
|
||||
attributes: {
|
||||
lat: latitude,
|
||||
lon: longitude,
|
||||
},
|
||||
name: name.length > 0 ? name : undefined,
|
||||
desc: description.length > 0 ? description : undefined,
|
||||
cmt: description.length > 0 ? description : undefined,
|
||||
link: link.length > 0 ? { attributes: { href: link } } : undefined,
|
||||
sym: sym.length > 0 ? sym : undefined,
|
||||
},
|
||||
selectedWaypoint.wpt && selectedWaypoint.fileId
|
||||
? new ListWaypointItem(selectedWaypoint.fileId, selectedWaypoint.wpt._data.index)
|
||||
: undefined
|
||||
);
|
||||
const target = $selectedWaypoint;
|
||||
const [ele] = await getElevation([{ lat: latitude, lon: longitude }]);
|
||||
const waypoint = {
|
||||
lng: longitude,
|
||||
lat: latitude,
|
||||
ele,
|
||||
name,
|
||||
desc: description,
|
||||
icon: sym,
|
||||
link,
|
||||
};
|
||||
if (target) {
|
||||
// the engine changes the selected waypoint
|
||||
await engine.selectWaypoints(target.fileId, [target.id]);
|
||||
await engine.updateWaypoint(waypoint);
|
||||
} else {
|
||||
// it goes in the selected files
|
||||
await engine.newWaypoint(waypoint);
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
@@ -1,74 +1,107 @@
|
||||
import { ListWaypointItem } from '$lib/components/file-list/file-list';
|
||||
import { fileStateCollection } from '$lib/logic/file-state';
|
||||
import { selection } from '$lib/logic/selection';
|
||||
import { get, writable } from 'svelte/store';
|
||||
import { engine, type WaypointDetails } from '$lib/engine';
|
||||
import { settings } from '$lib/logic/settings';
|
||||
import type { Waypoint } from 'gpx';
|
||||
import { get, writable, type Writable } from 'svelte/store';
|
||||
|
||||
export type SelectedWaypoint = {
|
||||
fileId: string;
|
||||
id: string;
|
||||
/** The data of the waypoint, kept up to date with the file. */
|
||||
waypoint: WaypointDetails;
|
||||
};
|
||||
|
||||
/**
|
||||
* The waypoint that the waypoint tool is about: the selected one when the file tree is shown and
|
||||
* a single waypoint is selected, or the one that was set explicitly (clicking a waypoint of the
|
||||
* map) until the selection changes to something else than its file or itself (that is what
|
||||
* clicking it selects, depending on the view, and the selection may arrive after it is set).
|
||||
*/
|
||||
export class WaypointSelection {
|
||||
private _selection: Writable<[Waypoint, string] | undefined>;
|
||||
private _selection = writable<SelectedWaypoint | undefined>(undefined);
|
||||
private _fileUnsubscribe: (() => void) | undefined;
|
||||
private _explicit: { fileId: string; id: string } | undefined;
|
||||
|
||||
constructor() {
|
||||
this._selection = writable(undefined);
|
||||
settings.treeFileView.subscribe(() => {
|
||||
this.update();
|
||||
});
|
||||
selection.subscribe(() => {
|
||||
this.update();
|
||||
});
|
||||
settings.treeFileView.subscribe(() => this.updateFromSelection());
|
||||
engine.selection.subscribe(() => this.updateFromSelection());
|
||||
}
|
||||
|
||||
subscribe(
|
||||
run: (value: [Waypoint, string] | undefined) => void,
|
||||
invalidate?: (value?: [Waypoint, string] | undefined) => void
|
||||
run: (value: SelectedWaypoint | undefined) => void,
|
||||
invalidate?: (value?: SelectedWaypoint | undefined) => void
|
||||
) {
|
||||
return this._selection.subscribe(run, invalidate);
|
||||
}
|
||||
|
||||
set(value: [Waypoint, string] | undefined) {
|
||||
this._selection.set(value);
|
||||
/** Sets the waypoint, whatever the selection is. */
|
||||
set(target: { fileId: string; id: string } | undefined) {
|
||||
this._explicit = target;
|
||||
this.track(target);
|
||||
}
|
||||
|
||||
update() {
|
||||
if (this._fileUnsubscribe) {
|
||||
this._fileUnsubscribe();
|
||||
this._fileUnsubscribe = undefined;
|
||||
updateFromSelection() {
|
||||
const selection = get(engine.selection);
|
||||
const explicit = this._explicit;
|
||||
if (
|
||||
explicit &&
|
||||
((selection.type === 'file' &&
|
||||
selection.fileIds.length === 1 &&
|
||||
selection.fileIds[0] === explicit.fileId) ||
|
||||
(selection.type === 'waypoint' &&
|
||||
selection.fileId === explicit.fileId &&
|
||||
selection.waypointIds.length === 1 &&
|
||||
selection.waypointIds[0] === explicit.id))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this._explicit = undefined;
|
||||
if (
|
||||
get(settings.treeFileView) &&
|
||||
selection.type === 'waypoint' &&
|
||||
selection.waypointIds.length === 1
|
||||
) {
|
||||
this.track({ fileId: selection.fileId, id: selection.waypointIds[0] });
|
||||
} else {
|
||||
this.track(undefined);
|
||||
}
|
||||
this._selection.update(() => {
|
||||
if (get(settings.treeFileView) && get(selection).size === 1) {
|
||||
let item = get(selection).getSelected()[0];
|
||||
if (item instanceof ListWaypointItem) {
|
||||
let fileState = fileStateCollection.getFileState(item.getFileId());
|
||||
if (fileState) {
|
||||
let first = true;
|
||||
this._fileUnsubscribe = fileState.subscribe(() => {
|
||||
if (first) first = false;
|
||||
else this.update();
|
||||
});
|
||||
let waypoint = fileState.file?.wpt[item.getWaypointIndex()];
|
||||
if (waypoint) {
|
||||
return [waypoint, item.getFileId()];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
reset() {
|
||||
this._selection.set(undefined);
|
||||
this._explicit = undefined;
|
||||
this.track(undefined);
|
||||
}
|
||||
|
||||
get wpt(): Waypoint | undefined {
|
||||
const selection = get(this._selection);
|
||||
return selection ? selection[0] : undefined;
|
||||
get waypoint(): WaypointDetails | undefined {
|
||||
return get(this._selection)?.waypoint;
|
||||
}
|
||||
|
||||
get fileId(): string | undefined {
|
||||
const selection = get(this._selection);
|
||||
return selection ? selection[1] : undefined;
|
||||
return get(this._selection)?.fileId;
|
||||
}
|
||||
|
||||
get id(): string | undefined {
|
||||
return get(this._selection)?.id;
|
||||
}
|
||||
|
||||
private track(target: { fileId: string; id: string } | undefined) {
|
||||
this._fileUnsubscribe?.();
|
||||
this._fileUnsubscribe = undefined;
|
||||
|
||||
if (!target) {
|
||||
this._selection.set(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
// read again each time the file changes
|
||||
const read = () => {
|
||||
const waypoint = engine.waypoint(target.fileId, target.id);
|
||||
this._selection.set(waypoint ? { ...target, waypoint } : undefined);
|
||||
};
|
||||
const file = get(engine.files).get(target.fileId);
|
||||
if (file) {
|
||||
this._fileUnsubscribe = file.subscribe(read);
|
||||
} else {
|
||||
read();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user