import {useI18n} from '@codeimage/locale'; import {getExportCanvasStore} from '@codeimage/store/canvas'; import type {SegmentedFieldItem} from '@codeimage/ui'; import { Box, FieldLabel, FieldLabelHint, FlexField, HStack, Link, RangeField, toast, VStack, } from '@codeimage/ui'; import type {DialogProps} from '@codeui/kit'; import { Button, Checkbox, Dialog, DialogPanelContent, DialogPanelFooter, } from '@codeui/kit'; import {getUmami} from '@core/constants/umami'; import {useModality} from '@core/hooks/isMobile'; import {useWebshare} from '@core/hooks/use-webshare'; import {DynamicSizedContainer} from '@ui/DynamicSizedContainer/DynamicSizedContainer'; import {SegmentedField} from '@ui/SegmentedField/SegmentedField'; import type {Component} from 'solid-js'; import {createEffect, createSignal, onMount, Show, untrack} from 'solid-js'; import {useExportSnippet} from '../../hooks/export-snippet'; import {ExportExtension, ExportMode} from '../../hooks/use-export-image'; import {useHotkey} from '../../hooks/use-hotkey'; import type {AppLocaleEntries} from '../../i18n'; import {DownloadIcon} from '../Icons/Download'; import {ExclamationIcon} from '../Icons/Exclamation'; import {HintIcon} from '../Icons/Hint'; interface ExportButtonProps { canvasRef: HTMLElement | undefined; } export const ExportButton: Component = props => { const [t] = useI18n(); const modality = useModality(); const buttonSize = () => (modality === 'full' ? 'sm' : 'xs'); const [open, setOpen] = createSignal(false); const [data, notify] = useExportSnippet(); const label = () => t('toolbar.export'); createEffect(() => { if (data.error) { untrack(() => { toast.error( () => { const [t] = useI18n(); return <>{t('export.genericSaveError')}; }, { position: 'bottom-center', }, ); }); } }); useHotkey(document.body, { 'Control+s': event => { event.preventDefault(); setOpen(true); }, }); return ( <> { notify({ options: { extension: payload.extension, mode: payload.type, pixelRatio: payload.pixelRatio, quality: payload.quality, }, ref: props.canvasRef, }); }} /> ); }; export type ExportDialogProps = { onConfirm: ( payload: | { type: ExportMode.export; extension: ExportExtension; pixelRatio: number; quality: number; } | { type: ExportMode.share; message: string; extension: ExportExtension; pixelRatio: number; quality: number; }, ) => void; }; export function ExportDialog(props: ExportDialogProps & DialogProps) { const [t] = useI18n(); const [supportWebShare] = useWebshare(); const exportCanvasStore = getExportCanvasStore(); const [mode, setMode] = createSignal(ExportMode.export); const [extension, setExtension] = createSignal( ExportExtension.png, ); const [quality, setQuality] = createSignal(100); const [devicePixelRatio, setDevicePixelRatio] = createSignal( Math.round(window.devicePixelRatio), ); const modeItems = () => [ {label: t('export.exportMode'), value: ExportMode.export}, {label: t('export.shareMode'), value: ExportMode.share}, ] as SegmentedFieldItem[]; const extensionItems: SegmentedFieldItem[] = [ {label: 'PNG', value: ExportExtension.png}, {label: 'SVG', value: ExportExtension.svg}, {label: 'JPEG', value: ExportExtension.jpeg}, ]; const onConfirm = () => { props.onOpenChange?.(false); const selectedMode = mode(); if (selectedMode !== ExportMode.export && selectedMode !== ExportMode.share) return; const selectedExtension = extension(); getUmami().track('export-confirm', { mode: selectedMode, extension: selectedExtension, }); props.onConfirm({ type: selectedMode, extension: selectedExtension, pixelRatio: devicePixelRatio(), message: '', quality: quality() / 100, }); }; onMount(() => { if (!supportWebShare()) { setMode(ExportMode.export); } }); return ( props.onOpenChange?.(value)} modal={true} size={props.size} title={t('export.title')} > } > {t('export.shareHint')}   Web Share API {t('export.extensionType')} } > {t('export.noOpacitySupportedWithThisExtension')}   {t('export.quality')} {quality()}% {t('export.pixelRatio')} {devicePixelRatio()}x ); }