mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-25 20:40:36 +03:00
F: Add space mode to ossFlow
This commit is contained in:
parent
a618a2bc42
commit
e6a5b49b7a
|
@ -3,12 +3,15 @@ import {
|
||||||
IconAnimation,
|
IconAnimation,
|
||||||
IconAnimationOff,
|
IconAnimationOff,
|
||||||
IconChild,
|
IconChild,
|
||||||
|
IconConceptBlock,
|
||||||
IconConnect,
|
IconConnect,
|
||||||
IconConsolidation,
|
IconConsolidation,
|
||||||
|
IconCoordinates,
|
||||||
IconDestroy,
|
IconDestroy,
|
||||||
IconEdit2,
|
IconEdit2,
|
||||||
IconExecute,
|
IconExecute,
|
||||||
IconFitImage,
|
IconFitImage,
|
||||||
|
IconFixLayout,
|
||||||
IconGrid,
|
IconGrid,
|
||||||
IconLineStraight,
|
IconLineStraight,
|
||||||
IconLineWave,
|
IconLineWave,
|
||||||
|
@ -16,7 +19,8 @@ import {
|
||||||
IconNewRSForm,
|
IconNewRSForm,
|
||||||
IconReset,
|
IconReset,
|
||||||
IconRSForm,
|
IconRSForm,
|
||||||
IconSave
|
IconSave,
|
||||||
|
IconSettings
|
||||||
} from '@/components/icons';
|
} from '@/components/icons';
|
||||||
|
|
||||||
import { LinkTopic } from '../../components/link-topic';
|
import { LinkTopic } from '../../components/link-topic';
|
||||||
|
@ -29,9 +33,19 @@ export function HelpOssGraph() {
|
||||||
<div className='flex flex-col sm:flex-row'>
|
<div className='flex flex-col sm:flex-row'>
|
||||||
<div className='sm:w-56'>
|
<div className='sm:w-56'>
|
||||||
<h1>Настройка графа</h1>
|
<h1>Настройка графа</h1>
|
||||||
|
<li>
|
||||||
|
<IconReset className='inline-icon' /> Сбросить изменения
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<IconFitImage className='inline-icon' /> Вписать в экран
|
<IconFitImage className='inline-icon' /> Вписать в экран
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconFixLayout className='inline-icon' /> Исправить расположения
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconSettings className='inline-icon' /> Диалог настроек
|
||||||
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<IconGrid className='inline-icon' /> Отображение сетки
|
<IconGrid className='inline-icon' /> Отображение сетки
|
||||||
</li>
|
</li>
|
||||||
|
@ -43,6 +57,9 @@ export function HelpOssGraph() {
|
||||||
<IconAnimation className='inline-icon' />
|
<IconAnimation className='inline-icon' />
|
||||||
<IconAnimationOff className='inline-icon' /> Анимация
|
<IconAnimationOff className='inline-icon' /> Анимация
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconCoordinates className='inline-icon' /> Отображение координат
|
||||||
|
</li>
|
||||||
<li>черта сверху - Загрузка</li>
|
<li>черта сверху - Загрузка</li>
|
||||||
<li>
|
<li>
|
||||||
черта слева - КС <LinkTopic text='внешняя' topic={HelpTopic.CC_OSS} />
|
черта слева - КС <LinkTopic text='внешняя' topic={HelpTopic.CC_OSS} />
|
||||||
|
@ -63,11 +80,14 @@ export function HelpOssGraph() {
|
||||||
<kbd>Двойной клик</kbd> – переход к связанной <LinkTopic text='КС' topic={HelpTopic.CC_SYSTEM} />
|
<kbd>Двойной клик</kbd> – переход к связанной <LinkTopic text='КС' topic={HelpTopic.CC_SYSTEM} />
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<IconEdit2 className='inline-icon' /> Редактирование операции
|
<IconConceptBlock className='inline-icon icon-green' /> Новый блок
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<IconNewItem className='inline-icon icon-green' /> Новая операция
|
<IconNewItem className='inline-icon icon-green' /> Новая операция
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconEdit2 className='inline-icon' /> Редактирование узла
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<IconDestroy className='inline-icon icon-red' /> <kbd>Delete</kbd> – удалить выбранные
|
<IconDestroy className='inline-icon icon-red' /> <kbd>Delete</kbd> – удалить выбранные
|
||||||
</li>
|
</li>
|
||||||
|
@ -80,10 +100,13 @@ export function HelpOssGraph() {
|
||||||
<div className='sm:w-56'>
|
<div className='sm:w-56'>
|
||||||
<h1>Общие</h1>
|
<h1>Общие</h1>
|
||||||
<li>
|
<li>
|
||||||
<IconReset className='inline-icon' /> Сбросить изменения
|
<IconSave className='inline-icon' /> Сохранить положения
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<IconSave className='inline-icon' /> Сохранить положения
|
<kbd>Space</kbd> – перемещение экрана
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<kbd>Shift</kbd> – перемещение выделенных элементов в границах родителя
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -97,8 +97,6 @@ export class LayoutManager {
|
||||||
: Math.max(bottom, block.y + block.height + MIN_DISTANCE);
|
: 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) {
|
for (const operation of operation_nodes) {
|
||||||
left = !left ? operation.x - MIN_DISTANCE : Math.min(left, operation.x - MIN_DISTANCE);
|
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);
|
top = !top ? operation.y - MIN_DISTANCE : Math.min(top, operation.y - MIN_DISTANCE);
|
||||||
|
|
|
@ -28,7 +28,7 @@ export function BlockNode(node: BlockInternalNode) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NodeResizeControl minWidth={BLOCK_NODE_MIN_WIDTH} minHeight={BLOCK_NODE_MIN_HEIGHT}>
|
<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>
|
</NodeResizeControl>
|
||||||
{showCoordinates ? (
|
{showCoordinates ? (
|
||||||
<div
|
<div
|
||||||
|
@ -49,10 +49,10 @@ export function BlockNode(node: BlockInternalNode) {
|
||||||
isChild && 'border-accent-orange'
|
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 left-0 w-full h-2 cc-graph-interactive cursor-pointer' />
|
||||||
<div className='absolute top-0 right-0 h-full w-2 pointer-events-auto 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 pointer-events-auto 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 pointer-events-auto cursor-pointer' />
|
<div className='absolute bottom-0 left-0 h-full w-2 cc-graph-interactive cursor-pointer' />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
@ -60,7 +60,7 @@ export function BlockNode(node: BlockInternalNode) {
|
||||||
'px-2',
|
'px-2',
|
||||||
'bg-background rounded-lg',
|
'bg-background rounded-lg',
|
||||||
'text-[18px]/[20px] line-clamp-2 text-center text-ellipsis',
|
'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-id={globalIDs.operation_tooltip}
|
||||||
data-tooltip-hidden={node.dragging}
|
data-tooltip-hidden={node.dragging}
|
||||||
|
|
|
@ -46,6 +46,7 @@ export function OssFlow() {
|
||||||
const { deleteBlock } = useDeleteBlock();
|
const { deleteBlock } = useDeleteBlock();
|
||||||
|
|
||||||
const [mouseCoords, setMouseCoords] = useState<Position2D>({ x: 0, y: 0 });
|
const [mouseCoords, setMouseCoords] = useState<Position2D>({ x: 0, y: 0 });
|
||||||
|
const [spacePressed, setSpacePressed] = useState(false);
|
||||||
|
|
||||||
const showCreateOperation = useDialogsStore(state => state.showCreateOperation);
|
const showCreateOperation = useDialogsStore(state => state.showCreateOperation);
|
||||||
const showCreateBlock = useDialogsStore(state => state.showCreateBlock);
|
const showCreateBlock = useDialogsStore(state => state.showCreateBlock);
|
||||||
|
@ -128,6 +129,12 @@ export function OssFlow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
|
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
|
||||||
|
if (event.code === 'Space') {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
setSpacePressed(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isProcessing) {
|
if (isProcessing) {
|
||||||
return;
|
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>) {
|
function handleMouseMove(event: React.MouseEvent<HTMLDivElement>) {
|
||||||
const targetPosition = screenToFlowPosition({ x: event.clientX, y: event.clientY });
|
const targetPosition = screenToFlowPosition({ x: event.clientX, y: event.clientY });
|
||||||
setMouseCoords(targetPosition);
|
setMouseCoords(targetPosition);
|
||||||
|
@ -174,6 +187,7 @@ export function OssFlow() {
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
className='relative'
|
className='relative'
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
|
onKeyUp={handleKeyUp}
|
||||||
onMouseMove={showCoordinates ? handleMouseMove : undefined}
|
onMouseMove={showCoordinates ? handleMouseMove : undefined}
|
||||||
>
|
>
|
||||||
{showCoordinates ? <CoordinateDisplay mouseCoords={mouseCoords} className='absolute top-1 right-2' /> : null}
|
{showCoordinates ? <CoordinateDisplay mouseCoords={mouseCoords} className='absolute top-1 right-2' /> : null}
|
||||||
|
@ -188,14 +202,18 @@ export function OssFlow() {
|
||||||
<ContextMenu isOpen={isContextMenuOpen} onHide={hideContextMenu} {...menuProps} />
|
<ContextMenu isOpen={isContextMenuOpen} onHide={hideContextMenu} {...menuProps} />
|
||||||
|
|
||||||
<div
|
<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' }}
|
style={{ height: mainHeight, fontFamily: 'Rubik' }}
|
||||||
>
|
>
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
onNodesChange={onNodesChange}
|
onNodesChange={spacePressed ? undefined : onNodesChange}
|
||||||
onEdgesChange={onEdgesChange}
|
onEdgesChange={spacePressed ? undefined : onEdgesChange}
|
||||||
edgesFocusable={false}
|
edgesFocusable={false}
|
||||||
nodesFocusable={false}
|
nodesFocusable={false}
|
||||||
fitView
|
fitView
|
||||||
|
@ -206,15 +224,16 @@ export function OssFlow() {
|
||||||
snapToGrid={true}
|
snapToGrid={true}
|
||||||
snapGrid={[GRID_SIZE, GRID_SIZE]}
|
snapGrid={[GRID_SIZE, GRID_SIZE]}
|
||||||
onClick={hideContextMenu}
|
onClick={hideContextMenu}
|
||||||
onNodeDoubleClick={handleNodeDoubleClick}
|
onNodeDoubleClick={spacePressed ? undefined : handleNodeDoubleClick}
|
||||||
onNodeContextMenu={handleContextMenu}
|
onNodeContextMenu={handleContextMenu}
|
||||||
onContextMenu={event => {
|
onContextMenu={event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
hideContextMenu();
|
hideContextMenu();
|
||||||
}}
|
}}
|
||||||
onNodeDragStart={handleDragStart}
|
nodesDraggable={!spacePressed}
|
||||||
onNodeDrag={handleDrag}
|
onNodeDragStart={spacePressed ? undefined : handleDragStart}
|
||||||
onNodeDragStop={handleDragStop}
|
onNodeDrag={spacePressed ? undefined : handleDrag}
|
||||||
|
onNodeDragStop={spacePressed ? undefined : handleDragStop}
|
||||||
>
|
>
|
||||||
{showGrid ? <Background gap={GRID_SIZE} /> : null}
|
{showGrid ? <Background gap={GRID_SIZE} /> : null}
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
/* stylelint-disable selector-class-pattern */
|
/* stylelint-disable selector-class-pattern */
|
||||||
|
|
||||||
.react-flow__handle {
|
.react-flow__handle {
|
||||||
|
pointer-events: auto;
|
||||||
|
|
||||||
z-index: var(--z-index-navigation);
|
z-index: var(--z-index-navigation);
|
||||||
cursor: default !important;
|
cursor: default !important;
|
||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
|
@ -16,6 +18,10 @@
|
||||||
.selected & {
|
.selected & {
|
||||||
border-color: var(--color-muted-foreground);
|
border-color: var(--color-muted-foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.space-mode & {
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-flow__resize-control.handle {
|
.react-flow__resize-control.handle {
|
||||||
|
@ -31,14 +37,26 @@
|
||||||
&:hover {
|
&:hover {
|
||||||
color: var(--color-foreground);
|
color: var(--color-foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.space-mode & {
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-flow__pane {
|
.react-flow__pane {
|
||||||
cursor: default;
|
cursor: inherit;
|
||||||
|
|
||||||
|
.space-mode & {
|
||||||
|
cursor: grab;
|
||||||
|
|
||||||
|
&.dragging {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-flow__edge {
|
.react-flow__edge {
|
||||||
cursor: default;
|
cursor: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-flow__attribution {
|
.react-flow__attribution {
|
||||||
|
@ -52,8 +70,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
[class*='react-flow__node-'] {
|
[class*='react-flow__node-'] {
|
||||||
|
.space-mode & {
|
||||||
|
box-shadow: none;
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover:not(.selected) {
|
&: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-input,
|
||||||
.react-flow__node-synthesis {
|
.react-flow__node-synthesis {
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
|
|
||||||
|
|
|
@ -205,3 +205,11 @@
|
||||||
--tw-duration: var(--duration-move);
|
--tw-duration: var(--duration-move);
|
||||||
transition-duration: var(--duration-move);
|
transition-duration: var(--duration-move);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@utility cc-graph-interactive {
|
||||||
|
pointer-events: auto;
|
||||||
|
|
||||||
|
.space-mode & {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user