Source Share
Source Share
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/export/share/share.declaration.tspackages/common/src/lib/widgets/export/share/share.config.tspackages/common/src/lib/widgets/export/share/share.models.tspackages/common/src/lib/widgets/export/share/Share.svelte
packages/common/src/lib/widgets/export/share/share.declaration.ts
import { widgetFactorySvelte, type WidgetProps } from '$lib/api/managers/widget';import { type ShareConfig, shareConfigSchema } from './share.config';import type { WidgetDeclaration } from '$lib/api/managers/widget/widget-declaration';
export const declaration = { factory: () => import('./Share.svelte').then((Share) => widgetFactorySvelte(Share)), schema: () => shareConfigSchema,} satisfies WidgetDeclaration;
export type ShareProps = WidgetProps<ShareConfig>;packages/common/src/lib/widgets/export/share/share.config.ts
import { defineWidgetConfig, inToolbarSchemaFrom } from '$lib/api/managers/configuration';import { z } from 'zod';import { i18nDataSchema, type I18nRegistry, i18nSchemaFrom } from '$lib/api/managers/i18n';import { iconSchema } from '$lib/api/icons';
export const shareTranslations = { 'integrate-map': { fr: 'Intégrer la carte', nl: 'NL - Intégrer la carte', }, 'copy-code': { fr: 'Copier', nl: 'NL - Copier', }, 'link-copied': { fr: 'Le lien a été copié dans le presse papier', nl: 'NL - Le lien a été copié dans le presse papier', }, 'code-copied': { fr: 'Le code a été copié dans le presse papier', nl: 'NL - Le code a été copié dans le presse papier', }, 'link-copy-error': { fr: 'Une erreur est survenue lors de la copie du lien', nl: 'NL - Une erreur est survenue lors de la copie du lien', },} satisfies I18nRegistry;
export const shareOptionSchema = z.object({ icon: iconSchema, label: i18nDataSchema, type: z.enum(['facebook', 'mail', 'x', 'linkedin', 'link', 'whatsapp']),});export type ShareOption = z.infer<typeof shareOptionSchema>;
const defaultShareOptions: ShareOption[] = [ { type: 'mail', icon: { geoviewer: 'mail' }, label: { fr: 'Mail', nl: 'NL - Mail', }, }, { type: 'facebook', icon: { geoviewer: 'facebook' }, label: { fr: 'Facebook', nl: 'NL - Facebook', }, }, { type: 'linkedin', icon: { geoviewer: 'linkedin' }, label: { fr: 'LinkedIn', nl: 'NL - LinkedIn', }, }, { type: 'whatsapp', icon: { geoviewer: 'whatsapp' }, label: { fr: 'WhatsApp', nl: 'NL - WhatsApp', }, }, { type: 'link', icon: { geoviewer: 'link' }, label: { fr: 'Lien à copier', nl: 'NL - Lien à copier', }, },];
export const shareConfigSchema = defineWidgetConfig({ title: { fr: 'Partager', nl: 'NL - Partager', }, i18n: i18nSchemaFrom(shareTranslations), icon: { lucide: 'Share2', }, inToolbar: inToolbarSchemaFrom(false), active: false, config: z .object({ shareOptions: z.array(shareOptionSchema).default(defaultShareOptions), iframeBaseUrl: z.string().default('https://geoportail.wallonie.be/files/GeoViewer/WOMLIGHT-5/index.html'), }) .prefault({}),});
export type ShareConfig = z.infer<typeof shareConfigSchema>;packages/common/src/lib/widgets/export/share/share.models.ts
import type { ShareOption } from '$lib/widgets/export/share/share.config';
export function buildIntegrationLink(shareLink: ShareOption, url: string): string { switch (shareLink.type) { case 'mail': { const urlParams = new URLSearchParams({ body: url, }); return `mailto:?${urlParams}`; } case 'facebook': { const urlParams = new URLSearchParams({ u: url, }); return `https://www.facebook.com/sharer/sharer.php?${urlParams}`; } case 'linkedin': { const urlParams = new URLSearchParams({ url: url, mini: 'true', }); return `https://www.linkedin.com/shareArticle?${urlParams}`; } case 'whatsapp': { const urlParams = new URLSearchParams({ text: url, }); return `https://wa.me/?${urlParams}`; } default: return url; }}packages/common/src/lib/widgets/export/share/Share.svelte
<script lang="ts"> import { Button } from '$lib/components/shadcn/ui/button'; import { getI18n } from '$lib/api/managers/i18n'; import { getMapManager } from '$lib/api/map'; import { Input } from '$lib/components/shadcn/ui/input'; import type { ShareProps } from '$lib/widgets/export/share/share.declaration'; import { Icon } from '$lib/components/icon'; import { queryState } from '$lib/api/utils'; import Loader from '$lib/components/common/Loader.svelte'; import { copyToClipboard } from '$lib/api/utils/clipboard.utils'; import { showToast } from '$lib/components/toast/toast.utils'; import type { ShareOption } from '$lib/widgets/export/share/share.config'; import { buildIntegrationLink } from '$lib/widgets/export/share/share.models'; import { ShareService } from '$lib/api/services/share/share.service'; import { getViewerService } from '$lib/api/viewer.service';
let { fullConfig }: ShareProps = $props();
const { config } = fullConfig; const i18n = getI18n(fullConfig.i18n); const mapManager = getMapManager(); const viewerService = getViewerService(); const shareService = new ShareService(viewerService.info);
const generateShareLinkQuery = queryState({ queryFn: () => shareService.createShare(mapManager).then((token) => (currentToken = token)), });
let currentToken = $state<string | undefined>(); let selectedShareOption = $state<ShareOption>();
const linkWithShare = $derived.by(() => `${getBaseUrl()}#SHARE=${currentToken}`); const iframeLinkWithShare = $derived.by(() => `${config.iframeBaseUrl}#SHARE=${currentToken}`); const iframeIntegrationCode = $derived.by( () => `<iframe width="500" height="500" src="${iframeLinkWithShare}"></iframe>`, );
$effect(() => { if (!selectedShareOption) return; if (selectedShareOption.type === 'link') { copy(i18n('link-copied'), linkWithShare); } else { const shareLink = buildIntegrationLink(selectedShareOption, linkWithShare); window.open(shareLink, '_blank'); } });
function getBaseUrl(): string { let currentWindow = window; while (currentWindow !== currentWindow.parent) { currentWindow = currentWindow.parent as never; } return currentWindow.location.href.replace(/#SHARE=[^&]*/, '').replace(/#$/, ''); }
function copy(toastMessage: string, link?: string) { if (!link) return; copyToClipboard(link, { onSuccess: () => showToast({ level: 'success', message: toastMessage }), onError: () => showToast({ level: 'error', message: i18n('link-copy-error') }), }); }</script>
<div class="gv-p-3"> <div class="gv-flex gv-justify-start gv-gap-2"> {#each config.shareOptions as shareOption (shareOption)} <Button title={i18n.translate(shareOption.label)} class="gv-size-8 gv-p-1 gv-border-primary" size="icon" onclick={() => (selectedShareOption = shareOption)} variant="outline" > <Icon class="gv-text-primary" icon={shareOption.icon} /> </Button> {/each} </div>
{#if generateShareLinkQuery} {#if generateShareLinkQuery.loading} <div class="gv-flex gv-mt-2 gv-justify-center gv-items-center"> <Loader /> </div> {/if} {#if iframeIntegrationCode} <div class="gv-text-lg gv-mt-3 gv-font-bold">{i18n('integrate-map')}</div> <div class="gv-flex gv-items-center group gv-border gv-rounded-xs gv-pl-md"> <input class="gv-flex-1 gv-text-grey-600 gv-truncate gv-border-none" value={iframeIntegrationCode} /> <Button onclick={() => copy(i18n('code-copied'), iframeIntegrationCode)} variant="link" class=""> {i18n('copy-code')} </Button> </div> {/if} {/if}</div>