Files
LiquidCode_Frontend/src/views/mission/codeeditor/CodeEditor.tsx
Виталий Лавшонок 02de330034 add filters
2025-12-10 00:04:20 +03:00

154 lines
5.2 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import Editor from '@monaco-editor/react';
import { upload } from '../../../assets/icons/input';
import { cn } from '../../../lib/cn';
import { DropDownList } from '../../../components/input/DropDownList';
const languageMap: Record<string, string> = {
c: 'cpp',
'C++': 'cpp',
java: 'java',
python: 'python',
pascal: 'pascal',
kotlin: 'kotlin',
csharp: 'csharp',
};
export interface CodeEditorProps {
onChange: (value: string) => void;
onChangeLanguage: (value: string) => void;
}
const CodeEditor: React.FC<CodeEditorProps> = ({
onChange,
onChangeLanguage,
}) => {
const [language, setLanguage] = useState<string>('C++');
const [code, setCode] = useState<string>('');
const [isDragging, setIsDragging] = useState<boolean>(false);
const items = [
{ value: 'c', text: 'C' },
{ value: 'C++', text: 'C++' },
{ value: 'java', text: 'Java' },
{ value: 'python', text: 'Python' },
{ value: 'pascal', text: 'Pascal' },
{ value: 'kotlin', text: 'Kotlin' },
{ value: 'csharp', text: 'C#' },
];
useEffect(() => {
onChange(code);
}, [code]);
useEffect(() => {
onChangeLanguage(language);
}, [language]);
const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (event) => {
const text = event.target?.result;
if (typeof text === 'string') setCode(text);
};
reader.readAsText(file);
e.target.value = '';
};
const handleDrop = (e: React.DragEvent<HTMLLabelElement>) => {
e.preventDefault();
setIsDragging(false);
const droppedFile = e.dataTransfer.files[0];
if (!droppedFile) return;
const reader = new FileReader();
reader.onload = (event) => {
const text = event.target?.result;
if (typeof text === 'string') setCode(text);
};
reader.readAsText(droppedFile);
};
const handleDragOver = (e: React.DragEvent<HTMLLabelElement>) => {
e.preventDefault(); // обязательно
};
const handleDragEnter = (e: React.DragEvent<HTMLLabelElement>) => {
e.preventDefault();
setIsDragging(true);
};
const handleDragLeave = (e: React.DragEvent<HTMLLabelElement>) => {
e.preventDefault();
setIsDragging(false);
};
return (
<div className="flex flex-col w-full h-full">
{/* Панель выбора языка и загрузки файла */}
<div className="flex items-center justify-between py-3 ">
<div className="flex items-center gap-[20px]">
<DropDownList
items={items}
onChange={(v) => {
setLanguage(v);
}}
defaultState={{ value: 'C++', text: 'C++' }}
/>
<label
className={cn(
'h-[40px] w-[250px] rounded-[10px] px-[16px] relative flex items-center cursor-pointer transition-all bg-liquid-lighter outline-dashed outline-[2px] outline-transparent active:scale-[95%]',
isDragging && 'outline-blue-500 ',
)}
onDrop={handleDrop}
onDragOver={handleDragOver}
onDragEnter={handleDragEnter}
onDragLeave={handleDragLeave}
>
<span className="text-[18px] text-liquid-white font-bold pointer-events-none">
{'Загрузить решение'}
</span>
<img
src={upload}
className="absolute right-[16px] pointer-events-none"
/>
<input
type="file"
onChange={(e) => handleFileUpload(e)}
className="hidden"
/>
</label>
</div>
</div>
{/* Monaco Editor */}
<div className="bg-[#1E1E1E] py-[10px] h-full rounded-[10px]">
<Editor
width="100%"
height="100%"
language={languageMap[language]}
value={code}
onChange={(value) => setCode(value ?? '')}
theme="vs-dark"
options={{
fontSize: 14,
minimap: { enabled: false },
automaticLayout: true,
quickSuggestions: true,
suggestOnTriggerCharacters: true,
tabSize: 4,
insertSpaces: true,
detectIndentation: false,
autoIndent: 'full',
}}
/>
</div>
</div>
);
};
export default CodeEditor;