139 lines
5.1 KiB
TypeScript
139 lines
5.1 KiB
TypeScript
import React, { FC } from "react";
|
||
import { cn } from "../../../lib/cn";
|
||
import LaTextContainer from "./LaTextContainer";
|
||
import { CopyIcon } from "../../../assets/icons/missions";
|
||
// import FullLatexRenderer from "./FullLatexRenderer";
|
||
|
||
|
||
|
||
import { useState } from "react";
|
||
|
||
interface CopyableDivPropd{
|
||
content: string;
|
||
}
|
||
|
||
const CopyableDiv: FC<CopyableDivPropd> = ({ content }) => {
|
||
const [hovered, setHovered] = useState(false);
|
||
|
||
const handleCopy = async () => {
|
||
try {
|
||
await navigator.clipboard.writeText(content);
|
||
alert("Скопировано!");
|
||
} catch (err) {
|
||
console.error("Ошибка копирования:", err);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div
|
||
className="relative p-[10px] bg-liquid-lighter rounded-[10px] whitespace-pre-line"
|
||
onMouseEnter={() => setHovered(true)}
|
||
onMouseLeave={() => setHovered(false)}
|
||
>
|
||
{content}
|
||
|
||
|
||
<img
|
||
src={CopyIcon}
|
||
alt="copy"
|
||
className={cn("absolute top-2 right-2 w-6 h-6 cursor-pointer opacity-0 transition-all duration-300 hover:h-7 hover:w-7 hover:top-[6px] hover:right-[6px]",
|
||
hovered && " opacity-100"
|
||
)}
|
||
onClick={handleCopy}
|
||
/>
|
||
|
||
</div>
|
||
);
|
||
}
|
||
|
||
|
||
|
||
|
||
export interface StatementData {
|
||
id?: number;
|
||
name?: string;
|
||
tags?: string[];
|
||
timeLimit?: number;
|
||
memoryLimit?: number;
|
||
legend?: string;
|
||
input?: string;
|
||
output?: string;
|
||
sampleTests?: { input: string; output: string }[];
|
||
notes?: string;
|
||
html?: string;
|
||
mediaFiles?: { id: number; fileName: string; mediaUrl: string }[];
|
||
}
|
||
|
||
function extractDivByClass(html: string, className: string): string {
|
||
const parser = new DOMParser();
|
||
const doc = parser.parseFromString(html, "text/html");
|
||
const div = doc.querySelector(`div.${className}`);
|
||
return div ? div.outerHTML : "";
|
||
}
|
||
|
||
const Statement: React.FC<StatementData> = ({
|
||
id,
|
||
name,
|
||
tags,
|
||
timeLimit = 1000,
|
||
memoryLimit = 256 * 1024 * 1024,
|
||
legend = "",
|
||
input = "",
|
||
output = "",
|
||
sampleTests = [],
|
||
notes = "",
|
||
html = "",
|
||
mediaFiles,
|
||
}) => {
|
||
|
||
return (
|
||
<div className="flex flex-col w-full h-full medium-scrollbar pl-[20px] pr-[12px] gap-[20px] text-liquid-white overflow-y-scroll thin-dark-scrollbar [scrollbar-gutter:stable]">
|
||
<div>
|
||
<p className="h-[50px] text-[40px] font-bold text-liquid-white">{name}</p>
|
||
<p className="h-[23px] text-[18px] font-bold text-liquid-light">Задача #{id}</p>
|
||
</div>
|
||
|
||
<div className="flex gap-[10px] w-full flex-wrap">
|
||
{tags && tags.map((v, i) => <div key={i} className="px-[16px] py-[8px] rounded-full bg-liquid-lighter ">{v}</div>)}
|
||
</div>
|
||
|
||
<div className="flex flex-col">
|
||
<p className="text-liquid-white h-[20px] text-[18px] font-bold"><span className="text-liquid-light">ограничение по времени на тест:</span> {timeLimit / 1000} секунда</p>
|
||
<p className="text-liquid-white h-[20px] text-[18px] font-bold"><span className="text-liquid-light">ограничение по памяти на тест:</span> {memoryLimit / 1024 / 1024} мегабайт</p>
|
||
<p className="text-liquid-white h-[20px] text-[18px] font-bold"><span className="text-liquid-light">ввод:</span> стандартный ввод</p>
|
||
<p className="text-liquid-white h-[20px] text-[18px] font-bold"><span className="text-liquid-light">вывод:</span> стандартный вывод</p>
|
||
</div>
|
||
|
||
<div className="flex flex-col gap-[10px] mt-[20px]">
|
||
<LaTextContainer html={extractDivByClass(html, "legend")} latex={legend} mediaFiles={mediaFiles}/>
|
||
</div>
|
||
<div className="flex flex-col gap-[10px]">
|
||
<LaTextContainer html={extractDivByClass(html, "input-specification")} latex={input} mediaFiles={mediaFiles}/>
|
||
</div>
|
||
<div className="flex flex-col gap-[10px]">
|
||
<LaTextContainer html={extractDivByClass(html, "output-specification")} latex={output} mediaFiles={mediaFiles}/>
|
||
</div>
|
||
|
||
<div className="flex flex-col gap-[10px]">
|
||
<div className="text-[18px] font-bold">{sampleTests.length == 1 ? "Пример" : "Примеры"}</div>
|
||
|
||
|
||
{sampleTests.map((v, i) =>
|
||
<div key={i} className="flex flex-col gap-[10px]">
|
||
<div className="text-[14px] font-bold">Входные данные</div>
|
||
<CopyableDiv content={v.input}/>
|
||
<div className="text-[14px] font-bold">Выходные данные</div>
|
||
<CopyableDiv content={v.output}/>
|
||
</div>
|
||
)}
|
||
</div>
|
||
<div className="flex flex-col gap-[10px]">
|
||
<LaTextContainer html={extractDivByClass(html, "note")} latex={notes} mediaFiles={mediaFiles}/>
|
||
<div>Автор: Jacks</div>
|
||
</div>
|
||
</div>
|
||
|
||
);
|
||
};
|
||
|
||
export default Statement; |