File size: 4,045 Bytes
4114d85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { IconClipboard, IconDownload } from '@tabler/icons'
import { memo, useState } from 'react'
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'
import PropTypes from 'prop-types'
import { Box, IconButton, Popover, Typography } from '@mui/material'
import { useTheme } from '@mui/material/styles'

const programmingLanguages = {
    javascript: '.js',
    python: '.py',
    java: '.java',
    c: '.c',
    cpp: '.cpp',
    'c++': '.cpp',
    'c#': '.cs',
    ruby: '.rb',
    php: '.php',
    swift: '.swift',
    'objective-c': '.m',
    kotlin: '.kt',
    typescript: '.ts',
    go: '.go',
    perl: '.pl',
    rust: '.rs',
    scala: '.scala',
    haskell: '.hs',
    lua: '.lua',
    shell: '.sh',
    sql: '.sql',
    html: '.html',
    css: '.css'
}

export const CodeBlock = memo(({ language, chatflowid, isDialog, value }) => {
    const theme = useTheme()
    const [anchorEl, setAnchorEl] = useState(null)
    const openPopOver = Boolean(anchorEl)

    const handleClosePopOver = () => {
        setAnchorEl(null)
    }

    const copyToClipboard = (event) => {
        if (!navigator.clipboard || !navigator.clipboard.writeText) {
            return
        }

        navigator.clipboard.writeText(value)
        setAnchorEl(event.currentTarget)
        setTimeout(() => {
            handleClosePopOver()
        }, 1500)
    }

    const downloadAsFile = () => {
        const fileExtension = programmingLanguages[language] || '.file'
        const suggestedFileName = `file-${chatflowid}${fileExtension}`
        const fileName = suggestedFileName

        if (!fileName) {
            // user pressed cancel on prompt
            return
        }

        const blob = new Blob([value], { type: 'text/plain' })
        const url = URL.createObjectURL(blob)
        const link = document.createElement('a')
        link.download = fileName
        link.href = url
        link.style.display = 'none'
        document.body.appendChild(link)
        link.click()
        document.body.removeChild(link)
        URL.revokeObjectURL(url)
    }

    return (
        <div style={{ width: isDialog ? '' : 300 }}>
            <Box sx={{ color: 'white', background: theme.palette?.common.dark, p: 1, borderTopLeftRadius: 10, borderTopRightRadius: 10 }}>
                <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
                    {language}
                    <div style={{ flex: 1 }}></div>
                    <IconButton size='small' title='Copy' color='success' onClick={copyToClipboard}>
                        <IconClipboard />
                    </IconButton>
                    <Popover
                        open={openPopOver}
                        anchorEl={anchorEl}
                        onClose={handleClosePopOver}
                        anchorOrigin={{
                            vertical: 'top',
                            horizontal: 'right'
                        }}
                        transformOrigin={{
                            vertical: 'top',
                            horizontal: 'left'
                        }}
                    >
                        <Typography variant='h6' sx={{ pl: 1, pr: 1, color: 'white', background: theme.palette.success.dark }}>
                            Copied!
                        </Typography>
                    </Popover>
                    <IconButton size='small' title='Download' color='primary' onClick={downloadAsFile}>
                        <IconDownload />
                    </IconButton>
                </div>
            </Box>

            <SyntaxHighlighter language={language} style={oneDark} customStyle={{ margin: 0 }}>
                {value}
            </SyntaxHighlighter>
        </div>
    )
})
CodeBlock.displayName = 'CodeBlock'

CodeBlock.propTypes = {
    language: PropTypes.string,
    chatflowid: PropTypes.string,
    isDialog: PropTypes.bool,
    value: PropTypes.string
}