-
Notifications
You must be signed in to change notification settings - Fork 42
/
Copy pathMarkdownViewer.tsx
109 lines (104 loc) · 3.11 KB
/
MarkdownViewer.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import {
Box,
Link,
OrderedList,
SkeletonText,
Text,
UnorderedList,
chakra,
useColorMode,
} from '@chakra-ui/react'
import { MarkdownPreviewProps } from '@uiw/react-markdown-preview'
import useTranslation from 'next-translate/useTranslation'
import dynamic from 'next/dynamic'
import { FC, useEffect, useRef, useState } from 'react'
const MDPreview = dynamic<MarkdownPreviewProps>(
() => import('@uiw/react-markdown-preview'),
{
ssr: false,
// SkeletonText placeholder while loading
loading: () => <SkeletonText noOfLines={2} />,
},
)
const MarkdownViewer: FC<MarkdownPreviewProps & { noTruncate?: boolean }> = ({
noTruncate,
source,
...props
}) => {
const { t } = useTranslation('components')
const { colorMode } = useColorMode()
const [isMultiline, setMultiline] = useState(false)
const [isOpen, setOpen] = useState(false)
const invisibleRef = useRef<HTMLDivElement>(null)
useEffect(() => {
if (noTruncate) return setOpen(true)
const element = invisibleRef.current
const ONE_LINE_HEIGHT = 24
if (
// hack to check if the text is multiline by using hidden div
(element && element.scrollHeight > ONE_LINE_HEIGHT) ||
// check if the text is multiline by checking for newlines
(source && source.split(/\r\n|\r|\n/).length > 1)
) {
setMultiline(true)
}
}, [noTruncate, source])
return (
<Box position="relative">
<chakra.div
ref={invisibleRef}
position="absolute"
w="full"
visibility="hidden"
>
{source}
</chakra.div>
<div data-color-mode={colorMode}>
<MDPreview
components={{
p: (props) => <Text {...props} />,
br: () => <br />,
ol: (props) => <OrderedList {...props} />,
ul: (props) => <UnorderedList {...props} />,
a: (props) => (
<Link
color="brand.500"
_hover={{ textDecoration: 'underline' }}
{...props}
/>
),
// Force these to be text components
h1: (props) => <Text {...props} />,
h2: (props) => <Text {...props} />,
h3: (props) => <Text {...props} />,
h4: (props) => <Text {...props} />,
h5: (props) => <Text {...props} />,
h6: (props) => <Text {...props} />,
code: (props) => <Text {...(props as any)} />, // TODO: fix this type
hr: () => <></>,
}}
style={{
display: 'flex',
height: isOpen ? 'auto' : '24px',
overflow: isOpen ? 'visible' : 'hidden',
}}
source={source}
{...props}
/>
</div>
{isMultiline && (
<chakra.button
onClick={() => setOpen(!isOpen)}
color="brand.500"
_active={{ opacity: 0.6 }}
_hover={{ bg: 'transparent', opacity: 0.8 }}
>
<Text variant="button2">
{isOpen ? t('truncate.show-less') : t('truncate.show-more')}
</Text>
</chakra.button>
)}
</Box>
)
}
export default MarkdownViewer