130 lines
3.9 KiB
TypeScript
130 lines
3.9 KiB
TypeScript
import React, { useState } from "react";
|
|
import Editor from "@monaco-editor/react";
|
|
import { upload } from "../../../assets/icons/input";
|
|
import { cn } from "../../../lib/cn";
|
|
import { DropDownList } from "../../../components/drop-down-list/DropDownList";
|
|
|
|
const languageMap: Record<string, string> = {
|
|
c: "cpp",
|
|
cpp: "cpp",
|
|
java: "java",
|
|
python: "python",
|
|
pascal: "pascal",
|
|
kotlin: "kotlin",
|
|
csharp: "csharp"
|
|
};
|
|
|
|
const CodeEditor: React.FC = () => {
|
|
const [language, setLanguage] = useState<string>("cpp");
|
|
const [code, setCode] = useState<string>("");
|
|
const [isDragging, setIsDragging] = useState<boolean>(false);
|
|
|
|
|
|
const items = [
|
|
{ value: "c", text: "C" },
|
|
{ value: "cpp", text: "C++" },
|
|
{ value: "java", text: "Java" },
|
|
{ value: "python", text: "Python" },
|
|
{ value: "pascal", text: "Pascal" },
|
|
{ value: "kotlin", text: "Kotlin" },
|
|
{ value: "csharp", text: "C#" },
|
|
];
|
|
|
|
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) }} />
|
|
|
|
<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;
|