import { ApiPath, Path, REPO_URL } from '@/app/constant'; import { nanoid } from 'nanoid'; import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react'; import { useParams } from 'react-router'; import CopyIcon from '../icons/copy.svg'; import DownloadIcon from '../icons/download.svg'; import GithubIcon from '../icons/github.svg'; import LoadingButtonIcon from '../icons/loading.svg'; import ReloadButtonIcon from '../icons/reload.svg'; import ExportIcon from '../icons/share.svg'; import Locale from '../locales'; import { copyToClipboard, downloadAs } from '../utils'; import styles from './artifacts.module.scss'; import { IconButton } from './button'; import { Loading } from './home'; import { Modal, showToast } from './ui-lib'; interface HTMLPreviewProps { code: string; autoHeight?: boolean; height?: number | string; onLoad?: (title?: string) => void; } export interface HTMLPreviewHander { reload: () => void; } export const HTMLPreview = forwardRef( (props, ref) => { const iframeRef = useRef(null); const [frameId, setFrameId] = useState(nanoid()); const [iframeHeight, setIframeHeight] = useState(600); const [title, setTitle] = useState(''); /* * https://stackoverflow.com/questions/19739001/what-is-the-difference-between-srcdoc-and-src-datatext-html-in-an * 1. using srcdoc * 2. using src with dataurl: * easy to share * length limit (Data URIs cannot be larger than 32,768 characters.) */ useEffect(() => { const handleMessage = (e: any) => { const { id, height, title } = e.data; setTitle(title); if (id == frameId) { setIframeHeight(height); } }; window.addEventListener('message', handleMessage); return () => { window.removeEventListener('message', handleMessage); }; }, [frameId]); useImperativeHandle(ref, () => ({ reload: () => { setFrameId(nanoid()); }, })); const height = useMemo(() => { if (!props.autoHeight) { return props.height || 600; } if (typeof props.height === 'string') { return props.height; } const parentHeight = props.height || 600; return iframeHeight + 40 > parentHeight ? parentHeight : iframeHeight + 40; }, [props.autoHeight, props.height, iframeHeight]); const srcDoc = useMemo(() => { const script = ``; if (props.code.includes('')) { props.code.replace('', `${script}`); } return script + props.code; }, [props.code, frameId]); const handleOnLoad = () => { if (props?.onLoad) { props.onLoad(title); } }; return (