| 'use client'; |
|
|
| import { useEffect, useRef } from 'react'; |
| import Editor from '@monaco-editor/react'; |
|
|
| interface CodeEditorProps { |
| code: string; |
| language: string; |
| onChange?: (value: string) => void; |
| readOnly?: boolean; |
| } |
|
|
| export default function CodeEditor({ code, language, onChange, readOnly = false }: CodeEditorProps) { |
| const editorRef = useRef<any>(null); |
| const lastFormattedCodeRef = useRef<string>(''); |
| const formatTimeoutRef = useRef<NodeJS.Timeout | null>(null); |
|
|
| |
| const getMonacoLanguage = (lang: string): string => { |
| const languageMap: Record<string, string> = { |
| 'html': 'html', |
| 'gradio': 'python', |
| 'streamlit': 'python', |
| 'transformers.js': 'html', |
| 'react': 'javascriptreact', |
| 'comfyui': 'json', |
| }; |
| return languageMap[lang] || 'plaintext'; |
| }; |
|
|
| const handleEditorDidMount = (editor: any) => { |
| editorRef.current = editor; |
| }; |
|
|
| |
| useEffect(() => { |
| if (editorRef.current && code && code.length > 100) { |
| |
| if (formatTimeoutRef.current) { |
| clearTimeout(formatTimeoutRef.current); |
| } |
| |
| |
| if (code !== lastFormattedCodeRef.current) { |
| |
| formatTimeoutRef.current = setTimeout(() => { |
| if (editorRef.current) { |
| editorRef.current.getAction('editor.action.formatDocument')?.run(); |
| lastFormattedCodeRef.current = code; |
| } |
| }, 1000); |
| } |
| } |
| |
| return () => { |
| if (formatTimeoutRef.current) { |
| clearTimeout(formatTimeoutRef.current); |
| } |
| }; |
| }, [code]); |
|
|
| return ( |
| <div className="h-full overflow-hidden bg-[#1e1e1e]"> |
| <Editor |
| height="100%" |
| language={getMonacoLanguage(language)} |
| value={code} |
| onChange={(value) => onChange && onChange(value || '')} |
| theme="vs-dark" |
| options={{ |
| readOnly, |
| minimap: { enabled: true }, |
| fontSize: 14, |
| fontFamily: "'SF Mono', 'JetBrains Mono', 'Menlo', 'Monaco', 'Courier New', monospace", |
| wordWrap: 'off', |
| lineNumbers: 'on', |
| lineNumbersMinChars: 3, |
| glyphMargin: false, |
| folding: true, |
| lineDecorationsWidth: 10, |
| scrollBeyondLastLine: false, |
| automaticLayout: true, |
| tabSize: 2, |
| insertSpaces: true, |
| padding: { top: 16, bottom: 16 }, |
| lineHeight: 22, |
| letterSpacing: 0.5, |
| renderLineHighlight: 'line', |
| formatOnPaste: true, |
| formatOnType: false, |
| scrollbar: { |
| verticalScrollbarSize: 10, |
| horizontalScrollbarSize: 10, |
| }, |
| }} |
| onMount={handleEditorDidMount} |
| /> |
| </div> |
| ); |
| } |
|
|
|
|