mirror of
				https://github.com/gpxstudio/gpx.studio.git
				synced 2025-11-04 05:21:09 +00:00 
			
		
		
		
	collapsible state memory in layer control
This commit is contained in:
		@@ -372,31 +372,39 @@ export const opacities: { [key: string]: number; } = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type LayerTreeType = string[] | { [key: string]: LayerTreeType; };
 | 
			
		||||
export type CollapsedInfoTreeType = {
 | 
			
		||||
    self: boolean;
 | 
			
		||||
    children: { [key: string]: CollapsedInfoTreeType; };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const basemapTree: LayerTreeType = {
 | 
			
		||||
    world: ['mapboxOutdoors', 'mapboxSatellite', 'openStreetMap', 'openTopoMap', 'openHikingMap', 'cyclOSM'],
 | 
			
		||||
    countries: {
 | 
			
		||||
        bulgaria: ['bgMountains'],
 | 
			
		||||
        finland: ['finlandTopo'],
 | 
			
		||||
        france: ['ignPlanV2', 'ignFrScan25', 'ignSatellite'],
 | 
			
		||||
        newZealand: ['linz', 'linzTopo'],
 | 
			
		||||
        norway: ['norwayTopo'],
 | 
			
		||||
        spain: ['ignEs'],
 | 
			
		||||
        sweden: ['swedenTopo'],
 | 
			
		||||
        switzerland: ['swisstopo'],
 | 
			
		||||
        unitedKingdom: ['ordnanceSurvey'],
 | 
			
		||||
        unitedStates: ['usgs'],
 | 
			
		||||
    basemaps: {
 | 
			
		||||
        world: ['mapboxOutdoors', 'mapboxSatellite', 'openStreetMap', 'openTopoMap', 'openHikingMap', 'cyclOSM'],
 | 
			
		||||
        countries: {
 | 
			
		||||
            bulgaria: ['bgMountains'],
 | 
			
		||||
            finland: ['finlandTopo'],
 | 
			
		||||
            france: ['ignPlanV2', 'ignFrScan25', 'ignSatellite'],
 | 
			
		||||
            newZealand: ['linz', 'linzTopo'],
 | 
			
		||||
            norway: ['norwayTopo'],
 | 
			
		||||
            spain: ['ignEs'],
 | 
			
		||||
            sweden: ['swedenTopo'],
 | 
			
		||||
            switzerland: ['swisstopo'],
 | 
			
		||||
            unitedKingdom: ['ordnanceSurvey'],
 | 
			
		||||
            unitedStates: ['usgs'],
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const overlayTree: LayerTreeType = {
 | 
			
		||||
    world: {
 | 
			
		||||
        cyclOSM: ['cyclOSMlite'],
 | 
			
		||||
        waymarkedTrails: ['waymarkedTrailsHiking', 'waymarkedTrailsCycling', 'waymarkedTrailsMTB', 'waymarkedTrailsSkating', 'waymarkedTrailsHorseRiding', 'waymarkedTrailsWinter']
 | 
			
		||||
    },
 | 
			
		||||
    countries: {
 | 
			
		||||
        france: ['ignFrCadastre', 'ignSlope'],
 | 
			
		||||
        switzerland: ['swisstopoSlope', 'swisstopoCycling', 'swisstopoMountainBike'],
 | 
			
		||||
    overlays: {
 | 
			
		||||
        world: {
 | 
			
		||||
            cyclOSM: ['cyclOSMlite'],
 | 
			
		||||
            waymarkedTrails: ['waymarkedTrailsHiking', 'waymarkedTrailsCycling', 'waymarkedTrailsMTB', 'waymarkedTrailsSkating', 'waymarkedTrailsHorseRiding', 'waymarkedTrailsWinter']
 | 
			
		||||
        },
 | 
			
		||||
        countries: {
 | 
			
		||||
            france: ['ignFrCadastre', 'ignSlope'],
 | 
			
		||||
            switzerland: ['swisstopoSlope', 'swisstopoCycling', 'swisstopoMountainBike'],
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,6 @@
 | 
			
		||||
					<div class="p-2">
 | 
			
		||||
						<LayerTree
 | 
			
		||||
							layerTree={basemapTree}
 | 
			
		||||
							label="Basemaps"
 | 
			
		||||
							name="basemaps"
 | 
			
		||||
							onValueChange={(id) => {
 | 
			
		||||
								if (map) {
 | 
			
		||||
@@ -54,7 +53,6 @@
 | 
			
		||||
					<div class="p-2">
 | 
			
		||||
						<LayerTree
 | 
			
		||||
							layerTree={overlayTree}
 | 
			
		||||
							label="Overlays"
 | 
			
		||||
							name="overlays"
 | 
			
		||||
							multiple={true}
 | 
			
		||||
							onValueChange={(id, checked) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,6 @@
 | 
			
		||||
						<ScrollArea class="py-2 pr-2">
 | 
			
		||||
							<LayerTree
 | 
			
		||||
								layerTree={basemapTree}
 | 
			
		||||
								label="Basemaps"
 | 
			
		||||
								name="basemapSettings"
 | 
			
		||||
								multiple={true}
 | 
			
		||||
								onValueChange={(id) => {
 | 
			
		||||
@@ -52,7 +51,6 @@
 | 
			
		||||
						<ScrollArea class="py-2 pr-2">
 | 
			
		||||
							<LayerTree
 | 
			
		||||
								layerTree={overlayTree}
 | 
			
		||||
								label="Overlays"
 | 
			
		||||
								name="overlaySettings"
 | 
			
		||||
								multiple={true}
 | 
			
		||||
								onValueChange={(id, checked) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,39 +1,19 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
	import LayerTreeNode from './LayerTreeNode.svelte';
 | 
			
		||||
	import { type LayerTreeType } from '$lib/assets/layers';
 | 
			
		||||
 | 
			
		||||
	import * as Collapsible from '$lib/components/ui/collapsible';
 | 
			
		||||
	import { Button } from '$lib/components/ui/button';
 | 
			
		||||
 | 
			
		||||
	import { ChevronDown, ChevronUp } from 'lucide-svelte';
 | 
			
		||||
	import { type CollapsedInfoTreeType, type LayerTreeType } from '$lib/assets/layers';
 | 
			
		||||
 | 
			
		||||
	export let layerTree: LayerTreeType;
 | 
			
		||||
	export let label: string;
 | 
			
		||||
	export let name: string;
 | 
			
		||||
	export let multiple: boolean = false;
 | 
			
		||||
 | 
			
		||||
	export let onValueChange: (id: string, checked: boolean) => void;
 | 
			
		||||
 | 
			
		||||
	let open = true;
 | 
			
		||||
	let open: CollapsedInfoTreeType = {
 | 
			
		||||
		self: true,
 | 
			
		||||
		children: {}
 | 
			
		||||
	};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<fieldset class="min-w-64">
 | 
			
		||||
	<Collapsible.Root bind:open>
 | 
			
		||||
		<Collapsible.Trigger class="w-full"
 | 
			
		||||
			><Button
 | 
			
		||||
				variant="ghost"
 | 
			
		||||
				class="w-full flex flex-row justify-between py-0 px-1 h-fit hover:bg-background"
 | 
			
		||||
			>
 | 
			
		||||
				<span class="mr-2">{label}</span>
 | 
			
		||||
				{#if open}
 | 
			
		||||
					<ChevronDown size="16" />
 | 
			
		||||
				{:else}
 | 
			
		||||
					<ChevronUp size="16" />
 | 
			
		||||
				{/if}
 | 
			
		||||
			</Button></Collapsible.Trigger
 | 
			
		||||
		>
 | 
			
		||||
		<Collapsible.Content>
 | 
			
		||||
			<LayerTreeNode {name} node={layerTree} {multiple} {onValueChange} />
 | 
			
		||||
		</Collapsible.Content>
 | 
			
		||||
	</Collapsible.Root>
 | 
			
		||||
	<LayerTreeNode {name} node={layerTree} {multiple} {onValueChange} bind:open />
 | 
			
		||||
</fieldset>
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
 | 
			
		||||
	import { ChevronDown, ChevronUp } from 'lucide-svelte';
 | 
			
		||||
 | 
			
		||||
	import { type LayerTreeType } from '$lib/assets/layers';
 | 
			
		||||
	import { type CollapsedInfoTreeType, type LayerTreeType } from '$lib/assets/layers';
 | 
			
		||||
 | 
			
		||||
	export let name: string;
 | 
			
		||||
	export let node: LayerTreeType;
 | 
			
		||||
@@ -21,10 +21,15 @@
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let open: { [key: string]: boolean } = {};
 | 
			
		||||
	export let open: CollapsedInfoTreeType;
 | 
			
		||||
	if (!Array.isArray(node)) {
 | 
			
		||||
		Object.keys(node).forEach((id) => {
 | 
			
		||||
			open[id] = true;
 | 
			
		||||
			if (!open.children.hasOwnProperty(id)) {
 | 
			
		||||
				open.children[id] = {
 | 
			
		||||
					self: true,
 | 
			
		||||
					children: {}
 | 
			
		||||
				};
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
</script>
 | 
			
		||||
@@ -62,14 +67,14 @@
 | 
			
		||||
{:else}
 | 
			
		||||
	<div class="flex flex-col gap-1">
 | 
			
		||||
		{#each Object.keys(node) as id}
 | 
			
		||||
			<Collapsible.Root bind:open={open[id]} class="ml-1">
 | 
			
		||||
			<Collapsible.Root bind:open={open.children[id].self} class="ml-1">
 | 
			
		||||
				<Collapsible.Trigger class="w-full"
 | 
			
		||||
					><Button
 | 
			
		||||
						variant="ghost"
 | 
			
		||||
						class="w-full flex flex-row justify-between py-0 px-1 h-fit hover:bg-background"
 | 
			
		||||
					>
 | 
			
		||||
						<span class="mr-2">{id}</span>
 | 
			
		||||
						{#if open[id]}
 | 
			
		||||
						{#if open.children[id].self}
 | 
			
		||||
							<ChevronUp size="16" />
 | 
			
		||||
						{:else}
 | 
			
		||||
							<ChevronDown size="16" />
 | 
			
		||||
@@ -77,7 +82,13 @@
 | 
			
		||||
					</Button></Collapsible.Trigger
 | 
			
		||||
				>
 | 
			
		||||
				<Collapsible.Content class="ml-1">
 | 
			
		||||
					<svelte:self node={node[id]} {name} {multiple} {onValueChange} />
 | 
			
		||||
					<svelte:self
 | 
			
		||||
						node={node[id]}
 | 
			
		||||
						{name}
 | 
			
		||||
						{multiple}
 | 
			
		||||
						{onValueChange}
 | 
			
		||||
						bind:open={open.children[id]}
 | 
			
		||||
					/>
 | 
			
		||||
				</Collapsible.Content>
 | 
			
		||||
			</Collapsible.Root>
 | 
			
		||||
		{/each}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user