Приводил к стилу consta UI

This commit is contained in:
NikitaKalitov
2026-07-22 09:42:26 +03:00
parent 52e28e8dc6
commit 4852e55964
7 changed files with 478 additions and 75 deletions
+188 -3
View File
@@ -1,11 +1,70 @@
import { useRef, useState, type RefObject } from 'react';
import { Button } from '@consta/uikit/Button';
import { TextField } from '@consta/uikit/TextField';
import { ChoiceGroup } from '@consta/uikit/ChoiceGroup';
import { ColorPicker, hexModel } from '@consta/uikit/ColorPicker';
import { Text } from '@consta/uikit/Text';
import type { DiagramEdgeData, EdgeLineStyle } from './types';
const LINE_STYLE_ITEMS: { label: string; style: EdgeLineStyle }[] = [
{ label: 'Сплошная', style: 'solid' },
{ label: 'Пунктирная', style: 'dashed' },
{ label: 'Точечная', style: 'dotted' },
];
// "Основные цвета для мелкой графики, линий" — two tonal rows (blue, gray)
// meant specifically for lines, shown first.
const GRAPHIC_LINE_PRESETS: { hex: string; label: string }[] = [
{ hex: '#0079C2', label: 'Синий 1' },
{ hex: '#43B7F7', label: 'Синий 2' },
{ hex: '#89CFFF', label: 'Синий 3' },
{ hex: '#75AAC5', label: 'Синий 4' },
{ hex: '#8FD7E4', label: 'Синий 5' },
{ hex: '#004181', label: 'Синий 6' },
{ hex: '#929AA4', label: 'Серый 1' },
{ hex: '#CED2D6', label: 'Серый 2' },
{ hex: '#E9EBED', label: 'Серый 3' },
{ hex: '#FFFFFF', label: 'Серый 4' },
];
// "Дополнительные цвета" — the section palette.css marks as meant for
// lines/small graphics too (single accents), shown after the row above.
const ACCENT_LINE_PRESETS: { hex: string; label: string }[] = [
{ hex: '#B5309A', label: 'Пурпурный' },
{ hex: '#EC5665', label: 'Красный' },
{ hex: '#FFAB66', label: 'Оранжевый' },
{ hex: '#C2DC5B', label: 'Оливковый' },
{ hex: '#32CA88', label: 'Зелёный' },
{ hex: '#22926D', label: 'Тёмно-зелёный' },
{ hex: '#0EBAD5', label: 'Синий' },
{ hex: '#4EE7F4', label: 'Циан' },
{ hex: '#9152E6', label: 'Виолет' },
{ hex: '#9D9AF7', label: 'Лавандовый' },
{ hex: '#E88FDB', label: 'Розовый' },
];
const LINE_COLOR_PRESETS = [...GRAPHIC_LINE_PRESETS, ...ACCENT_LINE_PRESETS];
// "Цвета текста" from palette.css.
const TEXT_COLOR_PRESETS: { hex: string; label: string }[] = [
{ hex: '#0079C2', label: 'Синий' },
{ hex: '#525A64', label: 'Тёмный' },
{ hex: '#929AA4', label: 'Серый' },
{ hex: '#FFFFFF', label: 'Белый' },
];
const DEFAULT_STROKE_WIDTH = 1;
const DEFAULT_BORDER_RADIUS = 5;
const DEFAULT_EDGE_COLOR = '#b1b1b7';
const DEFAULT_TEXT_COLOR = '#FFFFFF';
const DEFAULT_FONT_SIZE = 11;
interface EdgeInspectorProps {
edgeId: string;
label: string;
onChange: (label: string) => void;
data: DiagramEdgeData;
onLabelChange: (label: string) => void;
onDataChange: (patch: Partial<DiagramEdgeData>) => void;
onDelete: () => void;
onBringToFront: () => void;
onSendToBack: () => void;
@@ -14,11 +73,21 @@ interface EdgeInspectorProps {
export function EdgeInspector({
edgeId,
label,
onChange,
data,
onLabelChange,
onDataChange,
onDelete,
onBringToFront,
onSendToBack,
}: EdgeInspectorProps) {
const [colorPickerOpen, setColorPickerOpen] = useState(false);
const colorButtonRef = useRef<HTMLDivElement>(null) as RefObject<HTMLDivElement>;
const currentColor = data.color ?? DEFAULT_EDGE_COLOR;
const [textColorPickerOpen, setTextColorPickerOpen] = useState(false);
const textColorButtonRef = useRef<HTMLDivElement>(null) as RefObject<HTMLDivElement>;
const currentTextColor = data.textColor ?? DEFAULT_TEXT_COLOR;
return (
<div className="node-inspector">
<div className="node-inspector__header">
@@ -39,7 +108,123 @@ export function EdgeInspector({
<Button size="s" view="secondary" label="На задний план" onClick={onSendToBack} />
</div>
<TextField label="Подпись" size="s" value={label} onChange={(value) => onChange(value ?? '')} />
<TextField label="Подпись" size="s" value={label} onChange={(value) => onLabelChange(value ?? '')} />
<div className="node-inspector__field">
<Text size="xs" view="secondary">
Цвет линии
</Text>
<div className="node-inspector__presets">
{LINE_COLOR_PRESETS.map(({ hex, label: presetLabel }) => (
<button
key={hex}
type="button"
title={presetLabel}
aria-label={presetLabel}
className={`node-inspector__preset${currentColor === hex ? ' node-inspector__preset--active' : ''}`}
style={{ background: hex }}
onClick={() => onDataChange({ color: hex })}
/>
))}
</div>
<div ref={colorButtonRef} className="node-inspector__color-trigger">
<Button size="s" view="secondary" label="Настроить цвет" onClick={() => setColorPickerOpen(true)} />
</div>
{colorPickerOpen && (
<ColorPicker
model={hexModel}
value={currentColor}
onChange={(value) => onDataChange({ color: value })}
anchorRef={colorButtonRef}
open={colorPickerOpen}
onOpen={setColorPickerOpen}
/>
)}
</div>
<div className="node-inspector__field">
<Text size="xs" view="secondary">
Цвет текста
</Text>
<div className="node-inspector__presets">
{TEXT_COLOR_PRESETS.map(({ hex, label: presetLabel }) => (
<button
key={hex}
type="button"
title={presetLabel}
aria-label={presetLabel}
className={`node-inspector__preset${currentTextColor === hex ? ' node-inspector__preset--active' : ''}`}
style={{ background: hex }}
onClick={() => onDataChange({ textColor: hex })}
/>
))}
</div>
<div ref={textColorButtonRef} className="node-inspector__color-trigger">
<Button size="s" view="secondary" label="Настроить цвет" onClick={() => setTextColorPickerOpen(true)} />
</div>
{textColorPickerOpen && (
<ColorPicker
model={hexModel}
value={currentTextColor}
onChange={(value) => onDataChange({ textColor: value })}
anchorRef={textColorButtonRef}
open={textColorPickerOpen}
onOpen={setTextColorPickerOpen}
/>
)}
</div>
<TextField
label="Размер текста"
type="number"
size="s"
min={8}
max={32}
value={String(data.fontSize ?? DEFAULT_FONT_SIZE)}
onChange={(value) => {
const n = Number(value);
if (value && !Number.isNaN(n)) onDataChange({ fontSize: n });
}}
/>
<TextField
label="Толщина линии"
type="number"
size="s"
min={1}
max={8}
value={String(data.strokeWidth ?? DEFAULT_STROKE_WIDTH)}
onChange={(value) => {
const n = Number(value);
if (value && !Number.isNaN(n)) onDataChange({ strokeWidth: n });
}}
/>
<div className="node-inspector__field">
<Text size="xs" view="secondary">
Стиль линии
</Text>
<ChoiceGroup
size="xs"
name={`edge-line-style-${edgeId}`}
items={LINE_STYLE_ITEMS}
value={LINE_STYLE_ITEMS.find((item) => item.style === (data.lineStyle ?? 'solid')) ?? null}
onChange={(item) => onDataChange({ lineStyle: item.style })}
/>
</div>
<TextField
label="Скругление углов"
type="number"
size="s"
min={0}
max={20}
value={String(data.borderRadius ?? DEFAULT_BORDER_RADIUS)}
onChange={(value) => {
const n = Number(value);
if (value && !Number.isNaN(n)) onDataChange({ borderRadius: n });
}}
/>
</div>
);
}