Начал переводить на consta UI
This commit is contained in:
+107
-63
@@ -1,6 +1,28 @@
|
||||
import { useRef, useState, type RefObject } from 'react';
|
||||
import { Button } from '@consta/uikit/Button';
|
||||
import { TextField } from '@consta/uikit/TextField';
|
||||
import { ColorControl, ColorPicker, hexModel } from '@consta/uikit/ColorPicker';
|
||||
import { Text } from '@consta/uikit/Text';
|
||||
import { DEFAULT_NODE_COLOR } from './nodes';
|
||||
import type { DiagramNodeData, NodeKind } from './types';
|
||||
|
||||
// "Дополнительные цвета" from palette.css — the section the palette itself
|
||||
// marks as meant for single-color accents (as opposed to the gradients used
|
||||
// for shape defaults, which a flat-hex picker can't represent).
|
||||
const NODE_COLOR_PRESETS = [
|
||||
'#B5309A',
|
||||
'#EC5665',
|
||||
'#FFAB66',
|
||||
'#C2DC5B',
|
||||
'#32CA88',
|
||||
'#22926D',
|
||||
'#0EBAD5',
|
||||
'#4EE7F4',
|
||||
'#9152E6',
|
||||
'#9D9AF7',
|
||||
'#E88FDB',
|
||||
];
|
||||
|
||||
const TYPE_LABELS: Record<NodeKind, string> = {
|
||||
task: 'Задача',
|
||||
startEvent: 'Начальное событие',
|
||||
@@ -38,17 +60,29 @@ export function NodeInspector({
|
||||
onBringToFront,
|
||||
onSendToBack,
|
||||
}: NodeInspectorProps) {
|
||||
const [colorPickerOpen, setColorPickerOpen] = useState(false);
|
||||
// Consta's ref props still use the pre-React-19 non-nullable RefObject shape.
|
||||
const colorMarkerRef = useRef<HTMLButtonElement>(null) as RefObject<HTMLButtonElement>;
|
||||
|
||||
if (mode === 'view') {
|
||||
const hasMeta = Boolean(data.responsible || data.duration);
|
||||
return (
|
||||
<div className="node-inspector">
|
||||
<div className="node-inspector__header">
|
||||
<span className="node-inspector__type">{TYPE_LABELS[nodeType]}</span>
|
||||
<Text size="s" weight="semibold">
|
||||
{TYPE_LABELS[nodeType]}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<h3 className="node-inspector__label">{data.label}</h3>
|
||||
<Text size="l" className="node-inspector__label">
|
||||
{data.label}
|
||||
</Text>
|
||||
|
||||
{data.description && <p className="node-inspector__description">{data.description}</p>}
|
||||
{data.description && (
|
||||
<Text size="s" view="secondary" className="node-inspector__description">
|
||||
{data.description}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{hasMeta && (
|
||||
<dl className="node-inspector__meta">
|
||||
@@ -68,9 +102,12 @@ export function NodeInspector({
|
||||
)}
|
||||
|
||||
{childCount > 0 && (
|
||||
<button type="button" className="node-inspector__action" onClick={() => onEnterSubProcess(nodeId)}>
|
||||
Открыть вложенный процесс →
|
||||
</button>
|
||||
<Button
|
||||
size="s"
|
||||
view="ghost"
|
||||
label="Открыть вложенный процесс →"
|
||||
onClick={() => onEnterSubProcess(nodeId)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
@@ -79,81 +116,88 @@ export function NodeInspector({
|
||||
return (
|
||||
<div className="node-inspector">
|
||||
<div className="node-inspector__header">
|
||||
<span className="node-inspector__type">{TYPE_LABELS[nodeType]}</span>
|
||||
<code className="node-inspector__id">{nodeId}</code>
|
||||
<Text size="s" weight="semibold">
|
||||
{TYPE_LABELS[nodeType]}
|
||||
</Text>
|
||||
<Text size="xs" view="secondary" font="mono">
|
||||
{nodeId}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div className="node-inspector__toolbar">
|
||||
<button type="button" onClick={onDuplicate}>
|
||||
Дублировать
|
||||
</button>
|
||||
<button type="button" onClick={onDelete}>
|
||||
Удалить
|
||||
</button>
|
||||
<Button size="s" view="secondary" label="Дублировать" onClick={onDuplicate} />
|
||||
<Button size="s" view="secondary" label="Удалить" onClick={onDelete} />
|
||||
</div>
|
||||
|
||||
<div className="node-inspector__toolbar">
|
||||
<button type="button" onClick={onBringToFront}>
|
||||
На передний план
|
||||
</button>
|
||||
<button type="button" onClick={onSendToBack}>
|
||||
На задний план
|
||||
</button>
|
||||
<Button size="s" view="secondary" label="На передний план" onClick={onBringToFront} />
|
||||
<Button size="s" view="secondary" label="На задний план" onClick={onSendToBack} />
|
||||
</div>
|
||||
|
||||
<label className="node-inspector__field node-inspector__field--color">
|
||||
Цвет фона
|
||||
<input
|
||||
type="color"
|
||||
<div className="node-inspector__field">
|
||||
<Text size="xs" view="secondary">
|
||||
Цвет фона
|
||||
</Text>
|
||||
<ColorControl
|
||||
markerRef={colorMarkerRef}
|
||||
model={hexModel}
|
||||
value={data.color ?? DEFAULT_NODE_COLOR[nodeType]}
|
||||
onChange={(e) => onChange({ color: e.target.value })}
|
||||
onChange={(value) => onChange({ color: value })}
|
||||
size="s"
|
||||
onClick={() => setColorPickerOpen(true)}
|
||||
/>
|
||||
</label>
|
||||
{colorPickerOpen && (
|
||||
<ColorPicker
|
||||
model={hexModel}
|
||||
value={data.color ?? DEFAULT_NODE_COLOR[nodeType]}
|
||||
onChange={(value) => onChange({ color: value })}
|
||||
anchorRef={colorMarkerRef}
|
||||
open={colorPickerOpen}
|
||||
onOpen={setColorPickerOpen}
|
||||
palette={NODE_COLOR_PRESETS}
|
||||
paletteTitle="Пресеты"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<label className="node-inspector__field">
|
||||
Название
|
||||
<textarea
|
||||
rows={2}
|
||||
value={data.label}
|
||||
onChange={(e) => onChange({ label: e.target.value })}
|
||||
/>
|
||||
</label>
|
||||
<TextField
|
||||
label="Название"
|
||||
type="textarea"
|
||||
rows={2}
|
||||
size="s"
|
||||
value={data.label}
|
||||
onChange={(value) => onChange({ label: value ?? '' })}
|
||||
/>
|
||||
|
||||
<label className="node-inspector__field">
|
||||
Описание
|
||||
<textarea
|
||||
rows={3}
|
||||
value={data.description ?? ''}
|
||||
onChange={(e) => onChange({ description: e.target.value })}
|
||||
/>
|
||||
</label>
|
||||
<TextField
|
||||
label="Описание"
|
||||
type="textarea"
|
||||
rows={3}
|
||||
size="s"
|
||||
value={data.description ?? ''}
|
||||
onChange={(value) => onChange({ description: value ?? '' })}
|
||||
/>
|
||||
|
||||
<label className="node-inspector__field">
|
||||
Ответственный
|
||||
<input
|
||||
type="text"
|
||||
value={data.responsible ?? ''}
|
||||
onChange={(e) => onChange({ responsible: e.target.value })}
|
||||
/>
|
||||
</label>
|
||||
<TextField
|
||||
label="Ответственный"
|
||||
size="s"
|
||||
value={data.responsible ?? ''}
|
||||
onChange={(value) => onChange({ responsible: value ?? '' })}
|
||||
/>
|
||||
|
||||
<label className="node-inspector__field">
|
||||
Длительность
|
||||
<input
|
||||
type="text"
|
||||
value={data.duration ?? ''}
|
||||
onChange={(e) => onChange({ duration: e.target.value })}
|
||||
/>
|
||||
</label>
|
||||
<TextField
|
||||
label="Длительность"
|
||||
size="s"
|
||||
value={data.duration ?? ''}
|
||||
onChange={(value) => onChange({ duration: value ?? '' })}
|
||||
/>
|
||||
|
||||
<button type="button" className="node-inspector__action" onClick={() => onEnterSubProcess(nodeId)}>
|
||||
Войти в под-процесс →
|
||||
</button>
|
||||
<p className="node-inspector__hint">
|
||||
<Button size="s" view="ghost" label="Войти в под-процесс →" onClick={() => onEnterSubProcess(nodeId)} />
|
||||
<Text size="xs" view="secondary" className="node-inspector__hint">
|
||||
{childCount > 0
|
||||
? `Внутри уже ${childCount} узл(ов).`
|
||||
: 'Пока пусто — зайдя внутрь, можно добавить узлы детального разбора этого шага.'}
|
||||
</p>
|
||||
</Text>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user