Skip to content

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.ts

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

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({
widgetsIds: 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

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

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();
const config = $derived(fullConfig.config);
const configurationManager = getConfigurationManager();
const widgetManager = getWidgetManager();
const inToolbarWidgets = $derived.by(() => {
const inToolbar = configurationManager.widgetsConfiguration!.filter(
(w) => w.inToolbar && w.inToolbar.toolbarId === config.toolbarId,
) as WidgetConfig[];
const toolbarTabs = configurationManager.viewerConfiguration!.containers.filter((c) =>
isToolbarTabConfig(c, config.toolbarId),
);
return [...inToolbar, ...toolbarTabs].sort((a, b) => {
const aOrder = getOrder(a);
const bOrder = getOrder(b);
return aOrder - bOrder;
});
});
function getOrder(item: WidgetConfig | ToolbarTabsConfig): number {
if (isToolbarTabs(item)) {
return item.order ?? 0;
} else {
return item.inToolbar?.order ?? 0;
}
}
function getKey(item: WidgetConfig | ToolbarTabsConfig): string {
if (isToolbarTabs(item)) {
return `toolbar-tab-${item.id}`;
} else {
return item.widgetId;
}
}
function isToolbarTabs(item: WidgetConfig | ToolbarTabsConfig): item is ToolbarTabsConfig {
return 'type' in item && item.type === 'toolbar-tabs';
}
function isToolbarTabConfig(
container: ContainerConfig | ContainerWidgetConfig | string,
toolbarId: string,
): container is ToolbarTabsConfig {
return (
!!container &&
typeof container === 'object' &&
'type' in container &&
container.type === 'toolbar-tabs' &&
container.toolbarId === toolbarId
);
}
async function toggleWidget(widgetId: string) {
const reference = widgetManager.getReference(widgetId);
reference.toggle({ openContainer: true });
}
</script>
<div
class={cn(
'toolbar-container gv-flex gv-rounded-full gv-overflow-hidden gv-text-primary gv-border-2 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 inToolbarWidgets as widget (getKey(widget))}
{#if isToolbarTabs(widget)}
<ToolbarTabs config={widget} class="gv-shadow-4md" />
{:else}
<ToolbarItem
widgetConfig={widget}
i18nConfig={fullConfig.i18n}
display={config.display}
tooltipSide={config.tooltipSide}
onclick={() => toggleWidget(widget.widgetId)}
style={recordToCssStyle(widget.inToolbar?.style)}
/>
{/if}
{/each}
</div>
<style>
.toolbar-container {
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.25);
}
</style>

packages/common/src/lib/widgets/toolbar/ToolbarItem.svelte

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 { ApiSimpleTooltip, 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 {
type MapIconSize,
type MapIconVariant,
mapIconButtonVariants,
mapIconVariants,
} 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';
interface Props extends HTMLAttributes<HTMLButtonElement> {
widgetConfig: WidgetConfig;
i18nConfig: ToolbarI18n;
display: ToolbarDisplay;
variant?: MapIconVariant;
size?: MapIconSize;
tooltipSide: TooltipSide;
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 = 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 = widgetManager.getReference(widgetConfig.widgetId);
</script>
{#if toolbarConfig.type === 'button'}
<ApiSimpleTooltip text={tooltipText} side={tooltipSide} openDelay={0}>
<div class={cn('gv-bg-background gv-contents', mapIconButtonVariants.variants.size[size], 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} class={mapIconVariants()}></Icon>
{:else}
<Icon {icon} class={mapIconVariants({ size })}></Icon>
{/if}
</button>
</div>
</ApiSimpleTooltip>
{:else if toolbarConfig.type === 'integrated'}
{#if reference.active}
<WidgetContainer {reference} class={className} />
{/if}
{/if}

Aller plus loin