2024-04-12 13:43:51 +02:00
|
|
|
<script lang="ts">
|
2025-06-21 21:07:36 +02:00
|
|
|
import Self from '$lib/components/map/layer-control/LayerTreeNode.svelte';
|
2025-02-02 11:17:22 +01:00
|
|
|
import { Label } from '$lib/components/ui/label';
|
|
|
|
|
import { Checkbox } from '$lib/components/ui/checkbox';
|
2025-06-21 21:07:36 +02:00
|
|
|
import CollapsibleTreeNode from '$lib/components/collapsible-tree/CollapsibleTreeNode.svelte';
|
2025-02-02 11:17:22 +01:00
|
|
|
import { type LayerTreeType } from '$lib/assets/layers';
|
2025-10-17 23:54:45 +02:00
|
|
|
import { anySelectedLayer } from './utils';
|
2025-06-21 21:07:36 +02:00
|
|
|
import { i18n } from '$lib/i18n.svelte';
|
2025-10-17 23:54:45 +02:00
|
|
|
import { settings } from '$lib/logic/settings';
|
2025-11-11 12:11:38 +01:00
|
|
|
import { extensionAPI } from '$lib/components/map/layer-control/extension-api';
|
2024-04-24 17:39:56 +02:00
|
|
|
|
2025-06-21 21:07:36 +02:00
|
|
|
let {
|
|
|
|
|
name,
|
|
|
|
|
node,
|
|
|
|
|
selected = '',
|
|
|
|
|
onselect = () => {},
|
|
|
|
|
multiple = false,
|
|
|
|
|
checked = $bindable({}),
|
|
|
|
|
}: {
|
|
|
|
|
name: string;
|
|
|
|
|
node: LayerTreeType;
|
|
|
|
|
selected?: string;
|
|
|
|
|
onselect?: (value: string) => void;
|
|
|
|
|
multiple: boolean;
|
|
|
|
|
checked: LayerTreeType;
|
|
|
|
|
} = $props();
|
2024-05-06 15:52:11 +02:00
|
|
|
|
2025-02-02 11:17:22 +01:00
|
|
|
const { customLayers } = settings;
|
2025-11-12 12:47:26 +01:00
|
|
|
const { isLayerFromExtension, getLayerName } = extensionAPI;
|
2024-06-26 17:19:41 +02:00
|
|
|
|
2025-06-21 21:07:36 +02:00
|
|
|
$effect.pre(() => {
|
2025-02-02 11:17:22 +01:00
|
|
|
if (checked !== undefined) {
|
|
|
|
|
Object.keys(node).forEach((id) => {
|
|
|
|
|
if (!checked.hasOwnProperty(id)) {
|
|
|
|
|
if (typeof node[id] == 'boolean') {
|
|
|
|
|
checked[id] = false;
|
|
|
|
|
} else {
|
|
|
|
|
checked[id] = {};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2024-04-12 13:43:51 +02:00
|
|
|
</script>
|
|
|
|
|
|
2024-05-23 11:21:57 +02:00
|
|
|
<div class="flex flex-col gap-[3px]">
|
2025-02-02 11:17:22 +01:00
|
|
|
{#each Object.keys(node) as id}
|
|
|
|
|
{#if typeof node[id] == 'boolean'}
|
|
|
|
|
{#if node[id]}
|
|
|
|
|
<div class="flex flex-row items-center gap-2 first:mt-0.5 h-4">
|
|
|
|
|
{#if multiple}
|
|
|
|
|
<Checkbox
|
|
|
|
|
id="{name}-{id}"
|
|
|
|
|
{name}
|
|
|
|
|
value={id}
|
|
|
|
|
bind:checked={checked[id]}
|
|
|
|
|
class="scale-90"
|
2025-06-21 21:07:36 +02:00
|
|
|
aria-label={i18n._(`layers.label.${id}`)}
|
2025-02-02 11:17:22 +01:00
|
|
|
/>
|
|
|
|
|
{:else}
|
|
|
|
|
<input
|
|
|
|
|
id="{name}-{id}"
|
|
|
|
|
type="radio"
|
|
|
|
|
{name}
|
|
|
|
|
value={id}
|
2025-06-21 21:07:36 +02:00
|
|
|
checked={selected === id}
|
|
|
|
|
oninput={(e) => {
|
|
|
|
|
if ((e.target as HTMLInputElement)?.checked) {
|
|
|
|
|
onselect(id);
|
|
|
|
|
}
|
|
|
|
|
}}
|
2025-02-02 11:17:22 +01:00
|
|
|
/>
|
|
|
|
|
{/if}
|
|
|
|
|
<Label for="{name}-{id}" class="flex flex-row items-center gap-1">
|
2025-10-17 23:54:45 +02:00
|
|
|
{#if $customLayers.hasOwnProperty(id)}
|
|
|
|
|
{$customLayers[id].name}
|
2025-11-12 12:47:26 +01:00
|
|
|
{:else if $isLayerFromExtension(id)}
|
|
|
|
|
{$getLayerName(id)}
|
2025-02-02 11:17:22 +01:00
|
|
|
{:else}
|
2025-06-21 21:07:36 +02:00
|
|
|
{i18n._(`layers.label.${id}`)}
|
2025-02-02 11:17:22 +01:00
|
|
|
{/if}
|
|
|
|
|
</Label>
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
{:else if anySelectedLayer(node[id])}
|
|
|
|
|
<CollapsibleTreeNode {id}>
|
2025-06-21 21:07:36 +02:00
|
|
|
{#snippet trigger()}
|
2025-11-25 19:18:54 +01:00
|
|
|
<span>{i18n._(`layers.label.${id}`, id)}</span>
|
2025-06-21 21:07:36 +02:00
|
|
|
{/snippet}
|
|
|
|
|
{#snippet content()}
|
|
|
|
|
<div class="ml-2">
|
|
|
|
|
<Self
|
|
|
|
|
node={node[id]}
|
|
|
|
|
{name}
|
|
|
|
|
{selected}
|
|
|
|
|
{onselect}
|
|
|
|
|
{multiple}
|
|
|
|
|
bind:checked={checked[id]}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
{/snippet}
|
2025-02-02 11:17:22 +01:00
|
|
|
</CollapsibleTreeNode>
|
|
|
|
|
{/if}
|
|
|
|
|
{/each}
|
2024-05-05 18:59:09 +02:00
|
|
|
</div>
|
2024-04-12 15:12:27 +02:00
|
|
|
|
|
|
|
|
<style lang="postcss">
|
2025-06-21 21:07:36 +02:00
|
|
|
@reference "../../../../app.css";
|
|
|
|
|
|
2025-02-02 11:17:22 +01:00
|
|
|
div :global(input[type='radio']) {
|
|
|
|
|
@apply appearance-none;
|
|
|
|
|
@apply w-4 h-4;
|
|
|
|
|
@apply border-[1.5px] border-primary;
|
|
|
|
|
@apply rounded-full;
|
|
|
|
|
@apply ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2;
|
|
|
|
|
@apply cursor-pointer;
|
|
|
|
|
@apply checked:bg-primary;
|
|
|
|
|
@apply checked:bg-clip-content;
|
|
|
|
|
@apply checked:p-0.5;
|
|
|
|
|
}
|
2024-04-12 15:12:27 +02:00
|
|
|
</style>
|