F: Add space mode to ossFlow
Some checks are pending
Frontend CI / build (22.x) (push) Waiting to run
Frontend CI / notify-failure (push) Blocked by required conditions

This commit is contained in:
Ivan 2025-04-29 14:29:28 +03:00
parent a618a2bc42
commit e6a5b49b7a
6 changed files with 93 additions and 24 deletions

View File

@ -3,12 +3,15 @@ import {
IconAnimation,
IconAnimationOff,
IconChild,
IconConceptBlock,
IconConnect,
IconConsolidation,
IconCoordinates,
IconDestroy,
IconEdit2,
IconExecute,
IconFitImage,
IconFixLayout,
IconGrid,
IconLineStraight,
IconLineWave,
@ -16,7 +19,8 @@ import {
IconNewRSForm,
IconReset,
IconRSForm,
IconSave
IconSave,
IconSettings
} from '@/components/icons';
import { LinkTopic } from '../../components/link-topic';
@ -29,9 +33,19 @@ export function HelpOssGraph() {
<div className='flex flex-col sm:flex-row'>
<div className='sm:w-56'>
<h1>Настройка графа</h1>
<li>
<IconReset className='inline-icon' /> Сбросить изменения
</li>
<li>
<IconFitImage className='inline-icon' /> Вписать в экран
</li>
<li>
<IconFixLayout className='inline-icon' /> Исправить расположения
</li>
<li>
<IconSettings className='inline-icon' /> Диалог настроек
</li>
<li>
<IconGrid className='inline-icon' /> Отображение сетки
</li>
@ -43,6 +57,9 @@ export function HelpOssGraph() {
<IconAnimation className='inline-icon' />
<IconAnimationOff className='inline-icon' /> Анимация
</li>
<li>
<IconCoordinates className='inline-icon' /> Отображение координат
</li>
<li>черта сверху - Загрузка</li>
<li>
черта слева - КС <LinkTopic text='внешняя' topic={HelpTopic.CC_OSS} />
@ -63,11 +80,14 @@ export function HelpOssGraph() {
<kbd>Двойной клик</kbd> переход к связанной <LinkTopic text='КС' topic={HelpTopic.CC_SYSTEM} />
</li>
<li>
<IconEdit2 className='inline-icon' /> Редактирование операции
<IconConceptBlock className='inline-icon icon-green' /> Новый блок
</li>
<li>
<IconNewItem className='inline-icon icon-green' /> Новая операция
</li>
<li>
<IconEdit2 className='inline-icon' /> Редактирование узла
</li>
<li>
<IconDestroy className='inline-icon icon-red' /> <kbd>Delete</kbd> удалить выбранные
</li>
@ -80,10 +100,13 @@ export function HelpOssGraph() {
<div className='sm:w-56'>
<h1>Общие</h1>
<li>
<IconReset className='inline-icon' /> Сбросить изменения
<IconSave className='inline-icon' /> Сохранить положения
</li>
<li>
<IconSave className='inline-icon' /> Сохранить положения
<kbd>Space</kbd> перемещение экрана
</li>
<li>
<kbd>Shift</kbd> перемещение выделенных элементов в границах родителя
</li>
</div>

View File

@ -97,8 +97,6 @@ export class LayoutManager {
: Math.max(bottom, block.y + block.height + MIN_DISTANCE);
}
console.log('left, top, right, bottom', left, top, right, bottom);
for (const operation of operation_nodes) {
left = !left ? operation.x - MIN_DISTANCE : Math.min(left, operation.x - MIN_DISTANCE);
top = !top ? operation.y - MIN_DISTANCE : Math.min(top, operation.y - MIN_DISTANCE);

View File

@ -28,7 +28,7 @@ export function BlockNode(node: BlockInternalNode) {
return (
<>
<NodeResizeControl minWidth={BLOCK_NODE_MIN_WIDTH} minHeight={BLOCK_NODE_MIN_HEIGHT}>
<IconResize size={8} className='absolute bottom-[2px] right-[2px]' />
<IconResize size={8} className='absolute bottom-[2px] right-[2px] cc-graph-interactive' />
</NodeResizeControl>
{showCoordinates ? (
<div
@ -49,10 +49,10 @@ export function BlockNode(node: BlockInternalNode) {
isChild && 'border-accent-orange'
)}
>
<div className='absolute top-0 left-0 w-full h-2 pointer-events-auto cursor-pointer' />
<div className='absolute top-0 right-0 h-full w-2 pointer-events-auto cursor-pointer' />
<div className='absolute bottom-0 right-0 w-full h-2 pointer-events-auto cursor-pointer' />
<div className='absolute bottom-0 left-0 h-full w-2 pointer-events-auto cursor-pointer' />
<div className='absolute top-0 left-0 w-full h-2 cc-graph-interactive cursor-pointer' />
<div className='absolute top-0 right-0 h-full w-2 cc-graph-interactive cursor-pointer' />
<div className='absolute bottom-0 right-0 w-full h-2 cc-graph-interactive cursor-pointer' />
<div className='absolute bottom-0 left-0 h-full w-2 cc-graph-interactive cursor-pointer' />
<div
className={clsx(
@ -60,7 +60,7 @@ export function BlockNode(node: BlockInternalNode) {
'px-2',
'bg-background rounded-lg',
'text-[18px]/[20px] line-clamp-2 text-center text-ellipsis',
'pointer-events-auto cursor-pointer'
'cc-graph-interactive cursor-pointer'
)}
data-tooltip-id={globalIDs.operation_tooltip}
data-tooltip-hidden={node.dragging}

View File

@ -46,6 +46,7 @@ export function OssFlow() {
const { deleteBlock } = useDeleteBlock();
const [mouseCoords, setMouseCoords] = useState<Position2D>({ x: 0, y: 0 });
const [spacePressed, setSpacePressed] = useState(false);
const showCreateOperation = useDialogsStore(state => state.showCreateOperation);
const showCreateBlock = useDialogsStore(state => state.showCreateBlock);
@ -128,6 +129,12 @@ export function OssFlow() {
}
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
if (event.code === 'Space') {
event.preventDefault();
event.stopPropagation();
setSpacePressed(true);
return;
}
if (isProcessing) {
return;
}
@ -164,6 +171,12 @@ export function OssFlow() {
}
}
function handleKeyUp(event: React.KeyboardEvent<HTMLDivElement>) {
if (event.code === 'Space') {
setSpacePressed(false);
}
}
function handleMouseMove(event: React.MouseEvent<HTMLDivElement>) {
const targetPosition = screenToFlowPosition({ x: event.clientX, y: event.clientY });
setMouseCoords(targetPosition);
@ -174,6 +187,7 @@ export function OssFlow() {
tabIndex={-1}
className='relative'
onKeyDown={handleKeyDown}
onKeyUp={handleKeyUp}
onMouseMove={showCoordinates ? handleMouseMove : undefined}
>
{showCoordinates ? <CoordinateDisplay mouseCoords={mouseCoords} className='absolute top-1 right-2' /> : null}
@ -188,14 +202,18 @@ export function OssFlow() {
<ContextMenu isOpen={isContextMenuOpen} onHide={hideContextMenu} {...menuProps} />
<div
className={clsx('relative w-[100vw] cc-mask-sides', !containMovement && 'cursor-relocate')}
className={clsx(
'relative w-[100vw] cc-mask-sides',
spacePressed ? 'space-mode' : '',
!containMovement && 'cursor-relocate'
)}
style={{ height: mainHeight, fontFamily: 'Rubik' }}
>
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onNodesChange={spacePressed ? undefined : onNodesChange}
onEdgesChange={spacePressed ? undefined : onEdgesChange}
edgesFocusable={false}
nodesFocusable={false}
fitView
@ -206,15 +224,16 @@ export function OssFlow() {
snapToGrid={true}
snapGrid={[GRID_SIZE, GRID_SIZE]}
onClick={hideContextMenu}
onNodeDoubleClick={handleNodeDoubleClick}
onNodeDoubleClick={spacePressed ? undefined : handleNodeDoubleClick}
onNodeContextMenu={handleContextMenu}
onContextMenu={event => {
event.preventDefault();
hideContextMenu();
}}
onNodeDragStart={handleDragStart}
onNodeDrag={handleDrag}
onNodeDragStop={handleDragStop}
nodesDraggable={!spacePressed}
onNodeDragStart={spacePressed ? undefined : handleDragStart}
onNodeDrag={spacePressed ? undefined : handleDrag}
onNodeDragStop={spacePressed ? undefined : handleDragStop}
>
{showGrid ? <Background gap={GRID_SIZE} /> : null}
</ReactFlow>

View File

@ -6,6 +6,8 @@
/* stylelint-disable selector-class-pattern */
.react-flow__handle {
pointer-events: auto;
z-index: var(--z-index-navigation);
cursor: default !important;
border-radius: 9999px;
@ -16,6 +18,10 @@
.selected & {
border-color: var(--color-muted-foreground);
}
.space-mode & {
pointer-events: none !important;
}
}
.react-flow__resize-control.handle {
@ -31,14 +37,26 @@
&:hover {
color: var(--color-foreground);
}
.space-mode & {
pointer-events: none !important;
}
}
.react-flow__pane {
cursor: default;
cursor: inherit;
.space-mode & {
cursor: grab;
&.dragging {
cursor: grabbing;
}
}
}
.react-flow__edge {
cursor: default;
cursor: inherit;
}
.react-flow__attribution {
@ -52,8 +70,13 @@
}
[class*='react-flow__node-'] {
.space-mode & {
box-shadow: none;
pointer-events: none !important;
}
&:hover:not(.selected) {
box-shadow: 0 0 0 2px var(--color-selected) !important;
box-shadow: 0 0 0 2px var(--color-selected);
}
}
@ -138,8 +161,6 @@
.react-flow__node-input,
.react-flow__node-synthesis {
cursor: pointer;
border-radius: 5px;
border-width: 0;

View File

@ -205,3 +205,11 @@
--tw-duration: var(--duration-move);
transition-duration: var(--duration-move);
}
@utility cc-graph-interactive {
pointer-events: auto;
.space-mode & {
pointer-events: none;
}
}