/* * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ import type { PropsWithDataCypressId } from '../../../../utils/cypress-attribute' import { cypressId } from '../../../../utils/cypress-attribute' import { Logger } from '../../../../utils/logger' import { ShowIf } from '../../../common/show-if/show-if' import { ProxyImageFrame } from '../../extensions/image/proxy-image-frame' import styles from './click-shield.module.scss' import type { Property } from 'csstype' import type { PropsWithChildren } from 'react' import React, { useCallback, useEffect, useMemo, useState } from 'react' import type { Icon } from 'react-bootstrap-icons' import { Trans, useTranslation } from 'react-i18next' const log = new Logger('OneClickEmbedding') export interface ClickShieldProps extends PropsWithChildren { onImageFetch?: () => Promise fallbackPreviewImageUrl?: string hoverIcon: Icon targetDescription: string containerClassName?: string fallbackBackgroundColor?: Property.BackgroundColor } /** * Prevents loading of the children elements until the user unlocks the content by e.g. clicking. * * @param containerClassName Additional CSS classes for the complete component * @param onImageFetch A callback that is used to get an URL for the preview image * @param fallbackPreviewImageUrl The URL for an image that should be shown. If onImageFetch is defined then this image will be shown until onImageFetch provides another URL. * @param targetDescription The name of the target service * @param hoverIcon The name of an icon that should be shown in the preview * @param fallbackBackgroundColor A color that should be used if no background image was provided or could be loaded. * @param children The children element that should be shielded. */ export const ClickShield: React.FC = ({ containerClassName, onImageFetch, fallbackPreviewImageUrl, children, targetDescription, hoverIcon, fallbackBackgroundColor, ...props }) => { const [showChildren, setShowChildren] = useState(false) const [previewImageUrl, setPreviewImageUrl] = useState(fallbackPreviewImageUrl) const { t } = useTranslation() const doShowChildren = useCallback(() => { setShowChildren(true) }, []) useEffect(() => { if (!onImageFetch) { return } onImageFetch() .then((imageLink) => { setPreviewImageUrl(imageLink) }) .catch((message) => { log.error(message) }) }, [onImageFetch]) const fallbackBackgroundStyle = useMemo( () => !fallbackBackgroundColor ? {} : { backgroundColor: fallbackBackgroundColor }, [fallbackBackgroundColor] ) const previewHoverText = useMemo(() => { return targetDescription ? t('renderer.clickShield.previewHoverText', { target: targetDescription }) : '' }, [t, targetDescription]) const previewBackground = useMemo(() => { return previewImageUrl === undefined ? ( ) : ( ) }, [fallbackBackgroundStyle, previewHoverText, previewImageUrl]) const hoverTextTranslationValues = useMemo(() => ({ target: targetDescription }), [targetDescription]) const icon = useMemo( () => React.createElement(hoverIcon, { width: '5em', height: '5em', className: 'mb-2' }), [hoverIcon] ) return ( {children} {previewBackground} {icon} ) }