Skip to content

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

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

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

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

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>

Aller plus loin