ReadonlyCodeEditor.tsx•2.86 kB
import { useMonacoTheme } from '@/src/hooks/useMonacoTheme';
import Editor from '@monaco-editor/react';
import React, { useMemo } from 'react';
import { CopyButton } from '../tools/shared/CopyButton';
interface CodeSnippetProps {
code: string;
language: 'javascript' | 'typescript' | 'python' | 'bash' | 'shell' | 'json';
}
export const CodeSnippet = React.memo(({
code,
language
}: CodeSnippetProps) => {
const { theme, onMount } = useMonacoTheme();
const height = useMemo(() => {
const lines = code.split('\n').length;
const lineHeight = 18;
const basePadding = 16;
// Multi-line bash/shell commands need significantly more space
let extraPadding = 0;
if ((language === 'bash' || language === 'shell') && lines > 1) {
extraPadding = 18;
}
return `${lines * lineHeight + basePadding + extraPadding}px`;
}, [code, language]);
const lines = useMemo(() => code.split('\n').length, [code]);
return (
<div className="relative bg-secondary rounded-md border overflow-hidden">
<div className={`absolute right-2 z-10 ${lines === 1 ? 'top-1/2 -translate-y-1/2' : 'top-2'}`}>
<CopyButton text={code} />
</div>
<div className="overflow-hidden px-2">
<Editor
height={height}
defaultLanguage={language}
value={code}
onMount={onMount}
options={{
readOnly: true,
minimap: { enabled: false },
fontSize: 11,
lineNumbers: 'off',
glyphMargin: false,
folding: false,
lineDecorationsWidth: 0,
lineNumbersMinChars: 0,
scrollBeyondLastLine: false,
scrollBeyondLastColumn: 0,
wordWrap: 'on',
contextmenu: false,
renderLineHighlight: 'none',
scrollbar: {
vertical: 'hidden',
horizontal: 'auto',
verticalScrollbarSize: 0,
horizontalScrollbarSize: 8,
alwaysConsumeMouseWheel: false
},
overviewRulerLanes: 0,
hideCursorInOverviewRuler: true,
overviewRulerBorder: false,
padding: { top: 8, bottom: 8 },
lineHeight: 18,
tabSize: 2,
quickSuggestions: false,
parameterHints: { enabled: false },
codeLens: false,
links: false,
colorDecorators: false,
occurrencesHighlight: 'off',
renderValidationDecorations: 'off',
stickyScroll: { enabled: false },
domReadOnly: true,
cursorStyle: 'line',
fixedOverflowWidgets: true
}}
theme={theme}
className="!bg-transparent"
/>
</div>
</div>
);
});
CodeSnippet.displayName = 'CodeSnippet';