Небольшие правки

This commit is contained in:
NikitaKalitov
2026-07-22 11:23:05 +03:00
parent 4852e55964
commit 5b8aaf0577
3 changed files with 71 additions and 44 deletions
-7
View File
@@ -1,10 +1,3 @@
/*
Извлечено со скриншотов брендбука/стайлгайда.
Угол градиента в источнике указан как «60%» — трактован как 60deg
(стандартная запись угла в CSS linear-gradient). Проверьте по оригиналу,
если это принципиально.
*/
:root { :root {
/* ============================================================ /* ============================================================
ОСНОВНЫЕ ГРАДИЕНТЫ (синие) — для инфоблоков, диаграмм, блок-схем ОСНОВНЫЕ ГРАДИЕНТЫ (синие) — для инфоблоков, диаграмм, блок-схем
+2
View File
@@ -61,6 +61,7 @@
.diagram-node__label { .diagram-node__label {
white-space: pre-wrap; white-space: pre-wrap;
overflow-wrap: break-word; overflow-wrap: break-word;
font-weight: 600;
} }
.diagram-node__badge { .diagram-node__badge {
@@ -89,6 +90,7 @@
max-width: 120px; max-width: 120px;
text-align: center; text-align: center;
white-space: pre-wrap; white-space: pre-wrap;
font-weight: 600;
} }
.diagram-node--circle { .diagram-node--circle {
+69 -37
View File
@@ -1,6 +1,12 @@
import { createContext, useContext } from 'react'; import { createContext, useContext } from "react";
import { Handle, NodeResizer, Position, type Node, type NodeProps } from '@xyflow/react'; import {
import type { DiagramNodeData, NodeKind } from './types'; Handle,
NodeResizer,
Position,
type Node,
type NodeProps,
} from "@xyflow/react";
import type { DiagramNodeData, NodeKind } from "./types";
type ShapeNode = Node<DiagramNodeData, NodeKind>; type ShapeNode = Node<DiagramNodeData, NodeKind>;
@@ -8,31 +14,31 @@ type ShapeNode = Node<DiagramNodeData, NodeKind>;
export const NodesWithChildrenContext = createContext<Set<string>>(new Set()); export const NodesWithChildrenContext = createContext<Set<string>>(new Set());
/** Current editor mode — resize handles and connection points only show in 'edit'. */ /** Current editor mode — resize handles and connection points only show in 'edit'. */
export const ModeContext = createContext<'edit' | 'view'>('edit'); export const ModeContext = createContext<"edit" | "view">("edit");
// Gradients from palette.css's "ОСНОВНАЯ ПАЛИТРА" section — the one the // Gradients from palette.css's "ОСНОВНАЯ ПАЛИТРА" section — the one the
// palette itself labels as meant for diagrams/flowcharts/semantic highlights. // palette itself labels as meant for diagrams/flowcharts/semantic highlights.
// This is what nodes actually render with until a user picks a custom color. // This is what nodes actually render with until a user picks a custom color.
export const DEFAULT_NODE_BACKGROUND: Record<NodeKind, string> = { export const DEFAULT_NODE_BACKGROUND: Record<NodeKind, string> = {
task: 'var(--gradient-blue)', task: "var(--gradient-blue)",
startEvent: 'var(--gradient-green)', startEvent: "var(--gradient-green)",
intermediateEvent: 'var(--gradient-orange)', intermediateEvent: "var(--gradient-orange)",
endEvent: 'var(--gradient-red)', endEvent: "var(--gradient-red)",
exclusiveGateway: 'var(--gradient-purple)', exclusiveGateway: "var(--gradient-purple)",
parallelGateway: 'var(--gradient-cyan)', parallelGateway: "var(--gradient-cyan)",
inclusiveGateway: 'var(--gradient-olive)', inclusiveGateway: "var(--gradient-olive)",
}; };
// The color picker only understands flat hex, so it needs a solid fallback // The color picker only understands flat hex, so it needs a solid fallback
// distinct from the gradient rendered on canvas — the gradient's start color. // distinct from the gradient rendered on canvas — the gradient's start color.
export const DEFAULT_NODE_COLOR: Record<NodeKind, string> = { export const DEFAULT_NODE_COLOR: Record<NodeKind, string> = {
task: '#0790CB', task: "#0790CB",
startEvent: '#2CB587', startEvent: "#2CB587",
intermediateEvent: '#FF8E58', intermediateEvent: "#FF8E58",
endEvent: '#E13042', endEvent: "#E13042",
exclusiveGateway: '#A12C7E', exclusiveGateway: "#A12C7E",
parallelGateway: '#1BD3F7', parallelGateway: "#1BD3F7",
inclusiveGateway: '#BBBD39', inclusiveGateway: "#BBBD39",
}; };
export const DEFAULT_TASK_BORDER_RADIUS = 6; export const DEFAULT_TASK_BORDER_RADIUS = 6;
@@ -41,15 +47,15 @@ export const DEFAULT_TASK_BORDER_RADIUS = 6;
// default; the caption below events/gateways sits on the plain canvas // default; the caption below events/gateways sits on the plain canvas
// background instead and needs a dark one. Both are overridable via the // background instead and needs a dark one. Both are overridable via the
// same `data.textColor`/`data.fontSize`. // same `data.textColor`/`data.fontSize`.
export const DEFAULT_NODE_TEXT_COLOR = '#FFFFFF'; export const DEFAULT_NODE_TEXT_COLOR = "#FFFFFF";
export const DEFAULT_CAPTION_TEXT_COLOR = '#525A64'; export const DEFAULT_CAPTION_TEXT_COLOR = "#525A64";
export const DEFAULT_NODE_FONT_SIZE = 12; export const DEFAULT_NODE_FONT_SIZE = 12;
const HANDLE_POSITIONS: { id: string; position: Position }[] = [ const HANDLE_POSITIONS: { id: string; position: Position }[] = [
{ id: 'top', position: Position.Top }, { id: "top", position: Position.Top },
{ id: 'right', position: Position.Right }, { id: "right", position: Position.Right },
{ id: 'bottom', position: Position.Bottom }, { id: "bottom", position: Position.Bottom },
{ id: 'left', position: Position.Left }, { id: "left", position: Position.Left },
]; ];
/** /**
@@ -71,7 +77,10 @@ function SubProcessBadge({ id }: { id: string }) {
const withChildren = useContext(NodesWithChildrenContext); const withChildren = useContext(NodesWithChildrenContext);
if (!withChildren.has(id)) return null; if (!withChildren.has(id)) return null;
return ( return (
<span className="diagram-node__badge" title="Есть вложенные узлы — двойной клик, чтобы открыть"> <span
className="diagram-node__badge"
title="Есть вложенные узлы — двойной клик, чтобы открыть"
>
⊞ ⊞
</span> </span>
); );
@@ -91,7 +100,7 @@ function ShapeResizer({
const mode = useContext(ModeContext); const mode = useContext(ModeContext);
return ( return (
<NodeResizer <NodeResizer
isVisible={selected && mode === 'edit'} isVisible={selected && mode === "edit"}
minWidth={minWidth} minWidth={minWidth}
minHeight={minHeight} minHeight={minHeight}
keepAspectRatio={keepAspectRatio} keepAspectRatio={keepAspectRatio}
@@ -108,12 +117,20 @@ function TaskNode({ id, data, selected }: NodeProps<ShapeNode>) {
borderRadius: data.borderRadius ?? DEFAULT_TASK_BORDER_RADIUS, borderRadius: data.borderRadius ?? DEFAULT_TASK_BORDER_RADIUS,
}} }}
> >
<ShapeResizer selected={selected} minWidth={70} minHeight={32} keepAspectRatio={false} /> <ShapeResizer
selected={selected}
minWidth={70}
minHeight={32}
keepAspectRatio={false}
/>
<ShapeHandles /> <ShapeHandles />
<SubProcessBadge id={id} /> <SubProcessBadge id={id} />
<span <span
className="diagram-node__label" className="diagram-node__label"
style={{ color: data.textColor ?? DEFAULT_NODE_TEXT_COLOR, fontSize: data.fontSize ?? DEFAULT_NODE_FONT_SIZE }} style={{
color: data.textColor ?? DEFAULT_NODE_TEXT_COLOR,
fontSize: data.fontSize ?? DEFAULT_NODE_FONT_SIZE,
}}
> >
{data.label} {data.label}
</span> </span>
@@ -122,7 +139,8 @@ function TaskNode({ id, data, selected }: NodeProps<ShapeNode>) {
} }
function EventNode({ id, data, type, selected }: NodeProps<ShapeNode>) { function EventNode({ id, data, type, selected }: NodeProps<ShapeNode>) {
const kind = (type as 'startEvent' | 'intermediateEvent' | 'endEvent') ?? 'startEvent'; const kind =
(type as "startEvent" | "intermediateEvent" | "endEvent") ?? "startEvent";
return ( return (
<div <div
className="diagram-node diagram-node--circle" className="diagram-node diagram-node--circle"
@@ -133,7 +151,10 @@ function EventNode({ id, data, type, selected }: NodeProps<ShapeNode>) {
<SubProcessBadge id={id} /> <SubProcessBadge id={id} />
<span <span
className="diagram-node__caption" className="diagram-node__caption"
style={{ color: data.textColor ?? DEFAULT_CAPTION_TEXT_COLOR, fontSize: data.fontSize ?? DEFAULT_NODE_FONT_SIZE }} style={{
color: data.textColor ?? DEFAULT_CAPTION_TEXT_COLOR,
fontSize: data.fontSize ?? DEFAULT_NODE_FONT_SIZE,
}}
> >
{data.label} {data.label}
</span> </span>
@@ -141,14 +162,19 @@ function EventNode({ id, data, type, selected }: NodeProps<ShapeNode>) {
); );
} }
const GATEWAY_ICON: Record<'exclusiveGateway' | 'parallelGateway' | 'inclusiveGateway', string> = { const GATEWAY_ICON: Record<
exclusiveGateway: '✕', "exclusiveGateway" | "parallelGateway" | "inclusiveGateway",
parallelGateway: '+', string
inclusiveGateway: '○', > = {
exclusiveGateway: "✕",
parallelGateway: "+",
inclusiveGateway: "○",
}; };
function GatewayNode({ id, data, type, selected }: NodeProps<ShapeNode>) { function GatewayNode({ id, data, type, selected }: NodeProps<ShapeNode>) {
const kind = (type as 'exclusiveGateway' | 'parallelGateway' | 'inclusiveGateway') ?? 'exclusiveGateway'; const kind =
(type as "exclusiveGateway" | "parallelGateway" | "inclusiveGateway") ??
"exclusiveGateway";
return ( return (
<div className="diagram-node--gateway-outer"> <div className="diagram-node--gateway-outer">
<ShapeResizer selected={selected} minWidth={32} minHeight={32} /> <ShapeResizer selected={selected} minWidth={32} minHeight={32} />
@@ -165,13 +191,19 @@ function GatewayNode({ id, data, type, selected }: NodeProps<ShapeNode>) {
of it, since clip-path would otherwise cut off anything of theirs of it, since clip-path would otherwise cut off anything of theirs
that renders outside the diamond outline. that renders outside the diamond outline.
*/} */}
<div className="diagram-node--diamond-bg" style={{ background: data.color ?? DEFAULT_NODE_BACKGROUND[kind] }} /> <div
className="diagram-node--diamond-bg"
style={{ background: data.color ?? DEFAULT_NODE_BACKGROUND[kind] }}
/>
<ShapeHandles /> <ShapeHandles />
<SubProcessBadge id={id} /> <SubProcessBadge id={id} />
<span className="diagram-node__icon">{GATEWAY_ICON[kind]}</span> <span className="diagram-node__icon">{GATEWAY_ICON[kind]}</span>
<span <span
className="diagram-node__caption" className="diagram-node__caption"
style={{ color: data.textColor ?? DEFAULT_CAPTION_TEXT_COLOR, fontSize: data.fontSize ?? DEFAULT_NODE_FONT_SIZE }} style={{
color: data.textColor ?? DEFAULT_CAPTION_TEXT_COLOR,
fontSize: data.fontSize ?? DEFAULT_NODE_FONT_SIZE,
}}
> >
{data.label} {data.label}
</span> </span>