statement
This commit is contained in:
@@ -5,7 +5,7 @@ import { Route, Routes } from "react-router-dom";
|
||||
// import { Input } from "./components/input/Input";
|
||||
// import { Switch } from "./components/switch/Switch";
|
||||
import Home from "./pages/Home";
|
||||
import CodeEditor from "./views/mission/codeeditor/CodeEditor";
|
||||
// import CodeEditor from "./views/mission/codeeditor/CodeEditor";
|
||||
import Statement from "./views/mission/statement/Statement";
|
||||
import MissionStatement from "./views/mission/statement/Mission";
|
||||
import Mission from "./pages/Mission";
|
||||
@@ -19,7 +19,7 @@ function App() {
|
||||
<Route path="/home/*" element={<Home />} />
|
||||
<Route path="/mission/:missionId" element={<Mission />} />
|
||||
<Route path="/upload" element={<UploadMissionForm/>}/>
|
||||
<Route path="/editor" element={<div className="box-border p-[50px] w-full h-[800px] relative bg-red-8001"><CodeEditor /></div>} />
|
||||
{/* <Route path="/editor" element={<div className="box-border p-[50px] w-full h-[800px] relative bg-red-8001"><CodeEditor /></div>} /> */}
|
||||
<Route path="/statement" element={<div className="box-border p-[50px] w-full h-[800px] relative bg-red-8001"><Statement /></div>} />
|
||||
<Route path="*" element={<MissionStatement />} />
|
||||
</Routes>
|
||||
|
||||
@@ -1,24 +1,93 @@
|
||||
import { useParams, Navigate } from 'react-router-dom';
|
||||
|
||||
|
||||
import CodeEditor from '../views/mission/codeeditor/CodeEditor';
|
||||
import Statement, { StatementData } from '../views/mission/statement/Statement';
|
||||
import { PrimaryButton } from '../components/button/PrimaryButton';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useAppDispatch, useAppSelector } from '../redux/hooks';
|
||||
import { submitMission } from '../redux/slices/submit';
|
||||
import { fetchMissionById } from '../redux/slices/missions';
|
||||
|
||||
const Mission = () => {
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
// Получаем параметры из URL
|
||||
const { missionId } = useParams<{ missionId: string }>();
|
||||
const mission = useAppSelector((state) => state.missions.currentMission);
|
||||
const missionIdNumber = Number(missionId);
|
||||
|
||||
const [code, setCode] = useState<string>("");
|
||||
const [language, setLanguage] = useState<string>("");
|
||||
|
||||
// Если missionId нет, редиректим на /home
|
||||
if (!missionId) {
|
||||
|
||||
// Если missionId нет или не число — редиректим
|
||||
if (!missionId || isNaN(missionIdNumber)) {
|
||||
return <Navigate to="/home" replace />;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchMissionById(missionIdNumber));
|
||||
}, []);
|
||||
|
||||
if (!mission || !mission.statements || mission.statements.length === 0) {
|
||||
return <div>Загрузка или миссия не найдена...</div>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const statementRaw = mission.statements[0];
|
||||
let statementData: StatementData = { id: mission.id };
|
||||
|
||||
try {
|
||||
const statementTexts = JSON.parse(statementRaw.statementTexts["problem-properties.json"]);
|
||||
// console.log(mission);
|
||||
statementData = {
|
||||
id: statementRaw.id,
|
||||
legend: statementTexts.legend,
|
||||
timeLimit: statementTexts.timeLimit,
|
||||
output: statementTexts.output,
|
||||
input: statementTexts.input,
|
||||
sampleTests: statementTexts.sampleTests,
|
||||
name: statementTexts.name,
|
||||
memoryLimit: statementTexts.memoryLimit,
|
||||
tags: mission.tags,
|
||||
notes: statementTexts.notes,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error("Ошибка парсинга statementTexts:", err);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="w-full bg-liquid-background grid grid-cols-[250px,1fr,250px] divide-x-[1px] divide-liquid-lighter">
|
||||
<div className="w-full bg-liquid-background grid grid-cols-[minmax(0,1fr),minmax(0,1fr)] h-full gap-[20px] relative">
|
||||
<div><Statement
|
||||
id={missionIdNumber}
|
||||
{...statementData}
|
||||
|
||||
<div className="bg-red-300 w-full h-full">
|
||||
{missionId}
|
||||
/>
|
||||
</div>
|
||||
<div className=' grid grid-rows-[1fr,200px] grid-flow-row h-full w-full gap-[20px]'>
|
||||
<div className='w-full relative'>
|
||||
<CodeEditor
|
||||
onChange={(value: string) => { setCode(value); }}
|
||||
onChangeLanguage={((value: string) => { setLanguage(value); })}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<PrimaryButton text='Отправить' onClick={() => {
|
||||
dispatch(submitMission({
|
||||
missionId: missionIdNumber,
|
||||
language: language,
|
||||
languageVersion: "latest",
|
||||
sourceCode: code,
|
||||
contestId: null,
|
||||
|
||||
}))
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute top-0 bottom-0 left-1/2 w-[1px] bg-liquid-lighter transform -translate-x-1/2"></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -41,7 +41,7 @@ const initialState: MissionsState = {
|
||||
export const fetchMissions = createAsyncThunk(
|
||||
"missions/fetchMissions",
|
||||
async (
|
||||
{ page = 0, pageSize = 10, tags }: { page?: number; pageSize?: number; tags?: string[] },
|
||||
{ page = 0, pageSize = 10, tags = [] }: { page?: number; pageSize?: number; tags?: string[] },
|
||||
{ rejectWithValue }
|
||||
) => {
|
||||
try {
|
||||
@@ -120,6 +120,7 @@ const missionsSlice = createSlice({
|
||||
});
|
||||
builder.addCase(fetchMissionById.fulfilled, (state, action: PayloadAction<Mission>) => {
|
||||
state.status = "successful";
|
||||
console.log(action.payload);
|
||||
state.currentMission = action.payload;
|
||||
});
|
||||
builder.addCase(fetchMissionById.rejected, (state, action: PayloadAction<any>) => {
|
||||
|
||||
161
src/redux/slices/submit.ts
Normal file
161
src/redux/slices/submit.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
|
||||
import axios from "../../axios";
|
||||
|
||||
// Типы данных
|
||||
export interface Submit {
|
||||
id?: number;
|
||||
missionId: number;
|
||||
language: string;
|
||||
languageVersion: string;
|
||||
sourceCode: string;
|
||||
contestId: number | null;
|
||||
}
|
||||
|
||||
export interface SubmitStatus {
|
||||
SubmitId: number;
|
||||
State: string;
|
||||
ErrorCode: string;
|
||||
Message: string;
|
||||
CurrentTest: number;
|
||||
AmountOfTests: number;
|
||||
}
|
||||
|
||||
interface SubmitState {
|
||||
submits: Submit[];
|
||||
currentSubmit?: Submit;
|
||||
status: "idle" | "loading" | "successful" | "failed";
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
// Начальное состояние
|
||||
const initialState: SubmitState = {
|
||||
submits: [],
|
||||
currentSubmit: undefined,
|
||||
status: "idle",
|
||||
error: null,
|
||||
};
|
||||
|
||||
// AsyncThunk: Отправка решения
|
||||
export const submitMission = createAsyncThunk(
|
||||
"submit/submitMission",
|
||||
async (submitData: Submit, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await axios.post("/submits", submitData);
|
||||
return response.data;
|
||||
} catch (err: any) {
|
||||
return rejectWithValue(err.response?.data?.message || "Submit failed");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// AsyncThunk: Получить все свои отправки
|
||||
export const fetchMySubmits = createAsyncThunk(
|
||||
"submit/fetchMySubmits",
|
||||
async (_, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await axios.get("/submits/my");
|
||||
return response.data as Submit[];
|
||||
} catch (err: any) {
|
||||
return rejectWithValue(err.response?.data?.message || "Failed to fetch submits");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// AsyncThunk: Получить конкретную отправку по ID
|
||||
export const fetchSubmitById = createAsyncThunk(
|
||||
"submit/fetchSubmitById",
|
||||
async (id: number, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await axios.get(`/submits/${id}`);
|
||||
return response.data as Submit;
|
||||
} catch (err: any) {
|
||||
return rejectWithValue(err.response?.data?.message || "Failed to fetch submit");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// AsyncThunk: Получить свои отправки для конкретной миссии
|
||||
export const fetchMySubmitsByMission = createAsyncThunk(
|
||||
"submit/fetchMySubmitsByMission",
|
||||
async (missionId: number, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await axios.get(`/submits/my/mission/${missionId}`);
|
||||
return response.data as Submit[];
|
||||
} catch (err: any) {
|
||||
return rejectWithValue(err.response?.data?.message || "Failed to fetch mission submits");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Slice
|
||||
const submitSlice = createSlice({
|
||||
name: "submit",
|
||||
initialState,
|
||||
reducers: {
|
||||
clearCurrentSubmit: (state) => {
|
||||
state.currentSubmit = undefined;
|
||||
state.status = "idle";
|
||||
state.error = null;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
// Отправка решения
|
||||
builder.addCase(submitMission.pending, (state) => {
|
||||
state.status = "loading";
|
||||
state.error = null;
|
||||
});
|
||||
builder.addCase(submitMission.fulfilled, (state, action: PayloadAction<Submit>) => {
|
||||
state.status = "successful";
|
||||
state.submits.push(action.payload);
|
||||
});
|
||||
builder.addCase(submitMission.rejected, (state, action: PayloadAction<any>) => {
|
||||
state.status = "failed";
|
||||
state.error = action.payload;
|
||||
});
|
||||
|
||||
// Получить все свои отправки
|
||||
builder.addCase(fetchMySubmits.pending, (state) => {
|
||||
state.status = "loading";
|
||||
state.error = null;
|
||||
});
|
||||
builder.addCase(fetchMySubmits.fulfilled, (state, action: PayloadAction<Submit[]>) => {
|
||||
state.status = "successful";
|
||||
state.submits = action.payload;
|
||||
});
|
||||
builder.addCase(fetchMySubmits.rejected, (state, action: PayloadAction<any>) => {
|
||||
state.status = "failed";
|
||||
state.error = action.payload;
|
||||
});
|
||||
|
||||
// Получить отправку по ID
|
||||
builder.addCase(fetchSubmitById.pending, (state) => {
|
||||
state.status = "loading";
|
||||
state.error = null;
|
||||
});
|
||||
builder.addCase(fetchSubmitById.fulfilled, (state, action: PayloadAction<Submit>) => {
|
||||
state.status = "successful";
|
||||
state.currentSubmit = action.payload;
|
||||
});
|
||||
builder.addCase(fetchSubmitById.rejected, (state, action: PayloadAction<any>) => {
|
||||
state.status = "failed";
|
||||
state.error = action.payload;
|
||||
});
|
||||
|
||||
// Получить отправки по миссии
|
||||
builder.addCase(fetchMySubmitsByMission.pending, (state) => {
|
||||
state.status = "loading";
|
||||
state.error = null;
|
||||
});
|
||||
builder.addCase(fetchMySubmitsByMission.fulfilled, (state, action: PayloadAction<Submit[]>) => {
|
||||
state.status = "successful";
|
||||
state.submits = action.payload;
|
||||
});
|
||||
builder.addCase(fetchMySubmitsByMission.rejected, (state, action: PayloadAction<any>) => {
|
||||
state.status = "failed";
|
||||
state.error = action.payload;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const { clearCurrentSubmit } = submitSlice.actions;
|
||||
export const submitReducer = submitSlice.reducer;
|
||||
@@ -2,6 +2,7 @@ import { configureStore } from "@reduxjs/toolkit";
|
||||
import { authReducer } from "./slices/auth";
|
||||
import { storeReducer } from "./slices/store";
|
||||
import { missionsReducer } from "./slices/missions";
|
||||
import { submitReducer } from "./slices/submit";
|
||||
|
||||
|
||||
// использование
|
||||
@@ -19,6 +20,7 @@ export const store = configureStore({
|
||||
auth: authReducer,
|
||||
store: storeReducer,
|
||||
missions: missionsReducer,
|
||||
submin: submitReducer,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ const Menu = () => {
|
||||
{text: "Группы", href: "/home/groups", icon: Users, page: "groups" },
|
||||
{text: "Контесты", href: "/home/contests", icon: Cup, page: "contests" },
|
||||
{text: "Аккаунт", href: "/home/account", icon: Account, page: "account" },
|
||||
{text: "Загрузка", href: "/upload", icon: Account, page: "p" },
|
||||
];
|
||||
const activePage = useAppSelector((state) => state.store.menu.activePage);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { cn } from "../../../lib/cn";
|
||||
import { IconError, IconSuccess } from "../../../assets/icons/missions";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
export interface MissionItemProps {
|
||||
id: number;
|
||||
@@ -29,14 +30,18 @@ export function formatBytesToMB(bytes: number): string {
|
||||
const MissionItem: React.FC<MissionItemProps> = ({
|
||||
id, name, difficulty, timeLimit, memoryLimit, type, status
|
||||
}) => {
|
||||
console.log(id);
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div className={cn("h-[44px] w-full relative rounded-[10px] text-liquid-white",
|
||||
type == "first" ? "bg-liquid-lighter" : "bg-liquid-background",
|
||||
"grid grid-cols-[80px,1fr,1fr,60px,24px] grid-flow-col gap-[20px] px-[20px] box-border items-center",
|
||||
status == "error" && "border-l-[11px] border-l-liquid-red pl-[9px]",
|
||||
status == "success" && "border-l-[11px] border-l-liquid-green pl-[9px]",
|
||||
)}>
|
||||
"cursor-pointer brightness-100 hover:brightness-125 transition-all duration-300",
|
||||
)}
|
||||
onClick={() => {navigate(`/mission/${id}`)}}
|
||||
>
|
||||
<div className="text-[18px] font-bold">
|
||||
#{id}
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import MissionItem from "./MissionItem";
|
||||
import { SecondaryButton } from "../../../components/button/SecondaryButton";
|
||||
import { useAppDispatch } from "../../../redux/hooks";
|
||||
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
|
||||
import { useEffect } from "react";
|
||||
import { setMenuActivePage } from "../../../redux/slices/store";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { fetchMissions } from "../../../redux/slices/missions";
|
||||
|
||||
|
||||
export interface Mission {
|
||||
@@ -17,457 +19,18 @@ export interface Mission {
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
|
||||
const Missions = () => {
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const naivgate = useNavigate();
|
||||
|
||||
const missions: Mission[] = [
|
||||
{
|
||||
"id": 1,
|
||||
"authorId": 1,
|
||||
"name": "Todo List App",
|
||||
"difficulty": "Easy",
|
||||
"tags": ["react", "state", "list"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:13.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:13.000Z"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"authorId": 1,
|
||||
"name": "Search Filter Component",
|
||||
"difficulty": "Medium",
|
||||
"tags": ["filter", "props", "hooks"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:14.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:14.000Z"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"authorId": 1,
|
||||
"name": "User Card List",
|
||||
"difficulty": "Easy",
|
||||
"tags": ["components", "props", "array"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:15.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:15.000Z"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"authorId": 1,
|
||||
"name": "Theme Switcher",
|
||||
"difficulty": "Medium",
|
||||
"tags": ["context", "theme", "hooks"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:16.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:16.000Z"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"authorId": 1,
|
||||
"name": "Debounced Input",
|
||||
"difficulty": "Hard",
|
||||
"tags": ["debounce", "hooks", "events"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:17.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:17.000Z"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"authorId": 1,
|
||||
"name": "Pagination Component",
|
||||
"difficulty": "Medium",
|
||||
"tags": ["pagination", "array", "state"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:18.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:18.000Z"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"authorId": 1,
|
||||
"name": "Modal Window",
|
||||
"difficulty": "Easy",
|
||||
"tags": ["ui", "portal", "events"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:19.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:19.000Z"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"authorId": 1,
|
||||
"name": "Form Validation",
|
||||
"difficulty": "Hard",
|
||||
"tags": ["form", "validation", "hooks"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:20.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:20.000Z"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"authorId": 1,
|
||||
"name": "Countdown Timer",
|
||||
"difficulty": "Medium",
|
||||
"tags": ["timer", "hooks", "state"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:21.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:21.000Z"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"authorId": 1,
|
||||
"name": "Drag And Drop List",
|
||||
"difficulty": "Hard",
|
||||
"tags": ["dragdrop", "array", "events"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:22.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:22.000Z"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"authorId": 1,
|
||||
"name": "Custom Hook Use Fetch",
|
||||
"difficulty": "Medium",
|
||||
"tags": ["hook", "fetch", "async"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:23.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:23.000Z"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"authorId": 1,
|
||||
"name": "Infinite Scroll",
|
||||
"difficulty": "Hard",
|
||||
"tags": ["scroll", "pagination", "api"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:24.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:24.000Z"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"authorId": 1,
|
||||
"name": "Responsive Navbar",
|
||||
"difficulty": "Easy",
|
||||
"tags": ["css", "layout", "responsive"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:25.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:25.000Z"
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"authorId": 1,
|
||||
"name": "Accordion Component",
|
||||
"difficulty": "Easy",
|
||||
"tags": ["ui", "state", "events"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:26.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:26.000Z"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"authorId": 1,
|
||||
"name": "File Upload Preview",
|
||||
"difficulty": "Hard",
|
||||
"tags": ["file", "events", "preview"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:27.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:27.000Z"
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"authorId": 1,
|
||||
"name": "Dark Mode Toggle",
|
||||
"difficulty": "Easy",
|
||||
"tags": ["theme", "context", "localStorage"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:28.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:28.000Z"
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"authorId": 1,
|
||||
"name": "Realtime Clock",
|
||||
"difficulty": "Easy",
|
||||
"tags": ["date", "state", "interval"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:29.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:29.000Z"
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"authorId": 1,
|
||||
"name": "Chart With Recharts",
|
||||
"difficulty": "Medium",
|
||||
"tags": ["chart", "data", "props"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:30.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:30.000Z"
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"authorId": 1,
|
||||
"name": "Router Navigation",
|
||||
"difficulty": "Medium",
|
||||
"tags": ["router", "navigation", "hooks"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:31.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:31.000Z"
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
"authorId": 1,
|
||||
"name": "Data Table Sortable",
|
||||
"difficulty": "Hard",
|
||||
"tags": ["table", "sort", "filter"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:32.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:32.000Z"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"authorId": 1,
|
||||
"name": "Todo List App",
|
||||
"difficulty": "Easy",
|
||||
"tags": ["react", "state", "list"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:13.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:13.000Z"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"authorId": 1,
|
||||
"name": "Search Filter Component",
|
||||
"difficulty": "Medium",
|
||||
"tags": ["filter", "props", "hooks"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:14.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:14.000Z"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"authorId": 1,
|
||||
"name": "User Card List",
|
||||
"difficulty": "Easy",
|
||||
"tags": ["components", "props", "array"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:15.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:15.000Z"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"authorId": 1,
|
||||
"name": "Theme Switcher",
|
||||
"difficulty": "Medium",
|
||||
"tags": ["context", "theme", "hooks"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:16.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:16.000Z"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"authorId": 1,
|
||||
"name": "Debounced Input",
|
||||
"difficulty": "Hard",
|
||||
"tags": ["debounce", "hooks", "events"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:17.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:17.000Z"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"authorId": 1,
|
||||
"name": "Pagination Component",
|
||||
"difficulty": "Medium",
|
||||
"tags": ["pagination", "array", "state"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:18.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:18.000Z"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"authorId": 1,
|
||||
"name": "Modal Window",
|
||||
"difficulty": "Easy",
|
||||
"tags": ["ui", "portal", "events"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:19.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:19.000Z"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"authorId": 1,
|
||||
"name": "Form Validation",
|
||||
"difficulty": "Hard",
|
||||
"tags": ["form", "validation", "hooks"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:20.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:20.000Z"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"authorId": 1,
|
||||
"name": "Countdown Timer",
|
||||
"difficulty": "Medium",
|
||||
"tags": ["timer", "hooks", "state"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:21.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:21.000Z"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"authorId": 1,
|
||||
"name": "Drag And Drop List",
|
||||
"difficulty": "Hard",
|
||||
"tags": ["dragdrop", "array", "events"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:22.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:22.000Z"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"authorId": 1,
|
||||
"name": "Custom Hook Use Fetch",
|
||||
"difficulty": "Medium",
|
||||
"tags": ["hook", "fetch", "async"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:23.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:23.000Z"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"authorId": 1,
|
||||
"name": "Infinite Scroll",
|
||||
"difficulty": "Hard",
|
||||
"tags": ["scroll", "pagination", "api"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:24.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:24.000Z"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"authorId": 1,
|
||||
"name": "Responsive Navbar",
|
||||
"difficulty": "Easy",
|
||||
"tags": ["css", "layout", "responsive"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:25.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:25.000Z"
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"authorId": 1,
|
||||
"name": "Accordion Component",
|
||||
"difficulty": "Easy",
|
||||
"tags": ["ui", "state", "events"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:26.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:26.000Z"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"authorId": 1,
|
||||
"name": "File Upload Preview",
|
||||
"difficulty": "Hard",
|
||||
"tags": ["file", "events", "preview"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:27.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:27.000Z"
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"authorId": 1,
|
||||
"name": "Dark Mode Toggle",
|
||||
"difficulty": "Easy",
|
||||
"tags": ["theme", "context", "localStorage"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:28.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:28.000Z"
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"authorId": 1,
|
||||
"name": "Realtime Clock",
|
||||
"difficulty": "Easy",
|
||||
"tags": ["date", "state", "interval"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:29.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:29.000Z"
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"authorId": 1,
|
||||
"name": "Chart With Recharts",
|
||||
"difficulty": "Medium",
|
||||
"tags": ["chart", "data", "props"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:30.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:30.000Z"
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"authorId": 1,
|
||||
"name": "Router Navigation",
|
||||
"difficulty": "Medium",
|
||||
"tags": ["router", "navigation", "hooks"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:31.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:31.000Z"
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
"authorId": 1,
|
||||
"name": "Data Table Sortable",
|
||||
"difficulty": "Hard",
|
||||
"tags": ["table", "sort", "filter"],
|
||||
"timeLimit": 1000,
|
||||
"memoryLimit": 268435456,
|
||||
"createdAt": "2025-10-28T13:23:32.000Z",
|
||||
"updatedAt": "2025-10-28T13:23:32.000Z"
|
||||
}
|
||||
];
|
||||
const missions = useAppSelector((state) => state.missions.missions);
|
||||
|
||||
useEffect(() => {
|
||||
useEffect(() => {
|
||||
dispatch(setMenuActivePage("missions"))
|
||||
}, []);
|
||||
dispatch(fetchMissions({}))
|
||||
}, []);
|
||||
|
||||
|
||||
return (
|
||||
<div className=" h-full w-full box-border p-[20px] pt-[20px]">
|
||||
@@ -478,7 +41,7 @@ const Missions = () => {
|
||||
Задачи
|
||||
</div>
|
||||
<SecondaryButton
|
||||
onClick={() => {}}
|
||||
onClick={() => {naivgate("/upload")}}
|
||||
text="Создать задачу"
|
||||
className="absolute right-0"
|
||||
/>
|
||||
@@ -491,7 +54,19 @@ const Missions = () => {
|
||||
<div>
|
||||
|
||||
{missions.map((v, i) => (
|
||||
<MissionItem key={i} {...v} type={i % 2 == 0 ? "first" : "second"} status={i == 0 || i == 3 || i == 7 ? "success" : (i == 2 || i == 4 || i == 9 ? "error" : "empty")}/>
|
||||
<MissionItem
|
||||
key={i}
|
||||
id={v.id}
|
||||
authorId={v.authorId}
|
||||
name={v.name}
|
||||
difficulty={"Easy"}
|
||||
tags={v.tags}
|
||||
timeLimit={1000}
|
||||
memoryLimit={256 * 1024 * 1024}
|
||||
createdAt={v.createdAt}
|
||||
updatedAt={v.updatedAt}
|
||||
type={i % 2 == 0 ? "first" : "second"}
|
||||
status={i == 0 || i == 3 || i == 7 ? "success" : (i == 2 || i == 4 || i == 9 ? "error" : "empty")}/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Editor from "@monaco-editor/react";
|
||||
import { upload } from "../../../assets/icons/input";
|
||||
import { cn } from "../../../lib/cn";
|
||||
@@ -14,7 +14,12 @@ const languageMap: Record<string, string> = {
|
||||
csharp: "csharp"
|
||||
};
|
||||
|
||||
const CodeEditor: React.FC = () => {
|
||||
export interface CodeEditorProps {
|
||||
onChange: (value: string) => void;
|
||||
onChangeLanguage: (value: string) => void;
|
||||
}
|
||||
|
||||
const CodeEditor: React.FC<CodeEditorProps> = ({onChange, onChangeLanguage}) => {
|
||||
const [language, setLanguage] = useState<string>("cpp");
|
||||
const [code, setCode] = useState<string>("");
|
||||
const [isDragging, setIsDragging] = useState<boolean>(false);
|
||||
@@ -30,6 +35,13 @@ const CodeEditor: React.FC = () => {
|
||||
{ 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;
|
||||
|
||||
14
src/views/mission/statement/LaTextContainer.tsx
Normal file
14
src/views/mission/statement/LaTextContainer.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
|
||||
interface LaTextContainerProps {
|
||||
content: string;
|
||||
}
|
||||
|
||||
const LaTextContainer: React.FC<LaTextContainerProps> = ({ content }) => {
|
||||
|
||||
return <div>
|
||||
{content}
|
||||
</div>;
|
||||
};
|
||||
|
||||
export default LaTextContainer;
|
||||
@@ -1,58 +1,85 @@
|
||||
import React, { useState } from "react";
|
||||
import { cn } from "../../../lib/cn";
|
||||
import LaTextContainer from "./LaTextContainer";
|
||||
// import FullLatexRenderer from "./FullLatexRenderer";
|
||||
|
||||
const Statement: React.FC = () => {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const Statement: React.FC<StatementData> = ({
|
||||
id,
|
||||
name,
|
||||
tags,
|
||||
timeLimit = 1000,
|
||||
memoryLimit = 256 * 1024 * 1024,
|
||||
legend = "",
|
||||
input = "",
|
||||
output = "",
|
||||
sampleTests = [],
|
||||
notes = "",
|
||||
}) => {
|
||||
|
||||
const data = {
|
||||
"extraResources": {
|
||||
"example.01.mu": "TVXzATcgNg0KMSAyIDMgNCA1IDYgNw0KMSA4IDMNCjIgOQ0KMyAzDQoxIDMgOQ0KMiAxMA0KMyAxDQo="
|
||||
},
|
||||
"scoring": null,
|
||||
"notes": "Изначально очередь выглядит следующим образом:\r\n\r\n\\includegraphics{o1.png}\r\n\r\nВ первую минуту приходит студент с номером 8 и встает перед студентом с номером 3.\r\n\r\n\\includegraphics{o2.png}\r\n\r\nПотом студент с номером 9 встает в конец очереди.\r\n\r\n\\includegraphics{o3.png}\r\n\r\nСтудент с номером 3 уходит из очереди.\r\n\r\n\\includegraphics{o4.png}\r\n\r\nПотом он возвращается и становится перед студентом с номером 9.\r\n\r\n\\includegraphics{o5.png}\r\n\r\nПосле в конец очереди становится студент с номером 10.\r\n\r\n\\includegraphics{o6.png}\r\n\r\nИ студент с номером 1 уходит из очереди.\r\n\r\n\\includegraphics{o7.png}\r\n\r\nПосле $m$ событий очередь имеет следующий вид:\r\n\r\n\\includegraphics{o8.png}",
|
||||
"legend": "В честь юбилея ректорат ЮФУ решил запустить акцию <<Сто и десять кексов>>. \r\n\r\n $x$, $a_i^2 + b_i^2 \le a_{i+1}^2$ В каждом корпусе университета открылась лавка с кексами, в которой каждый студент может получить бесплатные кексы.\r\n\r\nНе прошло и пары минут после открытия, как к лавкам набежали студенты и образовалось много очередей. Но самая большая очередь образовалась в главном корпусе ЮФУ. Изначально в этой очереди стояло $n$ студентов, но потом в течение следующих $m$ минут какие-то студенты приходили и вставали в очередь, а какие-то уходили.\r\n\r\nЗа каждым студентом закреплен номер его зачетной книжки, будем называть это число номером студента. У каждого студента будет уникальный номер, по которому можно однозначно его идентифицировать. Будем считать, что каждую минуту происходило одно из следующих событий:\r\n\r\n\\begin{enumerate}\r\n \\item Студент с номером $x$ пришел и встал перед студентом с номером $y$;\r\n \\item Студент с номером $x$ пришел и встал в конец очереди;\r\n \\item Студент с номером $x$ ушел из очереди; возможно, он потом вернется.\r\n\\end{enumerate}\r\n\r\nАналитикам стало интересно, а какой будет очередь после $m$ минут? \r\n\r\nПомогите им и сообщите конечное состояние очереди.\r\n\r\n",
|
||||
"authorLogin": "valavshonok",
|
||||
"language": "russian",
|
||||
"timeLimit": 1000,
|
||||
"output": "В первой строке выведите одно число $|a|$~--- длину очереди после выполнения всех запросов изменения.\r\n\r\nВ следующей строке выведите $|a|$ чисел $a_1, a_2, \\cdots , a_{|a|}$, где $a_i$~--- номер студента, который стоит на $i$-й позиции в очереди.",
|
||||
"inputFile": "stdin",
|
||||
"outputFile": "stdout",
|
||||
"input": "В первой строке заданы два целых числа $n$ и $m$ $(1 \\le n, m \\le 10^5)$~--- текущее число студентов в очереди и количество изменений.\r\n\r\nВ следующей строке задается $n$ целых \\textbf{различных} чисел $a_1, a_2, \\cdots , a_n$ $(1 \\le a_i \\le 10^9)$, где $a_i$~--- номер студента, который стоит на $i$-й позиции в очереди.\r\n\r\nВ следующих $m$ строках идет описание запросов изменения очереди.\r\n\r\nВ каждой строке в зависимости от типа запроса задается два или три числа. Первое число $t_j$ $(1 \\le t_j \\le 3)$~--- тип события, которое произошло в $j$-ю минуту.\r\n\r\nЕсли $t_j = \\textbf{1}$, то в строке задается еще 2 числа $x$ $(1 \\le x_j \\le 10^9)$ и $y$ $(1 \\le y_j \\le 10^9)$~--- номер студента, который пришел, и номер студента, перед которым он встанет в очереди. Гарантируется, что студент с номером $x$ ещё не занял очередь, а студент с номером $y$ уже стоит в ней. \r\n\r\nЕсли $t_j = \\textbf{2}$, то в строке задается еще 1 число $x$ $(1 \\le x_j \\le 10^9)$~--- номер студента, который пришел и встал в конец очереди. Гарантируется, что студент с номером $x$ ещё не занял очередь.\r\n\r\nЕсли $t_j = \\textbf{3}$, то в строке задается еще 1 число $x$ $(1 \\le x_j \\le 10^9)$~--- номер студента, который ушел из очереди. Гарантируется, что студент с номером $x$ стоит в очереди.",
|
||||
"authorName": "Виталий Лавшонок",
|
||||
"sampleTests": [
|
||||
{
|
||||
"output": "9\r\n2 8 4 5 6 7 3 9 10 \r\n",
|
||||
"input": "7 6\r\n1 2 3 4 5 6 7\r\n1 8 3\r\n2 9\r\n3 3\r\n1 3 9\r\n2 10\r\n3 1\r\n",
|
||||
"inputFile": "example.01",
|
||||
"outputFile": "example.01.a"
|
||||
}
|
||||
],
|
||||
"name": "Очередь за кексами",
|
||||
"interaction": null,
|
||||
"memoryLimit": 268435456,
|
||||
"tutorial": "Давайте просто промоделируем все действия.\r\n\r\nЗаведем список элементов, а также сохраним по ключу $x$ указатель на элемент списка. Мы можем это сделать, так как все элементы различны. Например, в С++ можно просто завести коллекцию list<int>, а также map<int, list<int>::iterator> или реализовать свой список.\r\n\r\nТеперь мы можем легко обрабатывать все запросы, а в конце просто выведем весь список.\r\n\r\nЗапрос 1-го типа можно обработать так: просто берем по ключу указатель на нужный элемент и вставляем перед ним другой элемент, останется только по ключу $x$ записать указатель на новый элемент.\r\n\r\nЗапрос 2-го типа~--- просто добавить в список элемент в конец и сохранить на него указатель.\r\n\r\nЗапрос 3-го типа~--- удаляем из списка элемент по его указателю.\r\n\r\nВ конце просто выводим массив.\r\n\r\nИтоговая сложность $O(mlog(n))$"
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full h-full bg-red-3001 overflow-y-scroll medium-scrollbar pl-[20px] pr-[12px] gap-[20px]">
|
||||
<div>
|
||||
<p className="h-[50px] text-[40px] font-bold text-liquid-white">Грод на 2700</p>
|
||||
<p className="h-[23px] text-[18px] font-bold text-liquid-light">Задача #1234</p>
|
||||
<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>
|
||||
tags
|
||||
<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>
|
||||
<p className="text-liquid-white h-[20px] text-[18px] font-bold"><span className="text-liquid-light">ограничение по времени на тест:</span> 1 секунда</p>
|
||||
<p className="text-liquid-white h-[20px] text-[18px] font-bold"><span className="text-liquid-light">ограничение по памяти на тест:</span> 256 мегабайт</p>
|
||||
<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]">
|
||||
<LaTextContainer content={legend} />
|
||||
</div>
|
||||
<div className="flex flex-col gap-[10px]">
|
||||
<div>Входные данные</div>
|
||||
<LaTextContainer content={input} />
|
||||
</div>
|
||||
<div className="flex flex-col gap-[10px]">
|
||||
<div>Выходные данные</div>
|
||||
<LaTextContainer content={output} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{/* <FullLatexRenderer content={data.legend}/> */}
|
||||
<div>{sampleTests.length == 1 ? "Пример" : "Примеры"}</div>
|
||||
<div className="flex flex-col gap-[10px]">
|
||||
|
||||
{sampleTests.map((v, i) =>
|
||||
<div key={i} className="flex flex-col gap-[10px]">
|
||||
<div>Входные данные</div>
|
||||
<div>{v.input}</div>
|
||||
<div>Выходные данные</div>
|
||||
<div>{v.output}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-[10px]">
|
||||
<div>Примечание</div>
|
||||
<LaTextContainer content={notes} />
|
||||
<div>Автор: Jacks</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user