github-actions[bot]
Deploy demo from GitHub Actions - 2025-12-24 02:23:20
6cdce85
'use client';
import { useRef, useCallback } from 'react';
import Editor, { OnMount, OnChange } from '@monaco-editor/react';
import type * as Monaco from 'monaco-editor';
import { Loader2 } from 'lucide-react';
interface CodeEditorProps {
value: string;
onChange: (value: string) => void;
language?: string;
readOnly?: boolean;
height?: string;
className?: string;
}
export function CodeEditor({
value,
onChange,
language = 'python',
readOnly = false,
height = '100%',
className,
}: CodeEditorProps) {
const editorRef = useRef<Monaco.editor.IStandaloneCodeEditor | null>(null);
const handleEditorMount: OnMount = useCallback((editor) => {
editorRef.current = editor;
// Don't auto-focus to prevent unwanted page scroll when selecting problems
}, []);
const handleChange: OnChange = useCallback((val) => {
onChange(val || '');
}, [onChange]);
return (
<div className={className} style={{ height, minHeight: '300px' }}>
<Editor
height="100%"
width="100%"
language={language}
value={value}
onChange={handleChange}
onMount={handleEditorMount}
theme="quantum-dark"
loading={
<div className="flex items-center justify-center h-full bg-zinc-900">
<Loader2 className="w-6 h-6 animate-spin text-teal-500" />
</div>
}
beforeMount={(monaco) => {
monaco.editor.defineTheme('quantum-dark', {
base: 'vs-dark',
inherit: true,
rules: [
{ token: 'comment', foreground: '71717a', fontStyle: 'italic' },
{ token: 'keyword', foreground: 'c4b5fd' },
{ token: 'string', foreground: '86efac' },
{ token: 'number', foreground: 'c4b5fd' },
{ token: 'type', foreground: '93c5fd' },
{ token: 'function', foreground: '93c5fd' },
{ token: 'variable', foreground: 'd4d4d8' },
{ token: 'operator', foreground: 'f0abfc' },
{ token: 'delimiter', foreground: 'a1a1aa' },
],
colors: {
'editor.background': '#18181b',
'editor.foreground': '#d4d4d8',
'editor.lineHighlightBackground': '#27272a',
'editor.selectionBackground': '#0d9488aa',
'editor.inactiveSelectionBackground': '#27272a',
'editorCursor.foreground': '#14b8a6',
'editorLineNumber.foreground': '#52525b',
'editorLineNumber.activeForeground': '#a1a1aa',
'editorIndentGuide.background': '#27272a',
'editorIndentGuide.activeBackground': '#3f3f46',
'editor.selectionHighlightBackground': '#0d94882a',
'editorBracketMatch.background': '#0d94884a',
'editorBracketMatch.border': '#14b8a6',
'scrollbar.shadow': '#00000000',
'scrollbarSlider.background': '#3f3f4680',
'scrollbarSlider.hoverBackground': '#52525b80',
'scrollbarSlider.activeBackground': '#71717a80',
},
});
}}
options={{
readOnly,
fontSize: 14,
fontFamily: "'JetBrains Mono', Consolas, 'Courier New', monospace",
fontLigatures: true,
lineHeight: 1.6,
padding: { top: 16, bottom: 16 },
minimap: { enabled: false },
scrollBeyondLastLine: false,
automaticLayout: true,
tabSize: 4,
insertSpaces: true,
wordWrap: 'on',
lineNumbers: 'on',
glyphMargin: false,
folding: true,
lineDecorationsWidth: 8,
lineNumbersMinChars: 4,
renderLineHighlight: 'line',
cursorBlinking: 'smooth',
cursorSmoothCaretAnimation: 'on',
smoothScrolling: true,
contextmenu: true,
quickSuggestions: true,
suggestOnTriggerCharacters: true,
acceptSuggestionOnEnter: 'on',
formatOnPaste: true,
formatOnType: true,
bracketPairColorization: { enabled: true },
}}
/>
</div>
);
}