F: Improve OSS UI
This commit is contained in:
parent
976ab669e7
commit
6b36a3fd41
|
@ -107,7 +107,7 @@ export function HelpOssGraph() {
|
||||||
<kbd>Space</kbd> – перемещение экрана
|
<kbd>Space</kbd> – перемещение экрана
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<kbd>Shift</kbd> – перемещение выделенных элементов в границах родителя
|
<kbd>Shift</kbd> – перемещение в границах блока
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -31,10 +31,6 @@ export function NodeCore({ node }: NodeCoreProps) {
|
||||||
const hasFile = !!node.data.operation.result;
|
const hasFile = !!node.data.operation.result;
|
||||||
const longLabel = node.data.label.length > LONG_LABEL_CHARS;
|
const longLabel = node.data.label.length > LONG_LABEL_CHARS;
|
||||||
|
|
||||||
function handleTouchStart(event: React.TouchEvent) {
|
|
||||||
console.log('handleTouchStart', event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
|
@ -42,7 +38,6 @@ export function NodeCore({ node }: NodeCoreProps) {
|
||||||
'relative flex items-center justify-center p-[2px]',
|
'relative flex items-center justify-center p-[2px]',
|
||||||
isChild && 'border-accent-orange'
|
isChild && 'border-accent-orange'
|
||||||
)}
|
)}
|
||||||
onTouchStart={handleTouchStart}
|
|
||||||
>
|
>
|
||||||
<div className='absolute z-pop top-0 right-0 flex flex-col gap-[4px] p-[2px]'>
|
<div className='absolute z-pop top-0 right-0 flex flex-col gap-[4px] p-[2px]'>
|
||||||
<Indicator
|
<Indicator
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useRef, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import { DiagramFlow, useReactFlow, useStoreApi } from '@/components/flow/diagram-flow';
|
import { DiagramFlow, useReactFlow, useStoreApi } from '@/components/flow/diagram-flow';
|
||||||
|
@ -8,7 +8,6 @@ import { useMainHeight } from '@/stores/app-layout';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
import { PARAMETER } from '@/utils/constants';
|
import { PARAMETER } from '@/utils/constants';
|
||||||
import { promptText } from '@/utils/labels';
|
import { promptText } from '@/utils/labels';
|
||||||
import { isIOS } from '@/utils/utils';
|
|
||||||
|
|
||||||
import { useDeleteBlock } from '../../../backend/use-delete-block';
|
import { useDeleteBlock } from '../../../backend/use-delete-block';
|
||||||
import { useMutatingOss } from '../../../backend/use-mutating-oss';
|
import { useMutatingOss } from '../../../backend/use-mutating-oss';
|
||||||
|
@ -68,9 +67,6 @@ export function OssFlow() {
|
||||||
const { isOpen: isContextMenuOpen, menuProps, openContextMenu, hideContextMenu } = useContextMenu();
|
const { isOpen: isContextMenuOpen, menuProps, openContextMenu, hideContextMenu } = useContextMenu();
|
||||||
const { handleDragStart, handleDrag, handleDragStop } = useDragging({ hideContextMenu });
|
const { handleDragStart, handleDrag, handleDragStop } = useDragging({ hideContextMenu });
|
||||||
|
|
||||||
const longPressTimeout = useRef<NodeJS.Timeout | null>(null);
|
|
||||||
const longPressTarget = useRef<EventTarget | null>(null);
|
|
||||||
|
|
||||||
function handleSavePositions() {
|
function handleSavePositions() {
|
||||||
void updateLayout({ itemID: schema.id, data: getLayout() });
|
void updateLayout({ itemID: schema.id, data: getLayout() });
|
||||||
}
|
}
|
||||||
|
@ -193,62 +189,23 @@ export function OssFlow() {
|
||||||
openContextMenu(node, event.clientX, event.clientY);
|
openContextMenu(node, event.clientX, event.clientY);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTouchStart(event: React.TouchEvent) {
|
|
||||||
if (!isIOS() || event.touches.length !== 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Long-press support for iOS/iPadOS
|
|
||||||
const touch = event.touches[0];
|
|
||||||
longPressTarget.current = touch.target;
|
|
||||||
longPressTimeout.current = setTimeout(() => {
|
|
||||||
let targetID = null;
|
|
||||||
let element = touch.target as HTMLElement | null;
|
|
||||||
while (element) {
|
|
||||||
if (element?.getAttribute?.('data-id')) {
|
|
||||||
targetID = element.getAttribute('data-id');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
element = element.parentElement;
|
|
||||||
}
|
|
||||||
if (targetID) {
|
|
||||||
const targetNode = nodes.find(node => node.id === targetID);
|
|
||||||
if (targetNode) {
|
|
||||||
openContextMenu(targetNode, touch.clientX, touch.clientY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, PARAMETER.ossContextMenuDuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleTouchEnd() {
|
|
||||||
if (!isIOS()) return;
|
|
||||||
if (longPressTimeout.current) {
|
|
||||||
clearTimeout(longPressTimeout.current);
|
|
||||||
longPressTimeout.current = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleTouchMove() {
|
|
||||||
if (!isIOS()) return;
|
|
||||||
if (longPressTimeout.current) {
|
|
||||||
clearTimeout(longPressTimeout.current);
|
|
||||||
longPressTimeout.current = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div tabIndex={-1} className='relative' onMouseMove={showCoordinates ? handleMouseMove : undefined}>
|
<div tabIndex={-1} className='relative' 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}
|
||||||
|
|
||||||
|
<ContextMenu isOpen={isContextMenuOpen} onHide={hideContextMenu} {...menuProps} />
|
||||||
|
|
||||||
<ToolbarOssGraph
|
<ToolbarOssGraph
|
||||||
className='absolute z-pop top-8 right-1/2 translate-x-1/2'
|
className='absolute z-pop top-8 right-1/2 translate-x-1/2'
|
||||||
onCreateOperation={handleCreateOperation}
|
onCreateOperation={handleCreateOperation}
|
||||||
onCreateBlock={handleCreateBlock}
|
onCreateBlock={handleCreateBlock}
|
||||||
onDelete={handleDeleteSelected}
|
onDelete={handleDeleteSelected}
|
||||||
onResetPositions={resetGraph}
|
onResetPositions={resetGraph}
|
||||||
|
openContextMenu={openContextMenu}
|
||||||
|
isContextMenuOpen={isContextMenuOpen}
|
||||||
|
hideContextMenu={hideContextMenu}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ContextMenu isOpen={isContextMenuOpen} onHide={hideContextMenu} {...menuProps} />
|
|
||||||
|
|
||||||
<DiagramFlow
|
<DiagramFlow
|
||||||
{...flowOptions}
|
{...flowOptions}
|
||||||
className={clsx(!containMovement && 'cursor-relocate')}
|
className={clsx(!containMovement && 'cursor-relocate')}
|
||||||
|
@ -267,9 +224,6 @@ export function OssFlow() {
|
||||||
onNodeDragStart={handleDragStart}
|
onNodeDragStart={handleDragStart}
|
||||||
onNodeDrag={handleDrag}
|
onNodeDrag={handleDrag}
|
||||||
onNodeDragStop={handleDragStop}
|
onNodeDragStop={handleDragStop}
|
||||||
onTouchStart={handleTouchStart}
|
|
||||||
onTouchEnd={handleTouchEnd}
|
|
||||||
onTouchMove={handleTouchMove}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
import { HelpTopic } from '@/features/help';
|
import { HelpTopic } from '@/features/help';
|
||||||
import { BadgeHelp } from '@/features/help/components';
|
import { BadgeHelp } from '@/features/help/components';
|
||||||
|
import { type OssNode } from '@/features/oss/models/oss-layout';
|
||||||
|
|
||||||
import { MiniButton } from '@/components/control';
|
import { MiniButton } from '@/components/control';
|
||||||
import {
|
import {
|
||||||
IconConceptBlock,
|
IconConceptBlock,
|
||||||
IconDestroy,
|
IconDestroy,
|
||||||
IconEdit2,
|
IconEdit2,
|
||||||
IconExecute,
|
|
||||||
IconFitImage,
|
IconFitImage,
|
||||||
IconNewItem,
|
IconNewItem,
|
||||||
IconReset,
|
IconReset,
|
||||||
|
@ -18,14 +20,11 @@ import {
|
||||||
import { type Styling } from '@/components/props';
|
import { type Styling } from '@/components/props';
|
||||||
import { cn } from '@/components/utils';
|
import { cn } from '@/components/utils';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
import { prepareTooltip } from '@/utils/utils';
|
import { isIOS, prepareTooltip } from '@/utils/utils';
|
||||||
|
|
||||||
import { OperationType } from '../../../backend/types';
|
|
||||||
import { useExecuteOperation } from '../../../backend/use-execute-operation';
|
|
||||||
import { useMutatingOss } from '../../../backend/use-mutating-oss';
|
import { useMutatingOss } from '../../../backend/use-mutating-oss';
|
||||||
import { useUpdateLayout } from '../../../backend/use-update-layout';
|
import { useUpdateLayout } from '../../../backend/use-update-layout';
|
||||||
import { NodeType } from '../../../models/oss';
|
import { NodeType } from '../../../models/oss';
|
||||||
import { LayoutManager } from '../../../models/oss-layout-api';
|
|
||||||
import { useOssEdit } from '../oss-edit-context';
|
import { useOssEdit } from '../oss-edit-context';
|
||||||
|
|
||||||
import { useOssFlow } from './oss-flow-context';
|
import { useOssFlow } from './oss-flow-context';
|
||||||
|
@ -36,6 +35,10 @@ interface ToolbarOssGraphProps extends Styling {
|
||||||
onCreateBlock: () => void;
|
onCreateBlock: () => void;
|
||||||
onDelete: () => void;
|
onDelete: () => void;
|
||||||
onResetPositions: () => void;
|
onResetPositions: () => void;
|
||||||
|
|
||||||
|
isContextMenuOpen: boolean;
|
||||||
|
openContextMenu: (node: OssNode, clientX: number, clientY: number) => void;
|
||||||
|
hideContextMenu: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ToolbarOssGraph({
|
export function ToolbarOssGraph({
|
||||||
|
@ -43,12 +46,16 @@ export function ToolbarOssGraph({
|
||||||
onCreateBlock,
|
onCreateBlock,
|
||||||
onDelete,
|
onDelete,
|
||||||
onResetPositions,
|
onResetPositions,
|
||||||
|
|
||||||
|
isContextMenuOpen,
|
||||||
|
openContextMenu,
|
||||||
|
hideContextMenu,
|
||||||
className,
|
className,
|
||||||
...restProps
|
...restProps
|
||||||
}: ToolbarOssGraphProps) {
|
}: ToolbarOssGraphProps) {
|
||||||
const { schema, selectedItems, isMutable, canDeleteOperation: canDelete } = useOssEdit();
|
const { schema, selectedItems, isMutable, canDeleteOperation: canDelete } = useOssEdit();
|
||||||
const isProcessing = useMutatingOss();
|
const isProcessing = useMutatingOss();
|
||||||
const { resetView } = useOssFlow();
|
const { resetView, nodes } = useOssFlow();
|
||||||
const selectedOperation =
|
const selectedOperation =
|
||||||
selectedItems.length === 1 && selectedItems[0].nodeType === NodeType.OPERATION ? selectedItems[0] : null;
|
selectedItems.length === 1 && selectedItems[0].nodeType === NodeType.OPERATION ? selectedItems[0] : null;
|
||||||
const selectedBlock =
|
const selectedBlock =
|
||||||
|
@ -56,33 +63,9 @@ export function ToolbarOssGraph({
|
||||||
const getLayout = useGetLayout();
|
const getLayout = useGetLayout();
|
||||||
|
|
||||||
const { updateLayout } = useUpdateLayout();
|
const { updateLayout } = useUpdateLayout();
|
||||||
const { executeOperation } = useExecuteOperation();
|
|
||||||
|
|
||||||
const showEditOperation = useDialogsStore(state => state.showEditOperation);
|
|
||||||
const showEditBlock = useDialogsStore(state => state.showEditBlock);
|
|
||||||
const showOssOptions = useDialogsStore(state => state.showOssOptions);
|
const showOssOptions = useDialogsStore(state => state.showOssOptions);
|
||||||
|
|
||||||
const readyForSynthesis = (() => {
|
|
||||||
if (!selectedOperation || selectedOperation.operation_type !== OperationType.SYNTHESIS) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (selectedOperation.result) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const argumentIDs = schema.graph.expandInputs([selectedOperation.id]);
|
|
||||||
if (!argumentIDs || argumentIDs.length < 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const argumentOperations = argumentIDs.map(id => schema.operationByID.get(id)!);
|
|
||||||
if (argumentOperations.some(item => item.result === null)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
})();
|
|
||||||
|
|
||||||
function handleShowOptions() {
|
function handleShowOptions() {
|
||||||
showOssOptions();
|
showOssOptions();
|
||||||
}
|
}
|
||||||
|
@ -91,27 +74,18 @@ export function ToolbarOssGraph({
|
||||||
void updateLayout({ itemID: schema.id, data: getLayout() });
|
void updateLayout({ itemID: schema.id, data: getLayout() });
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleOperationExecute() {
|
function handleEditItem(event: React.MouseEvent<HTMLButtonElement>) {
|
||||||
if (!readyForSynthesis || !selectedOperation) {
|
if (isContextMenuOpen) {
|
||||||
|
hideContextMenu();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void executeOperation({
|
const nodeID = selectedOperation?.nodeID ?? selectedBlock?.nodeID;
|
||||||
itemID: schema.id, //
|
if (!nodeID) {
|
||||||
data: { target: selectedOperation.id, layout: getLayout() }
|
return;
|
||||||
});
|
}
|
||||||
}
|
const node = nodes.find(node => node.id === nodeID);
|
||||||
|
if (node) {
|
||||||
function handleEditItem() {
|
openContextMenu(node, event.clientX, event.clientY);
|
||||||
if (selectedOperation) {
|
|
||||||
showEditOperation({
|
|
||||||
manager: new LayoutManager(schema, getLayout()),
|
|
||||||
target: selectedOperation
|
|
||||||
});
|
|
||||||
} else if (selectedBlock) {
|
|
||||||
showEditBlock({
|
|
||||||
manager: new LayoutManager(schema, getLayout()),
|
|
||||||
target: selectedBlock
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,11 +127,12 @@ export function ToolbarOssGraph({
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
titleHtml={prepareTooltip('Новый блок', 'Ctrl + Shift + Q')}
|
titleHtml={prepareTooltip('Редактировать выбранную', isIOS() ? '' : 'Правый клик')}
|
||||||
aria-label='Новый блок'
|
hideTitle={isContextMenuOpen}
|
||||||
icon={<IconConceptBlock size='1.25rem' className='icon-green' />}
|
aria-label='Редактировать выбранную'
|
||||||
onClick={onCreateBlock}
|
icon={<IconEdit2 size='1.25rem' className='icon-primary' />}
|
||||||
disabled={isProcessing}
|
onClick={handleEditItem}
|
||||||
|
disabled={selectedItems.length !== 1 || isProcessing}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
titleHtml={prepareTooltip('Новая операция', 'Ctrl + Q')}
|
titleHtml={prepareTooltip('Новая операция', 'Ctrl + Q')}
|
||||||
|
@ -167,18 +142,13 @@ export function ToolbarOssGraph({
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Активировать операцию'
|
titleHtml={prepareTooltip('Новый блок', 'Ctrl + Shift + Q')}
|
||||||
icon={<IconExecute size='1.25rem' className='icon-green' />}
|
aria-label='Новый блок'
|
||||||
onClick={handleOperationExecute}
|
icon={<IconConceptBlock size='1.25rem' className='icon-green' />}
|
||||||
disabled={isProcessing || selectedItems.length !== 1 || !readyForSynthesis}
|
onClick={onCreateBlock}
|
||||||
/>
|
disabled={isProcessing}
|
||||||
<MiniButton
|
|
||||||
titleHtml={prepareTooltip('Редактировать выбранную', 'Двойной клик')}
|
|
||||||
aria-label='Редактировать выбранную'
|
|
||||||
icon={<IconEdit2 size='1.25rem' className='icon-primary' />}
|
|
||||||
onClick={handleEditItem}
|
|
||||||
disabled={selectedItems.length !== 1 || isProcessing}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MiniButton
|
<MiniButton
|
||||||
titleHtml={prepareTooltip('Удалить выбранную', 'Delete')}
|
titleHtml={prepareTooltip('Удалить выбранную', 'Delete')}
|
||||||
aria-label='Удалить выбранную'
|
aria-label='Удалить выбранную'
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
import { useAuthSuspense } from '@/features/auth';
|
|
||||||
|
|
||||||
import { MiniButton } from '@/components/control';
|
|
||||||
import { Dropdown, DropdownButton, useDropdown } from '@/components/dropdown';
|
|
||||||
import { IconChild, IconEdit2 } from '@/components/icons';
|
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
|
||||||
|
|
||||||
import { useMutatingOss } from '../../backend/use-mutating-oss';
|
|
||||||
|
|
||||||
import { useOssEdit } from './oss-edit-context';
|
|
||||||
|
|
||||||
export function MenuEditOss() {
|
|
||||||
const { isAnonymous } = useAuthSuspense();
|
|
||||||
const menu = useDropdown();
|
|
||||||
const { schema, isMutable } = useOssEdit();
|
|
||||||
const isProcessing = useMutatingOss();
|
|
||||||
|
|
||||||
const showRelocateConstituents = useDialogsStore(state => state.showRelocateConstituents);
|
|
||||||
|
|
||||||
function handleRelocate() {
|
|
||||||
menu.hide();
|
|
||||||
showRelocateConstituents({
|
|
||||||
oss: schema,
|
|
||||||
initialTarget: undefined
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isAnonymous) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div ref={menu.ref} onBlur={menu.handleBlur} className='relative'>
|
|
||||||
<MiniButton
|
|
||||||
noHover
|
|
||||||
noPadding
|
|
||||||
title='Редактирование'
|
|
||||||
hideTitle={menu.isOpen}
|
|
||||||
className='h-full px-3 text-muted-foreground hover:text-primary cc-animate-color'
|
|
||||||
icon={<IconEdit2 size='1.25rem' />}
|
|
||||||
onClick={menu.toggle}
|
|
||||||
/>
|
|
||||||
<Dropdown isOpen={menu.isOpen} margin='mt-3'>
|
|
||||||
<DropdownButton
|
|
||||||
text='Конституенты'
|
|
||||||
titleHtml='Перенос конституент</br>между схемами'
|
|
||||||
aria-label='Перенос конституент между схемами'
|
|
||||||
icon={<IconChild size='1rem' className='icon-green' />}
|
|
||||||
disabled={isProcessing || !isMutable}
|
|
||||||
onClick={handleRelocate}
|
|
||||||
/>
|
|
||||||
</Dropdown>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -53,7 +53,7 @@ export function MenuMain() {
|
||||||
title='Меню'
|
title='Меню'
|
||||||
hideTitle={menu.isOpen}
|
hideTitle={menu.isOpen}
|
||||||
icon={<IconMenu size='1.25rem' />}
|
icon={<IconMenu size='1.25rem' />}
|
||||||
className='h-full pl-2 text-muted-foreground hover:text-primary cc-animate-color'
|
className='h-full px-2 text-muted-foreground hover:text-primary cc-animate-color'
|
||||||
onClick={menu.toggle}
|
onClick={menu.toggle}
|
||||||
/>
|
/>
|
||||||
<Dropdown isOpen={menu.isOpen} margin='mt-3'>
|
<Dropdown isOpen={menu.isOpen} margin='mt-3'>
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
import { useAuthSuspense } from '@/features/auth';
|
import { useAuthSuspense } from '@/features/auth';
|
||||||
import { MenuRole } from '@/features/library/components';
|
import { MenuRole } from '@/features/library/components';
|
||||||
|
|
||||||
import { MenuEditOss } from './menu-edit-oss';
|
|
||||||
import { MenuMain } from './menu-main';
|
import { MenuMain } from './menu-main';
|
||||||
import { useOssEdit } from './oss-edit-context';
|
import { useOssEdit } from './oss-edit-context';
|
||||||
|
|
||||||
|
@ -14,8 +13,6 @@ export function MenuOssTabs() {
|
||||||
<div className='flex border-r-2'>
|
<div className='flex border-r-2'>
|
||||||
<MenuMain />
|
<MenuMain />
|
||||||
|
|
||||||
<MenuEditOss />
|
|
||||||
|
|
||||||
<MenuRole isOwned={isOwned} isEditor={!!user.id && schema.editors.includes(user.id)} />
|
<MenuRole isOwned={isOwned} isEditor={!!user.id && schema.editors.includes(user.id)} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,7 +11,6 @@ export const PARAMETER = {
|
||||||
notificationDelay: 300, // milliseconds delay for notifications
|
notificationDelay: 300, // milliseconds delay for notifications
|
||||||
zoomDuration: 500, // milliseconds animation duration
|
zoomDuration: 500, // milliseconds animation duration
|
||||||
navigationPopupDelay: 300, // milliseconds delay for navigation popup
|
navigationPopupDelay: 300, // milliseconds delay for navigation popup
|
||||||
ossContextMenuDuration: 500, // milliseconds - duration of long-press to trigger context menu on iOS/iPadOS
|
|
||||||
|
|
||||||
moveDuration: 500, // milliseconds - duration of move animation
|
moveDuration: 500, // milliseconds - duration of move animation
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user