feat: support HTML preview

pull/19162/head
G.Wood-Sun 1 year ago
parent f8e5341ac0
commit a7d6ea011d

@ -0,0 +1,74 @@
import React from 'react'
import FullScreenModal from '@/app/components/base/fullscreen-modal'
import cn from '@/utils/classnames'
import s from './style.module.css'
import { useTranslation } from 'react-i18next'
import ActionButton from '../action-button'
import Tooltip from '../tooltip'
type HTMLPreviewBtnProps = {
content: string,
completed?: boolean,
}
const prefixPreview = 'appOverview.overview.appInfo.preview'
type CreateIframeModalProps = {
show: boolean,
onClose: () => void,
content: string,
}
const CreateIframeModal = ({ show, onClose, content }: CreateIframeModalProps) => {
const { t } = useTranslation()
return (
<FullScreenModal
overflowVisible
closable
open={show}
onClose={onClose}
>
<iframe
srcDoc={content}
sandbox="allow-scripts"
title={t(`${prefixPreview}`)}
style={{ width: '100%', height: '100%', border: 'none' }}
/>
</FullScreenModal>
)
}
const HTMLPreviewBtn = ({
content,
completed = false,
}: HTMLPreviewBtnProps) => {
const { t } = useTranslation()
const [show, setShow] = React.useState(false)
const openModal = () => {
setShow(true)
}
const closeModal = () => {
setShow(false)
}
if (!completed) return null
return (
<>
<Tooltip
popupContent={t(`${prefixPreview}`)}>
<ActionButton onClick={openModal}>
<div className={cn('h-4 w-4', s.previewIcon)}></div>
</ActionButton>
</Tooltip>
<CreateIframeModal
show={show}
onClose={closeModal}
content={content}
/>
</>
)
}
export default HTMLPreviewBtn

@ -0,0 +1,5 @@
.previewIcon {
background-image: url(~@/app/components/develop/secret-key/assets/play.svg);
background-position: center;
background-repeat: no-repeat;
}

@ -16,6 +16,7 @@ import { flow } from 'lodash-es'
import ActionButton from '@/app/components/base/action-button'
import CopyIcon from '@/app/components/base/copy-icon'
import SVGBtn from '@/app/components/base/svg'
import HTMLPreviewBtn from '@/app/components/base/html-preview-button'
import Flowchart from '@/app/components/base/mermaid'
import ImageGallery from '@/app/components/base/image-gallery'
import { useChatContext } from '@/app/components/base/chat/chat/context'
@ -29,6 +30,7 @@ import { Theme } from '@/types/app'
import useTheme from '@/hooks/use-theme'
import cn from '@/utils/classnames'
import SVGRenderer from './svg-gallery'
import { getPureContent, isCompleteHTML } from './utils'
// Available language https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/master/AVAILABLE_LANGUAGES_HLJS.MD
const capitalizationLanguageNameMap: Record<string, string> = {
@ -191,14 +193,17 @@ const CodeBlock: any = memo(({ inline, className, children = '', ...props }: any
if (inline || !match)
return <code {...props} className={className}>{children}</code>
const pureCode = getPureContent(children)
return (
<div className='relative'>
<div className='flex h-8 items-center justify-between rounded-t-[10px] border-b border-divider-subtle bg-components-input-bg-normal p-1 pl-3'>
<div className='system-xs-semibold-uppercase text-text-secondary'>{languageShowName}</div>
<div className='flex items-center gap-1'>
{(['mermaid', 'svg']).includes(language!) && <SVGBtn isSVG={isSVG} setIsSVG={setIsSVG} />}
{(['html']).includes(language!) && <HTMLPreviewBtn content={pureCode} completed={isCompleteHTML(pureCode)} />}
<ActionButton>
<CopyIcon content={String(children).replace(/\n$/, '')} />
<CopyIcon content={pureCode} />
</ActionButton>
</div>
</div>

@ -0,0 +1,9 @@
export const isCompleteHTML = (code: string): boolean => {
// simple check
const completeHTMLRegex = /<\s*html\s*[^>]*>[\s\S]*<\/html\s*>/i
return completeHTMLRegex.test(code)
}
export const getPureContent = (code: string): string => {
return String(code).replace(/\n$/, '').trim()
}
Loading…
Cancel
Save