Files
gpustack-ui/src/components/highlight-code/code-viewer.tsx
T

159 lines
3.5 KiB
TypeScript

import classNames from 'classnames';
import hljs from 'highlight.js';
import { memo, useMemo } from 'react';
import styled from 'styled-components';
import CopyButton from '../copy-button';
import { escapeHtml } from './utils';
interface CodeViewerProps {
code: string;
copyValue?: string;
lang: string;
autodetect?: boolean;
ignoreIllegals?: boolean;
copyable?: boolean;
height?: string | number;
theme?: 'light' | 'dark';
style?: React.CSSProperties;
}
interface CodeHeaderProps {
copyValue: string;
copyable: boolean;
lang: string;
theme: 'light' | 'dark';
}
const CodeHeaderWrapper = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
height: 32px;
padding: 0 12px;
font-size: 12px;
color: var(--ant-color-text-tertiary);
background-color: #fafafa;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
&.dark {
background-color: #383838;
color: rgba(255, 255, 255, 0.65);
}
`;
const Wrapper = styled.div`
border-radius: var(--border-radius-mini);
`;
const CodeHeader: React.FC<CodeHeaderProps> = ({
copyValue,
lang,
theme,
copyable
}) => {
if (!copyable) {
return null;
}
return (
<CodeHeaderWrapper
className={classNames({
dark: theme === 'dark',
light: theme === 'light'
})}
>
<span>{lang}</span>
<CopyButton
text={copyValue}
size="small"
style={{ color: '#abb2bf' }}
></CopyButton>
</CodeHeaderWrapper>
);
};
const CodeViewer: React.FC<CodeViewerProps> = (props) => {
const {
code = '',
copyValue,
lang,
autodetect = true,
ignoreIllegals = true,
copyable = true,
height = 'auto',
style
} = props || {};
const highlightedCode = useMemo(() => {
const autodetectLang = autodetect && !lang;
const cannotDetectLanguage = !autodetectLang && !hljs.getLanguage(lang);
let className = '';
if (!cannotDetectLanguage) {
className = `hljs ${lang}`;
}
// No idea what language to use, return raw code
if (cannotDetectLanguage) {
console.warn(`The language "${lang}" you specified could not be found.`);
return {
value: escapeHtml(code),
className: className
};
}
if (autodetectLang) {
const result = hljs.highlightAuto(code);
return {
value: result.value,
className: className
};
}
const result = hljs.highlight(code, {
language: lang,
ignoreIllegals: ignoreIllegals
});
return {
value: result.value,
className: className
};
}, [code, lang, autodetect, ignoreIllegals]);
return (
<Wrapper>
<CodeHeader
copyValue={copyValue || code}
lang={lang}
copyable={copyable}
theme={props.theme || 'light'}
></CodeHeader>
<pre
className={classNames(
'code-pre custome-scrollbar custom-scrollbar-horizontal ',
{
dark: props.theme === 'dark',
light: props.theme === 'light'
}
)}
style={{
marginBottom: 0,
height: height,
...style
}}
>
<code
style={{ minHeight: height }}
className={classNames(highlightedCode.className, {
dark: props.theme === 'dark',
light: props.theme === 'light'
})}
dangerouslySetInnerHTML={{
__html: highlightedCode.value
}}
></code>
</pre>
</Wrapper>
);
};
export default memo(CodeViewer);