legends810/testingnew
0
1import { memo, useEffect, useState } from 'react';2import { bundledLanguages, codeToHtml, isSpecialLang, type BundledLanguage, type SpecialLanguage } from 'shiki';3import { classNames } from '~/utils/classNames';4import { createScopedLogger } from '~/utils/logger';5 6import styles from './CodeBlock.module.scss';7 8const logger = createScopedLogger('CodeBlock');9 10interface CodeBlockProps {11 className?: string;12 code: string;13 language?: BundledLanguage | SpecialLanguage;14 theme?: 'light-plus' | 'dark-plus';15 disableCopy?: boolean;16}17 18export const CodeBlock = memo(19 ({ className, code, language = 'plaintext', theme = 'dark-plus', disableCopy = false }: CodeBlockProps) => {20 const [html, setHTML] = useState<string | undefined>(undefined);21 const [copied, setCopied] = useState(false);22 23 const copyToClipboard = () => {24 if (copied) {25 return;26 }27 28 navigator.clipboard.writeText(code);29 30 setCopied(true);31 32 setTimeout(() => {33 setCopied(false);34 }, 2000);35 };36 37 useEffect(() => {38 if (language && !isSpecialLang(language) && !(language in bundledLanguages)) {39 logger.warn(`Unsupported language '${language}'`);40 }41 42 logger.trace(`Language = ${language}`);43 44 const processCode = async () => {45 setHTML(await codeToHtml(code, { lang: language, theme }));46 };47 48 processCode();49 }, [code]);50 51 return (52 <div className={classNames('relative group text-left', className)}>53 <div54 className={classNames(55 styles.CopyButtonContainer,56 'bg-transparant absolute top-[10px] right-[10px] rounded-md z-10 text-lg flex items-center justify-center opacity-0 group-hover:opacity-100',57 {58 'rounded-l-0 opacity-100': copied,59 },60 )}61 >62 {!disableCopy && (63 <button64 className={classNames(65 'flex items-center bg-accent-500 p-[6px] justify-center before:bg-white before:rounded-l-md before:text-gray-500 before:border-r before:border-gray-300 rounded-md transition-theme',66 {67 'before:opacity-0': !copied,68 'before:opacity-100': copied,69 },70 )}71 title="Copy Code"72 onClick={() => copyToClipboard()}73 >74 <div className="i-ph:clipboard-text-duotone"></div>75 </button>76 )}77 </div>78 <div dangerouslySetInnerHTML={{ __html: html ?? '' }}></div>79 </div>80 );81 },82);83 