154 lines
5.2 KiB
TypeScript
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;
|