mirror of
https://github.com/harness/drone.git
synced 2025-05-06 21:52:03 +08:00
91 lines
3.0 KiB
TypeScript
91 lines
3.0 KiB
TypeScript
import { useHistory } from 'react-router-dom'
|
|
import React, { useCallback, useState } from 'react'
|
|
import { Container } from '@harness/uicore'
|
|
import cx from 'classnames'
|
|
import MarkdownPreview from '@uiw/react-markdown-preview'
|
|
import rehypeVideo from 'rehype-video'
|
|
import rehypeExternalLinks from 'rehype-external-links'
|
|
import { INITIAL_ZOOM_LEVEL } from 'utils/Utils'
|
|
import ImageCarousel from 'components/ImageCarousel/ImageCarousel'
|
|
import css from './MarkdownViewer.module.scss'
|
|
|
|
interface MarkdownViewerProps {
|
|
source: string
|
|
className?: string
|
|
maxHeight?: string | number
|
|
}
|
|
|
|
export function MarkdownViewer({ source, className, maxHeight }: MarkdownViewerProps) {
|
|
const [isOpen, setIsOpen] = useState<boolean>(false)
|
|
const history = useHistory()
|
|
const [zoomLevel, setZoomLevel] = useState(INITIAL_ZOOM_LEVEL)
|
|
|
|
const [imgEvent, setImageEvent] = useState<string[]>([])
|
|
|
|
const interceptClickEventOnViewerContainer = useCallback(
|
|
event => {
|
|
const { target } = event
|
|
|
|
const imageArray = source.split('\n').filter(string => string.includes('![image]'))
|
|
const imageStringArray = imageArray.map(string => {
|
|
const imageSrc = string.split('![image]')[1]
|
|
return imageSrc.slice(1, imageSrc.length - 1)
|
|
})
|
|
setImageEvent(imageStringArray)
|
|
if (target?.tagName?.toLowerCase() === 'a') {
|
|
const { href } = target
|
|
|
|
// Intercept click event on internal links and navigate to pages to avoid full page reload
|
|
if (href && !href.startsWith('#')) {
|
|
try {
|
|
const url = new URL(href)
|
|
|
|
if (url.origin === window.location.origin) {
|
|
event.stopPropagation()
|
|
event.preventDefault()
|
|
history.push(url.pathname)
|
|
}
|
|
} catch (e) {
|
|
// eslint-disable-next-line no-console
|
|
console.error('Error: MarkdownViewer/interceptClickEventOnViewerContainer', e)
|
|
}
|
|
}
|
|
} else if (event.target.nodeName?.toLowerCase() === 'img') {
|
|
setIsOpen(true)
|
|
}
|
|
},
|
|
[history, source]
|
|
)
|
|
|
|
return (
|
|
<Container
|
|
className={cx(css.main, className, { [css.withMaxHeight]: maxHeight && maxHeight > 0 })}
|
|
onClick={interceptClickEventOnViewerContainer}
|
|
style={{ maxHeight: maxHeight }}>
|
|
<MarkdownPreview
|
|
source={source}
|
|
skipHtml={true}
|
|
warpperElement={{ 'data-color-mode': 'light' }}
|
|
rehypeRewrite={(node, _index, parent) => {
|
|
if ((node as unknown as HTMLDivElement).tagName === 'a') {
|
|
if (parent && /^h(1|2|3|4|5|6)/.test((parent as unknown as HTMLDivElement).tagName)) {
|
|
parent.children = parent.children.slice(1)
|
|
}
|
|
}
|
|
}}
|
|
rehypePlugins={[
|
|
rehypeVideo,
|
|
[rehypeExternalLinks, { rel: ['nofollow noreferrer noopener'], target: '_blank' }]
|
|
]}
|
|
/>
|
|
<ImageCarousel
|
|
isOpen={isOpen}
|
|
setIsOpen={setIsOpen}
|
|
setZoomLevel={setZoomLevel}
|
|
zoomLevel={zoomLevel}
|
|
imgEvent={imgEvent}
|
|
/>
|
|
</Container>
|
|
)
|
|
}
|