Source Toolbar
Source Toolbar
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/toolbar/toolbar.declaration.tspackages/common/src/lib/widgets/toolbar/toolbar.config.tspackages/common/src/lib/widgets/toolbar/toolbar.i18n.tspackages/common/src/lib/widgets/toolbar/Toolbar.sveltepackages/common/src/lib/widgets/toolbar/ToolbarItem.sveltepackages/common/src/lib/widgets/toolbar/ToolbarTooltip.svelte
packages/common/src/lib/widgets/toolbar/toolbar.declaration.ts
import { widgetFactorySvelte, type WidgetProps } from '$lib/api/managers/widget';import { type ToolbarConfig, toolbarConfigSchema } from './toolbar.config';import type { WidgetDeclaration } from '$lib/api/managers/widget/widget-declaration';
export const declaration = { factory: () => import('./Toolbar.svelte').then((Toolbar) => widgetFactorySvelte(Toolbar)), schema: () => toolbarConfigSchema,} satisfies WidgetDeclaration;
export type ToolbarProps = WidgetProps<ToolbarConfig>;packages/common/src/lib/widgets/toolbar/toolbar.config.ts
import { defineWidgetConfig } from '$lib/api/managers/configuration/models/widget/widget-configuration.schema';import { DEFAULT_TOOLBAR_ID, inToolbarSchemaFrom,} from '$lib/api/managers/configuration/models/widget/widget-in-toolbar.schema';import { mapIconSchema } from '$lib/components/icon/map-icon';import { z } from 'zod';import { styleRecordSchema } from '$lib/api/utils/style/style.schema';import { i18nSchemaFrom } from '$lib/api/managers/i18n';import { toolbarI18n } from '$lib/widgets/toolbar/toolbar.i18n';
export const sideEnumSchema = z.enum([ 'top', // 'top-start', // 'top-end', 'bottom', // 'bottom-start', // 'bottom-end', 'left', // 'left-start', // 'left-end', 'right', // 'right-start', // 'right-end',]);export const toolbarConfigSchema = defineWidgetConfig({ active: true, inToolbar: inToolbarSchemaFrom(false), i18n: i18nSchemaFrom(toolbarI18n), config: z .object({ elements: z.array(z.string()).optional(), iconStyle: mapIconSchema.optional(), display: z.enum(['full', 'light']).default('light'), orientation: z.enum(['right', 'left', 'up', 'down']).default('right'), tooltipSide: sideEnumSchema.default('bottom'), toolbarId: z.string().default(DEFAULT_TOOLBAR_ID), style: styleRecordSchema.optional(), }) .prefault({}),});
export type ToolbarConfig = z.infer<typeof toolbarConfigSchema>;export type ToolbarDisplay = ToolbarConfig['config']['display'];export type ToolbarI18n = ToolbarConfig['i18n'];packages/common/src/lib/widgets/toolbar/toolbar.i18n.ts
import type { I18nRegistry } from '$lib/api/managers/i18n';
export const toolbarI18n = {} satisfies I18nRegistry;packages/common/src/lib/widgets/toolbar/Toolbar.svelte
<script lang="ts"> import type { WidgetConfig } from '$lib/api/managers/configuration'; import { getConfigurationManager } from '$lib/api/managers/configuration/configuration.manager.svelte'; import { getWidgetManager } from '$lib/api/managers/widget/widget.manager.svelte'; import type { ContainerConfig, ContainerWidgetConfig } from '$lib/components/containers'; import { ToolbarTabs } from '$lib/components/containers/toolbar-tabs'; import type { ToolbarTabsConfig } from '$lib/components/containers/toolbar-tabs/toolbar-tabs.schema'; import { cn } from '$lib/components/shadcn/utils'; import ToolbarItem from './ToolbarItem.svelte'; import { recordToCssStyle } from '$lib/api/utils/style/style.utils'; import type { ToolbarProps } from './toolbar.declaration';
const { fullConfig }: ToolbarProps = $props();
type ToolbarItem = WidgetConfig | ToolbarTabsConfig;
const config = $derived(fullConfig.config);
const configurationManager = getConfigurationManager(); const widgetManager = getWidgetManager();
const sections = $derived.by(() => { return config.elements && config.elements.length > 0 ? getWidgetsFromIds(config.elements) : getWidgetsFromThereConfigs(); });
function getWidgetsFromThereConfigs(): ToolbarItem[][] { const inToolbar = configurationManager.widgetsConfiguration!.filter( (w) => w.inToolbar && w.inToolbar.toolbarId === config.toolbarId, ) as WidgetConfig[]; const toolbarTabs = configurationManager.viewerConfiguration!.containers.filter( (c) => isToolbarTabConfig(c) && c.toolbarId === config.toolbarId, ) as ToolbarTabsConfig[];
return [ [...inToolbar, ...toolbarTabs].sort((a, b) => { const aOrder = getOrder(a); const bOrder = getOrder(b); return aOrder - bOrder; }), ]; }
function getWidgetsFromIds(ids: string[]) { const sections = [] as ToolbarItem[][]; let current = [] as ToolbarItem[]; sections.push(current);
for (const id of ids) { if (id === '---') { current = []; sections.push(current); continue; }
const item = (configurationManager.viewerConfiguration!.containers.find( (c) => isToolbarTabConfig(c) && c.id === id, ) as ToolbarTabsConfig) ?? configurationManager.getWidgetConfigById(id) ?? configurationManager.getWidgetConfigByClass(id);
if (!item) { console.warn('No widgets found for id', id); continue; }
current.push(item); }
return sections; }
function getOrder(item: ToolbarItem): number { if (isToolbarTabs(item)) { return item.order ?? 0; } else { return item.inToolbar?.order ?? 0; } }
function getKey(item: ToolbarItem): string { if (isToolbarTabs(item)) { return `toolbar-tab-${item.id}`; } else { return item.widgetId; } }
function isToolbarTabs(item: ToolbarItem): item is ToolbarTabsConfig { return 'type' in item && item.type === 'toolbar-tabs'; }
function isToolbarTabConfig( container: ContainerConfig | ContainerWidgetConfig | string, ): container is ToolbarTabsConfig { return !!container && typeof container === 'object' && 'type' in container && container.type === 'toolbar-tabs'; }
async function toggleWidget(widgetId: string) { const reference = widgetManager.getReference(widgetId); reference.toggle({ openContainer: true }); }
const elementsPaddingClass = $derived( cn({ 'not-first:gv-px-2xs': config.orientation === 'left' || config.orientation === 'right', 'not-first:gv-py-2xs': config.orientation === 'up' || config.orientation === 'down', }), );</script>
{#if sections.length > 0} <div class={cn('gv-flex gv-gap-md', { 'gv-flex-row-reverse': config.orientation === 'left', 'gv-flex-row': config.orientation === 'right', 'gv-flex-col-reverse': config.orientation === 'up', 'gv-flex-col': config.orientation === 'down', })} > {#each sections as section} <div class={cn( 'toolbar gv-bg-background gv-flex gv-p-2xs gv-rounded-full gv-overflow-hidden gv-text-primary gv-border-background', { 'gv-flex-row-reverse gv-divide-x gv-divide-x-reverse': config.orientation === 'left', 'gv-flex-row gv-divide-x': config.orientation === 'right', 'gv-flex-col-reverse gv-divide-y gv-divide-y-reverse': config.orientation === 'up', 'gv-flex-col gv-divide-y ': config.orientation === 'down', }, )} style={recordToCssStyle(fullConfig.config.style)} > {#each section as widget (getKey(widget))} {#if isToolbarTabs(widget)} <ToolbarTabs config={widget} class={elementsPaddingClass} /> {:else} <ToolbarItem widgetConfig={widget} i18nConfig={fullConfig.i18n} display={config.display} tooltipSide={config.tooltipSide} onclick={() => toggleWidget(widget.widgetId)} style={recordToCssStyle(widget.inToolbar?.style)} class={elementsPaddingClass} /> {/if} {/each} </div> {/each} </div>{/if}
<style> .toolbar { box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.25); }</style>packages/common/src/lib/widgets/toolbar/ToolbarItem.svelte
<script lang="ts"> import type { WidgetConfig } from '$lib/api/managers/configuration'; import { isActiveIcon } from '$lib/api/managers/configuration/models/widget/widget-in-toolbar.schema'; import { getI18n } from '$lib/api/managers/i18n'; import { getWidgetManager } from '$lib/api/managers/widget'; import { type TooltipSide } from '$lib/components/api-simple-tooltip'; import WidgetContainer from '$lib/components/containers/WidgetContainer.svelte'; import Icon from '$lib/components/icon/Icon.svelte'; import { mapIconButtonVariants, type MapIconSize, type MapIconVariant } from '$lib/components/icon/map-icon'; import { cn } from '$lib/components/shadcn/utils'; import type { ToolbarDisplay, ToolbarI18n } from './toolbar.config'; import type { HTMLAttributes } from 'svelte/elements'; import ToolbarTooltip from '$lib/widgets/toolbar/ToolbarTooltip.svelte';
interface Props extends HTMLAttributes<HTMLButtonElement> { widgetConfig: WidgetConfig; i18nConfig: ToolbarI18n; display: ToolbarDisplay; variant?: MapIconVariant; tooltipSide: TooltipSide; size?: MapIconSize; onclick?: (e: MouseEvent) => void; class?: string; }
let { widgetConfig, i18nConfig, display, variant = 'default', size = 'default', tooltipSide, onclick, class: className, ...restProps }: Props = $props();
const widgetManager = getWidgetManager(); const i18n = $derived(getI18n(i18nConfig)); const toolbarConfig = $derived(widgetConfig.inToolbar!); const title = $derived( toolbarConfig.type === 'button' ? i18n.translate(toolbarConfig.label ?? widgetConfig.title) : undefined, ); // FIXME: remove this when WOM features are fully released (xd) const tooltipText = $derived( toolbarConfig.type === 'button' && toolbarConfig.disabled ? i18n('common.incoming-tool', { tool: title }) : title, ); const icon = $derived(toolbarConfig.type === 'button' ? (toolbarConfig.icon ?? widgetConfig.icon) : undefined); const reference = $derived(widgetManager.getReference(widgetConfig.widgetId));</script>
{#if toolbarConfig.type === 'button'} <ToolbarTooltip text={tooltipText} side={tooltipSide} class={className}> <button {onclick} disabled={toolbarConfig.disabled} data-test-id="ToolbarItem-{widgetConfig.widgetId}" class={cn(mapIconButtonVariants({ variant, size }))} data-state={reference.active ? 'active' : ''} {...restProps} > {#if display === 'full'} <span class="gv-text-[11px]">{title}</span> {/if} {#if isActiveIcon(icon)} <Icon icon={reference.active ? icon.active : icon.inactive} /> {:else} <Icon {icon} /> {/if} </button> </ToolbarTooltip>{:else if toolbarConfig.type === 'integrated'} {#if reference.active} <WidgetContainer {reference} class={className} /> {/if}{/if}packages/common/src/lib/widgets/toolbar/ToolbarTooltip.svelte
<script lang="ts"> import type { PropsWithChildren } from '$lib/api/utils/index.ts'; import { type ContentProps, Tooltip, TooltipContent, TooltipTrigger } from '$lib/components/shadcn/ui/tooltip'; import { cn } from '$lib/components/shadcn/utils';
interface Props { text: string | null | undefined; side: ContentProps['side']; class?: string; }
let { text, side, class: className, children }: PropsWithChildren<Props> = $props();</script>
<Tooltip openDelay={0}> <TooltipTrigger class={cn('gv-size-fit', className)}> {@render children?.()} </TooltipTrigger> {#if text} <TooltipContent class="gv-text-base gv-px-lb gv-py-[10px] gv-font-bold gv-rounded-5xl" {side} sideOffset={15}> <p>{text}</p> </TooltipContent> {/if}</Tooltip>