Source Legend
Source Legend
Cette page est générée automatiquement à partir du dépôt local au moment de la génération de la documentation.
Fichiers inclus
packages/common/src/lib/widgets/legend/legend.declaration.tspackages/common/src/lib/widgets/legend/legend.config.tspackages/common/src/lib/widgets/legend/legend-data-selector/LegendDataSelector.sveltepackages/common/src/lib/widgets/legend/legend-data-selector/LegendLayerHierarchy.sveltepackages/common/src/lib/widgets/legend/legend-list/LegendItemDisplay.sveltepackages/common/src/lib/widgets/legend/legend-list/LegendServiceDisplay.sveltepackages/common/src/lib/widgets/legend/legend-list/LegendServiceList.sveltepackages/common/src/lib/widgets/legend/Legend.sveltepackages/common/src/lib/widgets/legend/models/legend-data.svelte.ts
packages/common/src/lib/widgets/legend/legend.declaration.ts
import { widgetFactorySvelte, type WidgetProps } from '$lib/api/managers/widget';import { type LegendConfig, legendConfigSchema } from '$lib/widgets/legend/legend.config';import type { WidgetDeclaration } from '$lib/api/managers/widget/widget-declaration';
export const declaration = { factory: () => import('./Legend.svelte').then((Legend) => widgetFactorySvelte(Legend)), schema: () => legendConfigSchema,} satisfies WidgetDeclaration;
export type LegendProps = WidgetProps<LegendConfig>;packages/common/src/lib/widgets/legend/legend.config.ts
import { i18nSchemaFrom } from '$lib/api/managers/i18n';import { inToolbarSchemaFrom } from '$lib/api/managers/configuration/models/widget/widget-in-toolbar.schema';import type { z } from 'zod';import { defineWidgetConfig } from '$lib/api/managers/configuration';
export const legendI18n = i18nSchemaFrom({ dataToShow: { fr: 'Données à afficher', nl: 'NL - Données à afficher', }, legend: { fr: 'Légende', nl: 'NL - Légende', }, noData: { fr: 'Pas de données à afficher', nl: 'NL - Pas de données à afficher', }, selectUnselectAll: { fr: 'Tout cocher / décocher', nl: 'NL - Tout cocher / décocher', },});
export const legendConfigSchema = defineWidgetConfig({ title: { fr: 'Légende', nl: 'NL - Légende', }, icon: { lucide: 'Image', }, i18n: legendI18n, inToolbar: inToolbarSchemaFrom({ type: 'button', }),});
export type LegendConfig = z.infer<typeof legendConfigSchema>;packages/common/src/lib/widgets/legend/legend-data-selector/LegendDataSelector.svelte
<script lang="ts"> import type { LegendConfig } from '$lib/widgets/legend/legend.config'; import * as Collapsible from '$lib/components/shadcn/ui/collapsible'; import { getI18n } from '$lib/api/managers/i18n'; import LegendLayerHierarchy from '$lib/widgets/legend/legend-data-selector/LegendLayerHierarchy.svelte'; import { getLegendData } from '$lib/widgets/legend/models/legend-data.svelte'; import { Checkbox } from '$lib/components/shadcn/ui/checkbox';
type Props = { fullConfig: LegendConfig; }; let { fullConfig }: Props = $props();
const legendData = getLegendData();
const i18n = getI18n(fullConfig.i18n); const open = $state<boolean>(true);</script>
<Collapsible.Root {open} class="gv-border-solid gv-border-2 gv-border-primary"> <Collapsible.Trigger class="gv-w-full gv-p-1 gv-bg-primary/60"> <div class="gv-flex gv-justify-items-start gv-text-lg"> {i18n('dataToShow')} </div> </Collapsible.Trigger> <Collapsible.Content> <div class="space-y-4 gv-p-2"> <div class="gv-mb-2 gv-flex gv-items-center"> <Checkbox checked={legendData.allSelected} onCheckedChange={(checked) => legendData.selectUnselectAll(checked)} /> <div class="gv-ml-1">{i18n('selectUnselectAll')}</div> </div> {#each legendData.nodes as node (node.id)} {#if node.mapServiceInstance.visible} <div class="gv-mb-2"> <LegendLayerHierarchy {node} /> </div> {/if} {/each} {#if legendData.dataSelectorDisplayIsEmpty()} {i18n('noData')} {/if} </div> </Collapsible.Content></Collapsible.Root>packages/common/src/lib/widgets/legend/legend-data-selector/LegendLayerHierarchy.svelte
<script lang="ts"> import SvelteSelf from './LegendLayerHierarchy.svelte'; import * as Collapsible from '$lib/components/shadcn/ui/collapsible'; import { Checkbox } from '$lib/components/shadcn/ui/checkbox'; import { Label } from '$lib/components/shadcn/ui/label'; import { isMapService } from '$lib/api/utils/service.utils'; import Minus from 'lucide-svelte/icons/minus'; import Plus from 'lucide-svelte/icons/plus'; import { cn } from '$lib/components/shadcn/utils'; import { Button } from '$lib/components/shadcn/ui/button'; import type { LegendNode } from '$lib/api/utils/legend/legend.model.svelte';
type Props = { node: LegendNode; }; let { node }: Props = $props();
let open = $state<boolean>(true);
function onNodeSelectionChange(checked: boolean): void { node.updateSelectionTree(checked); }</script>
<div> <Collapsible.Root {open}> <Collapsible.Trigger asChild let:builder class="gv-w-full"> <div class="gv-flex gv-space-x-2"> {#if isMapService(node.mapServiceInstance)} <Button class={cn('gv-p-0 gv-h-4 gv-bg-transparent hover:gv-bg-transparent')} builders={[builder]} onclick={() => (open = !open)} > {#if open} <Minus class="gv-text-primary" /> {:else} <Plus class="gv-text-primary" /> {/if} </Button> {/if} {#if node} <Checkbox checked={node.selected} onCheckedChange={(checked) => onNodeSelectionChange(checked === 'indeterminate' ? false : checked)} /> {/if} <Label>{node.mapServiceInstance.label}</Label> </div> </Collapsible.Trigger> <Collapsible.Content> {#if node.children} <div class={cn( 'gv-flex gv-flex-col gv-gap-2 gv-mt-2', isMapService(node.mapServiceInstance) ? 'gv-ml-[50px]' : 'gv-ml-[18px]', )} > {#each node.children as child} <SvelteSelf node={child} /> {/each} </div> {/if} </Collapsible.Content> </Collapsible.Root></div>packages/common/src/lib/widgets/legend/legend-list/LegendItemDisplay.svelte
<script lang="ts"> import type { ApiLegendItem } from '$lib/api/utils/legend/legend.model.svelte'; import { cn } from '$lib/components/shadcn/utils'; import { Loader } from '$lib/components/common';
type Props = { legendItems: ApiLegendItem[]; class?: string; }; let { legendItems, class: className }: Props = $props();
let imageLoading = $state<boolean>(true);</script>
<div class={cn('gv-flex gv-flex-col gv-gap-2', className)}> {#each legendItems as legendItem} <div class="gv-flex gv-items-center gv-gap-2"> <img onload={() => (imageLoading = false)} src={legendItem.url ?? legendItem.base64String} alt="Legend symbology" /> {#if imageLoading} <Loader /> {/if} <span>{legendItem.label}</span> </div> {/each}</div>packages/common/src/lib/widgets/legend/legend-list/LegendServiceDisplay.svelte
<script lang="ts"> import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '$lib/components/shadcn/ui/collapsible'; import Error from '$lib/components/common/Error.svelte'; import Loader from '$lib/components/common/Loader.svelte'; import { Button } from '$lib/components/shadcn/ui/button'; import { Label } from '$lib/components/shadcn/ui/label'; import { cn } from '$lib/components/shadcn/utils'; import LegendServiceDisplay from '$lib/widgets/legend/legend-list/LegendServiceDisplay.svelte'; import Minus from 'lucide-svelte/icons/minus'; import Plus from 'lucide-svelte/icons/plus'; import LegendItemDisplay from '$lib/widgets/legend/legend-list/LegendItemDisplay.svelte'; import type { LegendNode } from '$lib/api/utils/legend/legend.model.svelte'; import { isSublayer } from '$lib/api/layers';
type Props = { node: LegendNode; }; let { node }: Props = $props(); let open = $state<boolean>(true);</script>
<Collapsible {open}> <CollapsibleTrigger asChild let:builder class="gv-w-full"> <div class="gv-flex gv-space-x-2"> <Button class={cn('gv-p-0 gv-h-4 gv-bg-transparent hover:gv-bg-transparent')} builders={[builder]} onclick={() => (open = !open)} > {#if open} <Minus class="gv-text-primary" /> {:else} <Plus class="gv-text-primary" /> {/if} </Button> <Label>{node.mapServiceInstance.label}</Label> </div> </CollapsibleTrigger> <CollapsibleContent> {#if node.children && node.children.length > 0} <div class={cn('gv-flex gv-flex-col gv-gap-2 gv-mt-2 gv-ml-[18px]')}> {#each node.children as child} {#if child.selected && isSublayer(child.mapServiceInstance)} <LegendServiceDisplay node={child} /> {/if} {/each} </div> {:else if node.legendCacheItem} {#if node.legendCacheItem.loading} <Loader /> {:else if node.legendCacheItem.error} <Error message={node.legendCacheItem.error.message} /> {:else if node.legendItemsData} <div class="gv-ml-10 gv-mt-2"> <LegendItemDisplay legendItems={node.legendItemsData}></LegendItemDisplay> </div> {/if} {/if} </CollapsibleContent></Collapsible>packages/common/src/lib/widgets/legend/legend-list/LegendServiceList.svelte
<script lang="ts"> import type { LegendConfig } from '$lib/widgets/legend/legend.config'; import * as Collapsible from '$lib/components/shadcn/ui/collapsible'; import { getI18n } from '$lib/api/managers/i18n'; import LegendServiceDisplay from '$lib/widgets/legend/legend-list/LegendServiceDisplay.svelte'; import { getLegendData } from '$lib/widgets/legend/models/legend-data.svelte';
type Props = { fullConfig: LegendConfig; }; let { fullConfig }: Props = $props();
const i18n = getI18n(fullConfig.i18n); const open = $state<boolean>(true); const legendData = getLegendData();</script>
<Collapsible.Root {open} class="gv-border-solid gv-border-2 gv-border-primary"> <Collapsible.Trigger class="gv-w-full gv-p-1 gv-bg-primary/60"> <div class="gv-flex gv-justify-items-start gv-text-lg"> {i18n('legend')} </div> </Collapsible.Trigger> <Collapsible.Content> <div class="space-y-4 gv-p-2"> {#each legendData.nodes as node} {#if node.selected && node.mapServiceInstance.visible} <div class="gv-mb-2"> <LegendServiceDisplay {node} /> </div> {/if} {/each} {#if legendData.legendDisplayIsEmpty()} {i18n('noData')} {/if} </div> </Collapsible.Content></Collapsible.Root>packages/common/src/lib/widgets/legend/Legend.svelte
<script lang="ts"> import { getMapManager } from '$lib/api/map'; import LegendDataSelector from './legend-data-selector/LegendDataSelector.svelte'; import LegendServiceList from './legend-list/LegendServiceList.svelte'; import { LegendData, setLegendContext } from './models/legend-data.svelte'; import type { LegendProps } from './legend.declaration';
let { fullConfig }: LegendProps = $props();
const mapManager = getMapManager(); setLegendContext(new LegendData(mapManager.layerList));</script>
<LegendDataSelector {fullConfig}></LegendDataSelector><LegendServiceList {fullConfig}></LegendServiceList>packages/common/src/lib/widgets/legend/models/legend-data.svelte.ts
import { getContext, setContext } from 'svelte';import type { ApiMapService, ApiMapServiceList } from '$lib/api/mapservices';import { reverse } from '$lib/api/utils';import { LegendNode } from '$lib/api/utils/legend/legend.model.svelte';
export class LegendData { public readonly nodes = $derived.by(() => { return reverse(this.layerList.list) .filter((x) => x.toc.visible) .map((service) => new LegendNode(service)); });
get allSelected(): boolean { if (this.nodes.every((x) => x.selected)) { return true; } if (this.nodes.filter((x) => x.mapServiceInstance?.visible).every((x) => !x.selected)) { return false; } return false; }
selectUnselectAll(value: boolean): void { this.nodes.forEach((node) => node.updateSelectionTree(value)); }
constructor(private readonly layerList: ApiMapServiceList) {}
legendDisplayIsEmpty(): boolean { return !this.nodes || !this.nodes.some((x) => x.selected && x.mapServiceInstance?.visible); }
dataSelectorDisplayIsEmpty(): boolean { return !this.nodes || this.nodes.filter((x) => x.mapServiceInstance?.visible).length === 0; }}
const LEGEND_CONTEXT_KEY = 'LEGEND_CONTEXT_KEY';
export function setLegendContext(legendData: LegendData) { setContext(LEGEND_CONTEXT_KEY, legendData); return getLegendData();}
export function getLegendData(): LegendData { const legendData = getContext<LegendData>(LEGEND_CONTEXT_KEY); if (!legendData) { throw new Error('Legend not found in context.'); } return legendData;}
export function isMapServiceWithUrl(mapService: unknown): mapService is MapServiceWithUrl { return !!mapService && typeof mapService === 'object' && 'url' in mapService;}
export type MapServiceWithUrl = ApiMapService & { url: string };