feat: appeal widget and right widget update

This commit is contained in:
2026-05-12 00:04:02 +03:00
parent 193f53c029
commit 51d1870198
12 changed files with 202 additions and 74 deletions

View File

@@ -47,6 +47,16 @@ function darkenHex(hex: string, amount: number): string {
return `#${dr.toString(16).padStart(2, "0")}${dg.toString(16).padStart(2, "0")}${db.toString(16).padStart(2, "0")}`; return `#${dr.toString(16).padStart(2, "0")}${dg.toString(16).padStart(2, "0")}${db.toString(16).padStart(2, "0")}`;
} }
function lightenRgbString(hex: string, amount: number): string | null {
const rgb = hexToRgbString(hex);
if (!rgb) return null;
const [r, g, b] = rgb.split(",").map(Number);
const lr = Math.round(r + (255 - r) * amount);
const lg = Math.round(g + (255 - g) * amount);
const lb = Math.round(b + (255 - b) * amount);
return `${lr}, ${lg}, ${lb}`;
}
function applyCarrierColors(carrier: { main_color?: string; left_color?: string; right_color?: string }) { function applyCarrierColors(carrier: { main_color?: string; left_color?: string; right_color?: string }) {
const mainColor = carrier.main_color || "#006f3a"; const mainColor = carrier.main_color || "#006f3a";
const leftColor = carrier.left_color || "#006f3a"; const leftColor = carrier.left_color || "#006f3a";
@@ -60,6 +70,7 @@ function applyCarrierColors(carrier: { main_color?: string; left_color?: string;
document.documentElement.style.setProperty("--carrier-left-rgb", hexToRgbString(leftColor) ?? "0, 111, 58"); document.documentElement.style.setProperty("--carrier-left-rgb", hexToRgbString(leftColor) ?? "0, 111, 58");
document.documentElement.style.setProperty("--carrier-right", rightColor); document.documentElement.style.setProperty("--carrier-right", rightColor);
document.documentElement.style.setProperty("--carrier-right-rgb", hexToRgbString(rightColor) ?? "0, 111, 58"); document.documentElement.style.setProperty("--carrier-right-rgb", hexToRgbString(rightColor) ?? "0, 111, 58");
document.documentElement.style.setProperty("--carrier-right-menu-rgb", lightenRgbString(rightColor, 0.38) ?? "179, 165, 152");
} }
class ApiStore { class ApiStore {

View File

@@ -1,4 +1,4 @@
import React from "react"; import React, { useState, useEffect, useRef } from "react";
const LANGUAGES = { const LANGUAGES = {
EN: "en", EN: "en",
@@ -18,6 +18,26 @@ const ListHeader = function ListHeader({
isTransferWidgetOpen, isTransferWidgetOpen,
onBackToNearest, onBackToNearest,
}) { }) {
const [isIdle, setIsIdle] = useState(false);
const timerRef = useRef(null);
useEffect(() => {
const resetTimer = () => {
setIsIdle(false);
clearTimeout(timerRef.current);
timerRef.current = setTimeout(() => setIsIdle(true), 15000);
};
const events = ["pointermove", "pointerdown", "touchstart", "keydown"];
events.forEach((e) => window.addEventListener(e, resetTimer));
resetTimer();
return () => {
clearTimeout(timerRef.current);
events.forEach((e) => window.removeEventListener(e, resetTimer));
};
}, []);
const getTitle = () => { const getTitle = () => {
return selectedLanguageRight === LANGUAGES.RU return selectedLanguageRight === LANGUAGES.RU
? "Достопримечательности" ? "Достопримечательности"
@@ -41,14 +61,11 @@ const ListHeader = function ListHeader({
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="21" width="20"
height="12" height="20"
viewBox="0 0 21 12" viewBox="0 0 21 12"
fill="none" fill="none"
style={{ className={`chevron-svg${isOpen ? " is-open" : ""}${isIdle ? " is-idle" : ""}`}
transform: isOpen ? "rotate(180deg)" : "rotate(0deg)",
transition: "transform 0.15s ease-in-out",
}}
> >
<g clipPath="url(#clip0_658_91932)"> <g clipPath="url(#clip0_658_91932)">
<path <path

View File

@@ -682,7 +682,7 @@ const SightFrame = observer(({ media, sight_id, sight_name }) => {
</> </>
)} )}
</div> </div>
<div className="sight-frame-menu"> <div className="sight-frame-menu" style={selectedSection !== 0 ? { paddingLeft: '50px' } : undefined}>
{selectedSection !== 0 && ( {selectedSection !== 0 && (
<div <div
style={{ style={{

View File

@@ -17,7 +17,6 @@ import {
UNPASSED_STATION_COLOR, UNPASSED_STATION_COLOR,
BUS_COLOR, BUS_COLOR,
BASE_ICON_SIZE, BASE_ICON_SIZE,
CLUSTER_RADIUS_BASE,
} from "./Constants"; } from "./Constants";
import { SCALE_FACTOR } from "../../assets/Constants"; import { SCALE_FACTOR } from "../../assets/Constants";
import { apiStore } from "../../api/ApiStore/store"; import { apiStore } from "../../api/ApiStore/store";
@@ -2551,14 +2550,8 @@ export const WebGLMap = observer(() => {
const rx = cluster.longitude; const rx = cluster.longitude;
const ry = cluster.latitude; const ry = cluster.latitude;
const iconSizePercent = resolveSightIconSizePercent();
const iconSize =
SIGHT_ICON_BASE_SIZE * clamp(iconSizePercent / 100, 0.1, 10);
const screenX = (rx * scale + position.x) / dpr; const screenX = (rx * scale + position.x) / dpr;
const screenY = (ry * scale + position.y) / dpr; const screenY = (ry * scale + position.y) / dpr;
const iconLeft = screenX - iconSize / 2;
const iconTop = screenY - iconSize / 2;
const isExpanded = activeClusterId === cluster.id; const isExpanded = activeClusterId === cluster.id;
const selectedSightInCluster = cluster.sights.find( const selectedSightInCluster = cluster.sights.find(
@@ -2570,6 +2563,20 @@ export const WebGLMap = observer(() => {
const selectedIsCustomInCluster = const selectedIsCustomInCluster =
selectedSightInCluster?.is_default_icon === false && selectedSightInCluster?.is_default_icon === false &&
selectedHasIconInCluster; selectedHasIconInCluster;
const iconSizePercent = resolveSightIconSizePercent(
cluster.sights[0],
);
const clusterCustomScaleFactor = selectedIsCustomInCluster
? scale / Math.max(customSightIconBaseScaleRef.current ?? 1, 1e-6)
: 1;
const iconSize =
SIGHT_ICON_BASE_SIZE *
clamp(iconSizePercent / 100, 0.1, 10) *
clusterCustomScaleFactor;
const iconLeft = screenX - iconSize;
const iconTop = screenY - iconSize;
const hasSelectedAltIconInCluster = const hasSelectedAltIconInCluster =
selectedSightInCluster != null && selectedSightInCluster != null &&
selectedIsCustomInCluster && selectedIsCustomInCluster &&
@@ -2643,13 +2650,10 @@ export const WebGLMap = observer(() => {
onTouchEnd={handleClusterClick} onTouchEnd={handleClusterClick}
style={{ style={{
position: "absolute", position: "absolute",
left: iconLeft - CLUSTER_RADIUS_BASE - 10, left: iconLeft - 25,
top: iconTop - CLUSTER_RADIUS_BASE - 10, top: iconTop - 25,
width: iconSize + CLUSTER_RADIUS_BASE * 2 + 20, width: iconSize + 50,
height: iconSize + CLUSTER_RADIUS_BASE * 2 + 20, height: iconSize + 50,
display: "flex",
alignItems: "center",
justifyContent: "center",
pointerEvents: "auto", pointerEvents: "auto",
cursor: "pointer", cursor: "pointer",
userSelect: "none", userSelect: "none",
@@ -2662,15 +2666,24 @@ export const WebGLMap = observer(() => {
}), }),
}} }}
> >
<div style={{ position: "relative" }}> <div
style={{
position: "absolute",
left: 25,
top: 25,
width: iconSize,
height: iconSize,
flexShrink: 0,
}}
>
<img <img
src={clusterIconUrl} src={clusterIconUrl}
alt="" alt=""
width={iconSize}
height={iconSize}
style={{ style={{
display: "block", display: "block",
pointerEvents: "none", pointerEvents: "none",
width: "100%",
height: "100%",
filter: hasSelectedSight filter: hasSelectedSight
? hasSelectedAltIconInCluster ? hasSelectedAltIconInCluster
? "none" ? "none"
@@ -2683,6 +2696,7 @@ export const WebGLMap = observer(() => {
position: "absolute", position: "absolute",
top: -6, top: -6,
right: -6, right: -6,
zIndex: 1,
width: 15, width: 15,
height: 15, height: 15,
borderRadius: "10px", borderRadius: "10px",
@@ -2708,8 +2722,8 @@ export const WebGLMap = observer(() => {
onMouseMove={handleCircleInteraction} onMouseMove={handleCircleInteraction}
style={{ style={{
position: "absolute", position: "absolute",
left: screenX - iconSize / 2, left: screenX - iconSize,
top: screenY - iconSize / 2, top: screenY - iconSize,
display: "flex", display: "flex",
alignItems: "flex-start", alignItems: "flex-start",
pointerEvents: "auto", pointerEvents: "auto",

View File

@@ -2,7 +2,6 @@ import "../../styles/SideMenu.css";
import AppealWidget from "../widgets/AppealWidget"; import AppealWidget from "../widgets/AppealWidget";
import { useEffect, useState, useCallback, useRef } from "react"; import { useEffect, useState, useCallback, useRef } from "react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import gouvermentImage from "../../assets/images/test-image.png";
import sideMenuPhoto from "/side-menu-photo.png"; import sideMenuPhoto from "/side-menu-photo.png";
import RouteWidget from "../widgets/RouteWidget"; import RouteWidget from "../widgets/RouteWidget";
import ContentAPI from "../../api/content/content.api"; import ContentAPI from "../../api/content/content.api";
@@ -455,7 +454,7 @@ const SideMenu = observer(({ onMenuToggle }) => {
: "Governor's appeal"} : "Governor's appeal"}
</div> </div>
)} )}
<div className="side-menu-buttons"> <div className="side-menu-buttons" style={{ marginTop: route?.governor_appeal > 0 ? '40px' : '260px' }}>
<div <div
onPointerUp={() => { onPointerUp={() => {
if (!isSightsOpen) { if (!isSightsOpen) {
@@ -583,11 +582,17 @@ const SideMenu = observer(({ onMenuToggle }) => {
<RouteWidget /> <RouteWidget />
<AppealWidget <AppealWidget
widgetImgPath={gouvermentImage} widgetImgPath={(() => {
const m = sightArticles.get(route?.governor_appeal + "_ru")?.media;
const mediaId = Array.isArray(m) ? m[0]?.id : m?.id;
return mediaId ? getMediaUrl(mediaId) : undefined;
})()}
isOpen={isWidgetOpen}
style={{ style={{
transform: isWidgetOpen ? "translateX(0)" : "translateX(-200%)", transform: isWidgetOpen ? "translateX(0)" : "translateX(-200%)",
transition: "transform 0.5s ease", transition: "transform 0.5s ease",
zIndex: -1, zIndex: -1,
pointerEvents: isWidgetOpen ? "auto" : "none",
}} }}
widgetLabel={ widgetLabel={
selectedLanguage == "ru" selectedLanguage == "ru"

View File

@@ -1,11 +1,29 @@
import { useRef, useEffect } from 'react'
import '../../styles/AppealWidget.css' import '../../styles/AppealWidget.css'
import { TouchableLayout } from '../TouchableLayout'
function AppealWidget({widgetImgPath, widgetLabel, widgetText, style, isOpen}) {
const stopProp = (e) => { e.stopPropagation(); e.preventDefault(); };
const layoutRef = useRef(null);
useEffect(() => {
if (isOpen && layoutRef.current) {
const scrollable = layoutRef.current.querySelector('.scrollable');
if (scrollable) scrollable.scrollTop = 0;
}
}, [isOpen]);
function AppealWidget({widgetImgPath, widgetLabel, widgetText, style}) {
return ( return (
<div style={style} className='dynamic-widget'> <div style={style} className='dynamic-widget'
<img className='dynamic-widget-image' src={widgetImgPath} /> onPointerDown={stopProp}
onPointerMove={stopProp}
onPointerUp={stopProp}
>
{widgetImgPath && <img className='dynamic-widget-image' src={widgetImgPath} />}
<div className='dynamic-widget-label'>{widgetLabel}</div> <div className='dynamic-widget-label'>{widgetLabel}</div>
<div className='dynamic-widget-text'>{widgetText}</div> <TouchableLayout ref={layoutRef} className="dynamic-widget-text-scroll" maxHeight="calc(100vh - 150px - 100px - 300px)">
<div className='dynamic-widget-text'>{widgetText}</div>
</TouchableLayout>
</div> </div>
); );
} }

View File

@@ -5,37 +5,57 @@
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
width: 420px; width: 420px;
max-height: calc(100vh - 150px - 100px);
border-radius: 10px; border-radius: 10px;
background: linear-gradient( background:
linear-gradient(
114deg, 114deg,
rgba(255, 255, 255, 0) 8.71%, rgba(255, 255, 255, 0) 8.71%,
rgba(255, 255, 255, 0.16) 69.69% rgba(255, 255, 255, 0.16) 69.69%
), ),
var(--carrier-main, #006F3A); var(--carrier-left, #006F3A);
box-sizing: border-box; box-sizing: border-box;
overflow: hidden;
touch-action: none;
} }
.dynamic-widget-image { .dynamic-widget-image {
border-radius-top-left: 10px;
border-radius-top-right: 10px;
padding-top: 4px; padding-top: 4px;
margin-left: 4px; margin-left: 4px;
margin-right: 4px; margin-right: 4px;
width: 412px; width: 412px;
border-radius: 6px 6px 0 0;
object-fit: cover;
} }
.dynamic-widget-label { .dynamic-widget-label {
width: 380px; width: 380px;
margin-top: 29px; margin-top: 20px;
margin-bottom: 5px;
font-size: 20px; font-size: 20px;
font-weight: 500; font-weight: 500;
} }
.dynamic-widget-text { .dynamic-widget-text-scroll {
margin-top: 16px; margin-top: 0;
margin-bottom: 25px; margin-bottom: 25px;
width: 380px; flex: 1;
font-size: 16px; min-height: 0;
font-weight: 300; }
line-height: 150%;
.dynamic-widget-text-scroll.scrollable-container {
margin: 0 20px;
}
.dynamic-widget-text-scroll .scrollable-viewport {
padding-bottom: 20px;
box-sizing: border-box;
}
.dynamic-widget-text {
font-size: 14px;
font-weight: 400;
line-height: 190%;
padding-bottom: 10px;
padding-right: 5px;
} }

View File

@@ -1,3 +1,25 @@
@keyframes pulse-chevron {
0% { transform: rotate(var(--r, 0deg)) translateY(0px) scale(1); }
40% { transform: rotate(var(--r, 0deg)) translateY(-4px) scale(1.12); }
60% { transform: rotate(var(--r, 0deg)) translateY(-5px) scale(1.14); }
100% { transform: rotate(var(--r, 0deg)) translateY(0px) scale(1); }
}
.chevron-svg {
font-size: 20px;
animation: pulse-chevron 1.2s ease-in-out infinite;
animation-play-state: paused;
will-change: transform;
}
.chevron-svg.is-idle {
animation-play-state: running;
}
.chevron-svg.is-open {
--r: 180deg;
}
.right-widget { .right-widget {
position: fixed; position: fixed;
right: 32px; right: 32px;
@@ -17,7 +39,7 @@
rgba(255, 255, 255, 0) 8.71%, rgba(255, 255, 255, 0) 8.71%,
rgba(255, 255, 255, 0.16) 69.69% rgba(255, 255, 255, 0.16) 69.69%
), ),
var(--carrier-right, #006f3a); var(--carrier-right, #806C59);
color: white; color: white;
max-height: 68px; max-height: 68px;
@@ -65,7 +87,7 @@
background-color: color-mix( background-color: color-mix(
in srgb, in srgb,
var(--carrier-right, #006f3a) 80%, var(--carrier-right, #806C59) 80%,
black black
); );
} }
@@ -198,7 +220,7 @@
rgba(255, 255, 255, 0) 8.71%, rgba(255, 255, 255, 0) 8.71%,
rgba(255, 255, 255, 0.16) 69.69% rgba(255, 255, 255, 0.16) 69.69%
), ),
var(--carrier-right, #006f3a); var(--carrier-right, #806C59);
max-height: calc(100vh - 128px); max-height: calc(100vh - 128px);
} }
@@ -241,7 +263,7 @@
rgba(255, 255, 255, 0.22) 0%, rgba(255, 255, 255, 0.22) 0%,
rgba(255, 255, 255, 0.04) 100% rgba(255, 255, 255, 0.04) 100%
), ),
rgba(var(--carrier-right-rgb, 0, 111, 58), 0.72); rgba(var(--carrier-right-rgb, 128, 108, 89), 0.72);
box-shadow: 4px 4px 12px 0px rgba(255, 255, 255, 0.12) inset; box-shadow: 4px 4px 12px 0px rgba(255, 255, 255, 0.12) inset;
box-sizing: border-box; box-sizing: border-box;
color: white; color: white;
@@ -250,6 +272,16 @@
min-width: 0; min-width: 0;
} }
.sight-frame-title:not(.intro-title) {
background:
linear-gradient(
180deg,
rgba(255, 255, 255, 0.2) 0%,
rgba(255, 255, 255, 0) 100%
),
rgba(var(--carrier-right-menu-rgb, 179, 165, 152), 0.4);
}
.sight-frame-title p { .sight-frame-title p {
word-wrap: break-word; word-wrap: break-word;
overflow-wrap: break-word; overflow-wrap: break-word;
@@ -308,7 +340,7 @@
background: linear-gradient( background: linear-gradient(
to right, to right,
transparent 35%, transparent 35%,
color-mix(in srgb, var(--carrier-right, #006f3a) 80%, black) 50%, color-mix(in srgb, var(--carrier-right, #806C59) 80%, black) 50%,
transparent 65% transparent 65%
); );
border-radius: 3px; border-radius: 3px;
@@ -336,7 +368,7 @@
width: 100%; width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-around; justify-content: space-evenly;
border-radius: 0px 0px 10px 10px; border-radius: 0px 0px 10px 10px;
border-top: 1px solid rgba(255, 255, 255, 0.8); border-top: 1px solid rgba(255, 255, 255, 0.8);
background: background:
@@ -345,7 +377,7 @@
rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0.2) 0%,
rgba(255, 255, 255, 0) 100% rgba(255, 255, 255, 0) 100%
), ),
rgba(var(--carrier-right-rgb, 0, 111, 58), 0.4); rgba(var(--carrier-right-menu-rgb, 179, 165, 152), 0.4);
box-shadow: 4px 4px 12px 0px rgba(255, 255, 255, 0.12) inset; box-shadow: 4px 4px 12px 0px rgba(255, 255, 255, 0.12) inset;
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
box-sizing: border-box; box-sizing: border-box;
@@ -360,7 +392,6 @@
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
padding: 8px 12px; padding: 8px 12px;
white-space: nowrap; white-space: nowrap;
transition: transition:
background-color 0.1s ease, background-color 0.1s ease,
@@ -368,8 +399,8 @@
} }
.sight-frame-menu-point.active { .sight-frame-menu-point.active {
border-bottom: 2px solid #fff;
font-weight: 600; font-weight: 600;
border-bottom: 2px solid #fff;
} }
.sight-frame-text-wrapper::-webkit-scrollbar-track { .sight-frame-text-wrapper::-webkit-scrollbar-track {
@@ -751,7 +782,7 @@
border-radius: 32px; border-radius: 32px;
right: 20px; right: 20px;
bottom: 20px; bottom: 20px;
background: var(--carrier-right, #006f3a); background: var(--carrier-right, #806C59);
z-index: 9999; z-index: 9999;
display: flex; display: flex;
} }

View File

@@ -39,7 +39,7 @@
.side-menu-buttons { .side-menu-buttons {
width: 220px; width: 220px;
margin-top: 260px; margin-top: 40px;
} }
.side-menu-button { .side-menu-button {

View File

@@ -288,7 +288,7 @@ export const CarrierCreatePage = observer(() => {
} }
/> />
<p className="text-xs text-gray-500 pl-1"> <p className="text-xs text-gray-500 pl-1">
Используется в: виджет маршрута, виджет обращений, значки на карте, скопление достопримечательностей на карте, информационный виджет Используется в: виджет обращений, значки на карте, скопление достопримечательностей на карте, информационный виджет
</p> </p>
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">

View File

@@ -30,7 +30,11 @@ import {
UploadMediaDialog, UploadMediaDialog,
} from "@shared"; } from "@shared";
type ColorFields = { main_color: string; left_color: string; right_color: string }; type ColorFields = {
main_color: string;
left_color: string;
right_color: string;
};
const colorFields = (data: ColorFields) => ({ const colorFields = (data: ColorFields) => ({
main_color: data.main_color, main_color: data.main_color,
@@ -130,7 +134,7 @@ export const CarrierEditPage = observer(() => {
carrierData.ru?.slogan || "", carrierData.ru?.slogan || "",
carrierData.ru?.logo || "", carrierData.ru?.logo || "",
"ru", "ru",
colors colors,
); );
setEditCarrierData( setEditCarrierData(
carrierData.en?.full_name || "", carrierData.en?.full_name || "",
@@ -138,7 +142,7 @@ export const CarrierEditPage = observer(() => {
carrierData.en?.city_id || 0, carrierData.en?.city_id || 0,
carrierData.en?.slogan || "", carrierData.en?.slogan || "",
carrierData.en?.logo || "", carrierData.en?.logo || "",
"en" "en",
); );
setEditCarrierData( setEditCarrierData(
carrierData.zh?.full_name || "", carrierData.zh?.full_name || "",
@@ -146,7 +150,7 @@ export const CarrierEditPage = observer(() => {
carrierData.zh?.city_id || 0, carrierData.zh?.city_id || 0,
carrierData.zh?.slogan || "", carrierData.zh?.slogan || "",
carrierData.zh?.logo || "", carrierData.zh?.logo || "",
"zh" "zh",
); );
setInitialCityName(carrierData.ru?.city || ""); setInitialCityName(carrierData.ru?.city || "");
} }
@@ -185,7 +189,7 @@ export const CarrierEditPage = observer(() => {
editCarrierData.city_id, editCarrierData.city_id,
editCarrierData[language].slogan, editCarrierData[language].slogan,
media.id, media.id,
language language,
); );
}; };
@@ -267,7 +271,7 @@ export const CarrierEditPage = observer(() => {
Number(e.target.value), Number(e.target.value),
editCarrierData[language].slogan, editCarrierData[language].slogan,
editCarrierData.logo, editCarrierData.logo,
language language,
) )
} }
> >
@@ -291,7 +295,7 @@ export const CarrierEditPage = observer(() => {
editCarrierData.city_id, editCarrierData.city_id,
editCarrierData[language].slogan, editCarrierData[language].slogan,
editCarrierData.logo, editCarrierData.logo,
language language,
) )
} }
/> />
@@ -308,7 +312,7 @@ export const CarrierEditPage = observer(() => {
editCarrierData.city_id, editCarrierData.city_id,
editCarrierData[language].slogan, editCarrierData[language].slogan,
editCarrierData.logo, editCarrierData.logo,
language language,
) )
} }
/> />
@@ -324,7 +328,7 @@ export const CarrierEditPage = observer(() => {
editCarrierData.city_id, editCarrierData.city_id,
e.target.value, e.target.value,
editCarrierData.logo, editCarrierData.logo,
language language,
) )
} }
/> />
@@ -342,12 +346,13 @@ export const CarrierEditPage = observer(() => {
editCarrierData[language].slogan, editCarrierData[language].slogan,
editCarrierData.logo, editCarrierData.logo,
language, language,
{ ...colorFields(editCarrierData), main_color: val } { ...colorFields(editCarrierData), main_color: val },
) )
} }
/> />
<p className="text-xs text-gray-500 pl-1"> <p className="text-xs text-gray-500 pl-1">
Используется в: виджет маршрута, виджет обращений, значки на карте, скопление достопримечательностей на карте, информационный виджет Используется в: значки на карте, скопление достопримечательностей
на карте, информационный виджет
</p> </p>
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
@@ -362,12 +367,13 @@ export const CarrierEditPage = observer(() => {
editCarrierData[language].slogan, editCarrierData[language].slogan,
editCarrierData.logo, editCarrierData.logo,
language, language,
{ ...colorFields(editCarrierData), left_color: val } { ...colorFields(editCarrierData), left_color: val },
) )
} }
/> />
<p className="text-xs text-gray-500 pl-1"> <p className="text-xs text-gray-500 pl-1">
Используется в: боковое меню, левый виджет достопримечательности Используется в: виджет обращений, боковое меню (фон, список
остановок), левый виджет достопримечательности
</p> </p>
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
@@ -382,12 +388,13 @@ export const CarrierEditPage = observer(() => {
editCarrierData[language].slogan, editCarrierData[language].slogan,
editCarrierData.logo, editCarrierData.logo,
language, language,
{ ...colorFields(editCarrierData), right_color: val } { ...colorFields(editCarrierData), right_color: val },
) )
} }
/> />
<p className="text-xs text-gray-500 pl-1"> <p className="text-xs text-gray-500 pl-1">
Используется в: список достопримечательностей, страница достопримечательности Используется в: список достопримечательностей (фон, карточки),
правый виджет достопримечательности
</p> </p>
</div> </div>
</div> </div>
@@ -465,7 +472,7 @@ export const CarrierEditPage = observer(() => {
editCarrierData.city_id, editCarrierData.city_id,
editCarrierData[language].slogan, editCarrierData[language].slogan,
"", "",
language language,
); );
setIsDeleteLogoModalOpen(false); setIsDeleteLogoModalOpen(false);
}} }}

View File

@@ -125,7 +125,12 @@ export const LeftSidebar = observer(({ open, onToggle }: LeftSidebarProps) => {
)} )}
{/* Кнопки — .side-menu-buttons */} {/* Кнопки — .side-menu-buttons */}
<div style={{ width: 220, marginTop: 260 }}> <div
style={{
width: 220,
marginTop: routeData?.governor_appeal || 0 > 0 ? 40 : 260,
}}
>
<div <div
style={{ style={{
backgroundColor: "#fff", backgroundColor: "#fff",