feat: update demo page + add city_id for media and articles

This commit is contained in:
2026-04-28 10:57:42 +03:00
parent 60c6840db4
commit 94f512e0e4
27 changed files with 499 additions and 222 deletions

View File

@@ -286,9 +286,9 @@ export const RouteCreatePage = observer(() => {
newRoute.governor_appeal = governor_appeal;
}
await routeStore.createRoute(newRoute);
const newId = await routeStore.createRoute(newRoute);
toast.success("Маршрут успешно создан");
navigate(-1);
navigate(`/route/${newId}/edit`);
} catch (error) {
console.error(error);
toast.error("Произошла ошибка при создании маршрута");

View File

@@ -141,6 +141,7 @@ export function RightSidebar() {
bgcolor="primary.main"
border="1px solid #e0e0e0"
borderRadius={2}
zIndex={2}
>
<Typography variant="h6" sx={{ mb: 2, color: "#fff" }} textAlign="center">
Настройка маршрута

View File

@@ -2,6 +2,7 @@ import { Stack, Typography, Box, IconButton } from "@mui/material";
import { Close } from "@mui/icons-material";
import { Landmark } from "lucide-react";
import { useMapData } from "./MapDataContext";
import { RouteWidget } from "./webgl-prototype/RouteWidget";
export function Widgets() {
const { selectedSight, setSelectedSight } = useMapData();
@@ -13,22 +14,11 @@ export function Widgets() {
position="absolute"
top={32}
left={32}
zIndex={2}
sx={{ pointerEvents: "none" }}
>
<Stack
bgcolor="primary.main"
width={361}
height={96}
p={2}
m={2}
borderRadius={2}
alignItems="center"
justifyContent="center"
>
<Typography variant="h6" sx={{ color: "#fff" }}>
Остановка
</Typography>
</Stack>
{/* Виджет маршрута */}
<RouteWidget />
{/* Виджет выбранной достопримечательности (заменяет виджет погоды) */}
<Stack

View File

@@ -0,0 +1,105 @@
.route-widget-label.marquee {
display: inline-block;
animation: marquee 14s linear infinite;
}
.route-widget-subtitle.marquee {
display: inline-block;
animation: marquee 14s linear infinite;
}
@keyframes marquee {
0% {
transform: translateX(0);
}
50% {
transform: translateX(-50%);
}
100% {
transform: translateX(0);
}
}
.route-widget {
width: 361px;
height: 96px;
position: fixed;
display: inline-flex;
border-radius: 10px;
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.3) inset,
/* Внутренняя рамка */ 4px 4px 12px 0 rgba(255, 255, 255, 0.12) inset; /* Ваш существующий внутренний shadow */
padding: 1px; /* Чтобы контент не прилипал к рамке */
background: linear-gradient(
to bottom right,
rgba(255, 255, 255, 0.2) 0%,
rgba(255, 255, 255, 0) 100%
),
rgba(179, 165, 152, 0.4);
backdrop-filter: blur(10px);
pointer-events: auto;
z-index: 10000001;
}
.route-widget-number {
position: absolute;
width: fit-content;
left: 0px;
top: 0px;
min-width: 94px;
max-width: 100px;
height: 96px;
background-color: #fcd500;
color: black;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
font-size: 70px;
padding: 14px;
font-weight: 900;
}
.route-widget-content {
overflow: hidden;
width: 257px;
display: flex;
flex-direction: column;
margin-top: 13px;
margin-left: 109px;
margin-right: 9px;
}
.route-widget-label {
white-space: nowrap;
font-size: 24px;
margin: 1px 0;
font-style: normal;
font-weight: 700;
line-height: 24px;
color: white;
}
.route-widget-label--medium {
font-size: 22px;
line-height: 22px;
}
.route-widget-label--small {
font-size: 20px;
line-height: 20px;
}
.route-widget-label--xsmall {
font-size: 18px;
line-height: 18px;
}
.route-widget-subtitle {
white-space: nowrap;
color: #cbcbcb;
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: normal;
margin-top: 4px;
}

View File

@@ -0,0 +1,72 @@
import styles from "./RouteWidget.module.css";
import { useMapData } from "../MapDataContext";
import { languageStore } from "@shared";
import { observer } from "mobx-react-lite";
const shouldAnimate = (text: string | undefined, maxLength: number) =>
(text?.length ?? 0) > maxLength;
const getLabelSizeClass = (text: string | undefined) => {
const length = text?.length ?? 0;
if (length <= 40) return "";
if (length <= 60) return styles["route-widget-label--medium"];
if (length <= 80) return styles["route-widget-label--small"];
return styles["route-widget-label--xsmall"];
};
export const RouteWidget = observer(() => {
const { routeData, stationData } = useMapData();
const { language } = languageStore;
const stations = stationData?.[language] ?? stationData?.["ru"] ?? [];
const stationsRu = stationData?.["ru"] ?? [];
const startStation = stations[0];
const endStation = stations[stations.length - 1];
const startStationRu = stationsRu[0];
const endStationRu = stationsRu[stationsRu.length - 1];
const enSubtitle = `${startStationRu?.name ?? ""} - ${endStationRu?.name ?? ""}`;
const zhSubtitle = `${startStation?.name ?? ""} - ${endStation?.name ?? ""}`;
const subtitle = language === "zh" ? zhSubtitle : enSubtitle;
return (
<div className={styles["route-widget"]} style={{ position: "relative" }}>
<div className={styles["route-widget-number"]}>
{routeData?.route_sys_number || ""}
</div>
<div className={styles["route-widget-content"]}>
<div
className={[
styles["route-widget-label"],
shouldAnimate(startStation?.name, 18) ? styles["marquee"] : "",
getLabelSizeClass(startStation?.name),
].join(" ")}
title={startStation?.name}
>
{startStation?.name}
</div>
<div
className={[
styles["route-widget-label"],
shouldAnimate(endStation?.name, 18) ? styles["marquee"] : "",
getLabelSizeClass(endStation?.name),
].join(" ")}
title={endStation?.name}
>
{endStation?.name}
</div>
<div
className={[
styles["route-widget-subtitle"],
shouldAnimate(subtitle, 50) ? styles["marquee"] : "",
].join(" ")}
title={subtitle}
>
{subtitle}
</div>
</div>
</div>
);
});