LibreChat/client/src/components/Messages/Content/CodeBlock.tsx
Marco Beretta 911babd3e0
🖌️ style: Update Light/Dark UI Themes (#1754)
* BIG UI UPDATE

* fix: search bar, dialog template, new chat icon, convo icon and delete/rename button

* moved some color config and a lot of files

* small text fixes and tailwind config refactor

* Update localization and UI styles

* Update styles and add user-select:none to Tooltip component

* Update mobile.css styles for navigation mask and background color

* Update component imports and styles

* Update DeleteButton imports and references

* Update UI components

* Update tooltip delay duration

* Fix styling and update text in various components

* fixed assistant style

* minor style fixes

* revert: removed CreationHeader & CreationPanel

* style: match new styling for SidePanel

* style: match bg-gray-800 to ChatGPT (#212121)

* style: remove slate for gray where applicable to match new light theme

---------

Co-authored-by: Danny Avila <messagedaniel@protonmail.com>
2024-03-06 12:05:43 -05:00

86 lines
2.4 KiB
TypeScript

import copy from 'copy-to-clipboard';
import { InfoIcon } from 'lucide-react';
import React, { useRef, useState, RefObject } from 'react';
import Clipboard from '~/components/svg/Clipboard';
import CheckMark from '~/components/svg/CheckMark';
import cn from '~/utils/cn';
type CodeBarProps = {
lang: string;
codeRef: RefObject<HTMLElement>;
plugin?: boolean;
error?: boolean;
};
type CodeBlockProps = Pick<CodeBarProps, 'lang' | 'plugin' | 'error'> & {
codeChildren: React.ReactNode;
classProp?: string;
};
const CodeBar: React.FC<CodeBarProps> = React.memo(({ lang, codeRef, error, plugin = null }) => {
const [isCopied, setIsCopied] = useState(false);
return (
<div className="relative flex items-center rounded-tl-md rounded-tr-md bg-gray-700 px-4 py-2 font-sans text-xs text-gray-200 dark:bg-gray-700">
<span className="">{lang}</span>
{plugin ? (
<InfoIcon className="ml-auto flex h-4 w-4 gap-2 text-white/50" />
) : (
<button
className={cn('ml-auto flex gap-2', error ? 'h-4 w-4 items-start text-white/50' : '')}
onClick={async () => {
const codeString = codeRef.current?.textContent;
if (codeString) {
setIsCopied(true);
copy(codeString);
setTimeout(() => {
setIsCopied(false);
}, 3000);
}
}}
>
{isCopied ? (
<>
<CheckMark />
{error ? '' : 'Copied!'}
</>
) : (
<>
<Clipboard />
{error ? '' : 'Copy code'}
</>
)}
</button>
)}
</div>
);
});
const CodeBlock: React.FC<CodeBlockProps> = ({
lang,
codeChildren,
classProp = '',
plugin = null,
error,
}) => {
const codeRef = useRef<HTMLElement>(null);
const language = plugin || error ? 'json' : lang;
return (
<div className="w-full rounded-md bg-gray-900 text-xs text-white/80">
<CodeBar lang={lang} codeRef={codeRef} plugin={!!plugin} error={error} />
<div className={cn(classProp, 'overflow-y-auto p-4')}>
<code
ref={codeRef}
className={cn(
plugin || error ? '!whitespace-pre-wrap' : `hljs language-${language} !whitespace-pre`,
)}
>
{codeChildren}
</code>
</div>
</div>
);
};
export default CodeBlock;