CoolFace
Apppublic

caijizy/bingo

sourceHugging Facemitupdated 3y agoView on Hugging Face
0likes
codeblock.tsx143 linesDownload Raw Back to ui
1'use client'2 3import { FC, memo } from 'react'4import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'5import { coldarkDark } from 'react-syntax-highlighter/dist/cjs/styles/prism'6 7import { useCopyToClipboard } from '@/lib/hooks/use-copy-to-clipboard'8import { IconCheck, IconCopy, IconDownload } from '@/components/ui/icons'9import { Button } from '@/components/ui/button'10 11interface Props {12  language: string13  value: string14}15 16interface languageMap {17  [key: string]: string | undefined18}19 20export const programmingLanguages: languageMap = {21  javascript: '.js',22  python: '.py',23  java: '.java',24  c: '.c',25  cpp: '.cpp',26  'c++': '.cpp',27  'c#': '.cs',28  ruby: '.rb',29  php: '.php',30  swift: '.swift',31  'objective-c': '.m',32  kotlin: '.kt',33  typescript: '.ts',34  go: '.go',35  perl: '.pl',36  rust: '.rs',37  scala: '.scala',38  haskell: '.hs',39  lua: '.lua',40  shell: '.sh',41  sql: '.sql',42  html: '.html',43  css: '.css'44  // add more file extensions here, make sure the key is same as language prop in CodeBlock.tsx component45}46 47export const generateRandomString = (length: number, lowercase = false) => {48  const chars = 'ABCDEFGHJKLMNPQRSTUVWXY3456789' // excluding similar looking characters like Z, 2, I, 1, O, 049  let result = ''50  for (let i = 0; i < length; i++) {51    result += chars.charAt(Math.floor(Math.random() * chars.length))52  }53  return lowercase ? result.toLowerCase() : result54}55 56const CodeBlock: FC<Props> = memo(({ language, value }) => {57  const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 })58 59  const downloadAsFile = () => {60    if (typeof window === 'undefined') {61      return62    }63    const fileExtension = programmingLanguages[language] || '.file'64    const suggestedFileName = `file-${generateRandomString(65      3,66      true67    )}${fileExtension}`68    const fileName = window.prompt('Enter file name' || '', suggestedFileName)69 70    if (!fileName) {71      // User pressed cancel on prompt.72      return73    }74 75    const blob = new Blob([value], { type: 'text/plain' })76    const url = URL.createObjectURL(blob)77    const link = document.createElement('a')78    link.download = fileName79    link.href = url80    link.style.display = 'none'81    document.body.appendChild(link)82    link.click()83    document.body.removeChild(link)84    URL.revokeObjectURL(url)85  }86 87  const onCopy = () => {88    if (isCopied) return89    copyToClipboard(value)90  }91 92  return (93    <div className="codeblock relative w-full bg-zinc-950 font-sans">94      <div className="flex w-full items-center justify-between bg-zinc-800 px-6 py-2 pr-4 text-zinc-100">95        <span className="text-xs lowercase">{language}</span>96        <div className="flex items-center space-x-1">97          <Button98            variant="ghost"99            className="hover:bg-zinc-800 focus-visible:ring-1 focus-visible:ring-slate-700 focus-visible:ring-offset-0"100            onClick={downloadAsFile}101            size="icon"102          >103            <IconDownload />104            <span className="sr-only">Download</span>105          </Button>106          <Button107            variant="ghost"108            size="icon"109            className="text-xs hover:bg-zinc-800 focus-visible:ring-1 focus-visible:ring-slate-700 focus-visible:ring-offset-0"110            onClick={onCopy}111          >112            {isCopied ? <IconCheck /> : <IconCopy />}113            <span className="sr-only">Copy code</span>114          </Button>115        </div>116      </div>117      <SyntaxHighlighter118        language={language}119        style={coldarkDark}120        PreTag="div"121        showLineNumbers122        customStyle={{123          margin: 0,124          width: '100%',125          background: 'transparent',126          padding: '1.5rem 1rem'127        }}128        codeTagProps={{129          style: {130            fontSize: '0.9rem',131            fontFamily: 'var(--font-mono)'132          }133        }}134      >135        {value}136      </SyntaxHighlighter>137    </div>138  )139})140CodeBlock.displayName = 'CodeBlock'141 142export { CodeBlock }143