diff --git a/services/frontend/src/App.tsx b/services/frontend/src/App.tsx index d7bd1eb..9c7f555 100644 --- a/services/frontend/src/App.tsx +++ b/services/frontend/src/App.tsx @@ -1,8 +1,8 @@ import { Routes, Route } from "react-router"; import "./styles/globals.css"; -import CompetitionsPage from "./pages/CompetitionsPage"; -import CompetitionPreviewPage from "./pages/CompetitionPreviewPage"; -import CompetitionRunnerPage from "./pages/CompetitionRunnerPage"; +import CompetitionsPage from "./pages/Competitions"; +import CompetitionPage from "./pages/Competition"; +import CompetitionRunnerPage from "./pages/CompetitionSession"; import { NavbarLayout } from "./widgets/navbar-layout"; const App = () => { @@ -10,12 +10,12 @@ const App = () => { }> } /> + } /> + } + /> - } /> - } - /> ); }; diff --git a/services/frontend/src/components/ui/button.tsx b/services/frontend/src/components/ui/button.tsx index 49dcad9..7558e04 100644 --- a/services/frontend/src/components/ui/button.tsx +++ b/services/frontend/src/components/ui/button.tsx @@ -9,8 +9,7 @@ const buttonVariants = cva( { variants: { variant: { - default: - "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", + default: "bg-primary text-foreground hover:bg-primary/80", destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40", outline: @@ -21,7 +20,7 @@ const buttonVariants = cva( link: "text-primary underline-offset-4 hover:underline", }, size: { - default: "h-9 px-4 py-2 has-[>svg]:px-3", + default: "h-12 px-5 py-3 has-[>svg]:px-3 text-lg font-semibold", sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", lg: "h-10 rounded-md px-6 has-[>svg]:px-4", icon: "size-9", diff --git a/services/frontend/src/pages/Competition/index.tsx b/services/frontend/src/pages/Competition/index.tsx new file mode 100644 index 0000000..bdddd5a --- /dev/null +++ b/services/frontend/src/pages/Competition/index.tsx @@ -0,0 +1,53 @@ +import { useState } from "react"; +import { useParams, Link } from "react-router-dom"; +import { Button } from "@/components/ui/button"; +import { ArrowLeft } from "lucide-react"; +import { Competition } from "@/shared/types"; +import { mockCompetitions } from "@/shared/mocks/mocks"; + +const CompetitionPage = () => { + const { id } = useParams<{ id: string }>(); + const [competition] = useState( + mockCompetitions.find((comp) => comp.id === id)!, + ); + + return ( +
+ + + Назад к соревнованиям + + +
+
+ {competition.name} +
+ +
+
+

+ {competition.name} +

+
+ {competition.description + ?.split("\n") + .map((line, i) =>

{line}

)} +
+
+
+ +
+
+
+
+ ); +}; + +export default CompetitionPage; diff --git a/services/frontend/src/pages/CompetitionSession/index.tsx b/services/frontend/src/pages/CompetitionSession/index.tsx new file mode 100644 index 0000000..f554a58 --- /dev/null +++ b/services/frontend/src/pages/CompetitionSession/index.tsx @@ -0,0 +1,164 @@ +import { useState, useEffect } from "react"; +import { useParams, useNavigate } from "react-router-dom"; +import { Task } from "@/shared/types"; +import { getTaskBgColor, getTaskTextColor } from "./utils/utils"; +import { mockTasks } from "@/shared/mocks/mocks"; +import { Button } from "@/components/ui/button"; +import { Calendar } from "lucide-react"; + +const CompetitionRunnerPage = () => { + const { id, taskId } = useParams<{ id: string; taskId?: string }>(); + const navigate = useNavigate(); + const [competitionTitle, setCompetitionTitle] = useState( + "Олимпиада DANO 2025. Индивидуальный этап", + ); + const [tasks] = useState(mockTasks); + const [selectedTaskId, setSelectedTaskId] = useState( + taskId || null, + ); + const [answer, setAnswer] = useState(""); + + useEffect(() => { + if (taskId) { + setSelectedTaskId(taskId); + } else if (tasks.length > 0) { + navigate(`/competition/${id}/tasks/${tasks[0].id}`, { replace: true }); + } + }, [taskId, tasks, id, navigate]); + + const handleTaskClick = (taskId: string) => { + if (selectedTaskId !== taskId) { + setSelectedTaskId(taskId); + navigate(`/competition/${id}/tasks/${taskId}`); + } + }; + + const currentTask = tasks.find((t) => t.id === selectedTaskId); + + const handleSubmit = () => { + console.log("Submitting answer:", answer); + // Submit logic here + }; + + const handleHistoryClick = () => { + console.log("View history"); + }; + + return ( +<<<<<<< HEAD:services/frontend/src/pages/CompetitionRunnerPage/index.tsx + <> +
+
+
+

{competitionTitle}

+======= + <> +
+
+
+

+ {competitionTitle} +

+>>>>>>> 58f493250150ba62ac4f325a0708b96eb88661e9:services/frontend/src/pages/CompetitionSession/index.tsx +
+ +
+ {tasks.map((task) => ( +
handleTaskClick(task.id)} + > + {task.number} +
+ ))} +
+
+
+ +
+
+ {currentTask ? ( +
+ {/* Left Container - Task Description */} +
+

+ Задача {currentTask.number} +

+ +
+

+ Рассмотрим последовательность чисел 2, 3, 5, 9, 17, 33, 65, + 129, ... Каждый член этой последовательности, начиная с + третьего, равен сумме двух предыдущих членов. +

+

+ Найдите сумму первых 15 членов этой последовательности. +

+

В ответе укажите целое число.

+
+
+ + {/* Right Container - Solution Area */} +
+ {/* Solution Status Card */} +
+
+ + Решение 12345 + + + Зачтено 5/10 баллов + +
+
+ 1 марта, 08:41 +
+
+ + {/* Answer Input */} +
+