mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Refactoring constants + small UI fixes
This commit is contained in:
parent
16252b2145
commit
a10bda8af3
|
@ -4,6 +4,7 @@ import { motion } from 'framer-motion';
|
|||
import { IconPin, IconUnpin } from '@/components/Icons';
|
||||
import { useConceptOptions } from '@/context/OptionsContext';
|
||||
import { animateNavigationToggle } from '@/styling/animations';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
function ToggleNavigationButton() {
|
||||
const { noNavigationAnimation, toggleNoNavigation } = useConceptOptions();
|
||||
|
@ -11,7 +12,6 @@ function ToggleNavigationButton() {
|
|||
<motion.button
|
||||
type='button'
|
||||
tabIndex={-1}
|
||||
title={noNavigationAnimation ? 'Показать навигацию' : 'Скрыть навигацию'}
|
||||
className={clsx(
|
||||
'absolute top-0 right-0 z-navigation flex items-center justify-center',
|
||||
'clr-btn-nav',
|
||||
|
@ -21,6 +21,8 @@ function ToggleNavigationButton() {
|
|||
initial={false}
|
||||
animate={noNavigationAnimation ? 'off' : 'on'}
|
||||
variants={animateNavigationToggle}
|
||||
data-tooltip-id={globals.tooltip}
|
||||
data-tooltip-content={noNavigationAnimation ? 'Показать навигацию' : 'Скрыть навигацию'}
|
||||
>
|
||||
{!noNavigationAnimation ? <IconPin /> : null}
|
||||
{noNavigationAnimation ? <IconUnpin /> : null}
|
||||
|
|
|
@ -22,7 +22,8 @@ export { LuGlasses as IconReader } from 'react-icons/lu';
|
|||
export { FiBell as IconFollow } from 'react-icons/fi';
|
||||
export { FiBellOff as IconFollowOff } from 'react-icons/fi';
|
||||
|
||||
export { BiListUl as IconList } from 'react-icons/bi';
|
||||
export { TbColumns as IconList } from 'react-icons/tb';
|
||||
export { TbColumnsOff as IconListOff } from 'react-icons/tb';
|
||||
export { BiFontFamily as IconText } from 'react-icons/bi';
|
||||
export { BiFont as IconTextOff } from 'react-icons/bi';
|
||||
export { RiTreeLine as IconTree } from 'react-icons/ri';
|
||||
|
|
|
@ -4,8 +4,6 @@ import EmbedYoutube from '@/components/ui/EmbedYoutube';
|
|||
import useWindowSize from '@/hooks/useWindowSize';
|
||||
import { external_urls, youtube } from '@/utils/constants';
|
||||
|
||||
const OPT_VIDEO_H = 1080;
|
||||
|
||||
function HelpRSLang() {
|
||||
const windowSize = useWindowSize();
|
||||
|
||||
|
@ -13,7 +11,7 @@ function HelpRSLang() {
|
|||
const viewH = windowSize.height ?? 0;
|
||||
const viewW = windowSize.width ?? 0;
|
||||
const availableWidth = viewW - (windowSize.isSmall ? 35 : 290);
|
||||
return Math.min(OPT_VIDEO_H, viewH - 320, Math.floor((availableWidth * 9) / 16));
|
||||
return Math.min(1080, viewH - 320, Math.floor((availableWidth * 9) / 16));
|
||||
}, [windowSize]);
|
||||
|
||||
// prettier-ignore
|
||||
|
|
|
@ -8,8 +8,7 @@ import { getDefinitionPrefix } from '@/models/rsformAPI';
|
|||
import { IArgumentInfo, IExpressionParse } from '@/models/rslang';
|
||||
import { RSErrorType } from '@/models/rslang';
|
||||
import { DataCallback, postCheckExpression } from '@/utils/backendAPI';
|
||||
|
||||
const LOGIC_TYPIFICATION = 'LOGIC';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
|
||||
function useCheckExpression({ schema }: { schema?: IRSForm }) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
@ -47,17 +46,17 @@ function checkTypeConsistency(type: CstType, typification: string, args: IArgume
|
|||
case CstType.CONSTANT:
|
||||
case CstType.STRUCTURED:
|
||||
case CstType.TERM:
|
||||
return typification !== LOGIC_TYPIFICATION && args.length === 0;
|
||||
return typification !== PARAMETER.logicLabel && args.length === 0;
|
||||
|
||||
case CstType.AXIOM:
|
||||
case CstType.THEOREM:
|
||||
return typification === LOGIC_TYPIFICATION && args.length === 0;
|
||||
return typification === PARAMETER.logicLabel && args.length === 0;
|
||||
|
||||
case CstType.FUNCTION:
|
||||
return typification !== LOGIC_TYPIFICATION && args.length !== 0;
|
||||
return typification !== PARAMETER.logicLabel && args.length !== 0;
|
||||
|
||||
case CstType.PREDICATE:
|
||||
return typification === LOGIC_TYPIFICATION && args.length !== 0;
|
||||
return typification === PARAMETER.logicLabel && args.length !== 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,10 @@
|
|||
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
const KEY_NAME_ESC = 'Escape';
|
||||
const KEY_EVENT_TYPE = 'keyup';
|
||||
|
||||
function useEscapeKey(handleClose: () => void) {
|
||||
const handleEscKey = useCallback(
|
||||
(event: KeyboardEvent) => {
|
||||
if (event.key === KEY_NAME_ESC) {
|
||||
if (event.key === 'Escape') {
|
||||
handleClose();
|
||||
}
|
||||
},
|
||||
|
@ -16,9 +13,9 @@ function useEscapeKey(handleClose: () => void) {
|
|||
);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener(KEY_EVENT_TYPE, handleEscKey, false);
|
||||
document.addEventListener('keyup', handleEscKey, false);
|
||||
return () => {
|
||||
document.removeEventListener(KEY_EVENT_TYPE, handleEscKey, false);
|
||||
document.removeEventListener('keyup', handleEscKey, false);
|
||||
};
|
||||
}, [handleEscKey]);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { SMALL_SCREEN_WIDTH } from '@/utils/constants';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
|
||||
function useWindowSize() {
|
||||
const isClient = typeof window === 'object';
|
||||
|
@ -11,7 +11,7 @@ function useWindowSize() {
|
|||
return {
|
||||
width: isClient ? window.innerWidth : undefined,
|
||||
height: isClient ? window.innerHeight : undefined,
|
||||
isSmall: isClient && window.innerWidth < SMALL_SCREEN_WIDTH
|
||||
isSmall: isClient && window.innerWidth < PARAMETER.smallScreen
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -32,9 +32,7 @@ export function loadRSFormData(input: IRSFormData): IRSForm {
|
|||
result.graph = new Graph();
|
||||
result.stats = calculateStats(result.items);
|
||||
|
||||
const derivationLookup: Map<ConstituentaID, ConstituentaID> = new Map();
|
||||
result.items.forEach(cst => {
|
||||
derivationLookup.set(cst.id, cst.id);
|
||||
cst.derived_from = cst.id;
|
||||
cst.derived_children = [];
|
||||
cst.derived_children_alias = [];
|
||||
|
@ -51,7 +49,9 @@ export function loadRSFormData(input: IRSFormData): IRSForm {
|
|||
});
|
||||
});
|
||||
// Calculate derivation of constituents based on formal definition analysis
|
||||
const derivationLookup: Map<ConstituentaID, ConstituentaID> = new Map();
|
||||
result.graph.topologicalOrder().forEach(id => {
|
||||
derivationLookup.set(id, id);
|
||||
const cst = result.items.find(item => item.id === id)!;
|
||||
if (cst.cst_type === CstType.STRUCTURED) {
|
||||
return;
|
||||
|
|
|
@ -3,7 +3,7 @@ import { useLayoutEffect } from 'react';
|
|||
import { urls } from '@/app/urls';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||
import { TIMEOUT_UI_REFRESH } from '@/utils/constants';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
|
||||
function HomePage() {
|
||||
const router = useConceptNavigation();
|
||||
|
@ -13,11 +13,11 @@ function HomePage() {
|
|||
if (!user) {
|
||||
setTimeout(() => {
|
||||
router.push(urls.manuals);
|
||||
}, TIMEOUT_UI_REFRESH);
|
||||
}, PARAMETER.refreshTimeout);
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
router.push(urls.library);
|
||||
}, TIMEOUT_UI_REFRESH);
|
||||
}, PARAMETER.refreshTimeout);
|
||||
}
|
||||
}, [router, user]);
|
||||
|
||||
|
|
|
@ -14,9 +14,6 @@ import ViewConstituents from '../ViewConstituents';
|
|||
import ConstituentaToolbar from './ConstituentaToolbar';
|
||||
import FormConstituenta from './FormConstituenta';
|
||||
|
||||
// Max height of content for left editor pane.
|
||||
const UNFOLDED_HEIGHT = '59.1rem';
|
||||
|
||||
// Threshold window width to switch layout.
|
||||
const SIDELIST_LAYOUT_THRESHOLD = 1100; // px
|
||||
|
||||
|
@ -119,7 +116,6 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
|
|||
schema={controller.schema}
|
||||
expression={activeCst?.definition_formal ?? ''}
|
||||
isBottom={isNarrow}
|
||||
baseHeight={UNFOLDED_HEIGHT}
|
||||
activeID={activeCst?.id}
|
||||
onOpenEdit={onOpenEdit}
|
||||
/>
|
||||
|
|
|
@ -6,7 +6,7 @@ import { useCallback, useLayoutEffect, useRef, useState } from 'react';
|
|||
import { FaRegKeyboard } from 'react-icons/fa6';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import { IconList, IconText, IconTree } from '@/components/Icons';
|
||||
import { IconList, IconListOff, IconText, IconTextOff, IconTree } from '@/components/Icons';
|
||||
import BadgeHelp from '@/components/man/BadgeHelp';
|
||||
import RSInput from '@/components/RSInput';
|
||||
import { RSTextWrapper } from '@/components/RSInput/textEditing';
|
||||
|
@ -164,19 +164,21 @@ function EditorRSExpression({
|
|||
<MiniButton
|
||||
title='Изменить шрифт'
|
||||
onClick={toggleFont}
|
||||
icon={<IconText size='1.25rem' className={mathFont === 'math' ? 'icon-primary' : ''} />}
|
||||
icon={
|
||||
mathFont === 'math' ? <IconText size='1.25rem' className='icon-primary' /> : <IconTextOff size='1.25rem' />
|
||||
}
|
||||
/>
|
||||
{!disabled || model.processing ? (
|
||||
<MiniButton
|
||||
title='Отображение специальной клавиатуры'
|
||||
onClick={() => setShowControls(prev => !prev)}
|
||||
icon={<FaRegKeyboard size='1.25rem' className={showControls ? 'icon-primary' : ''} />}
|
||||
onClick={() => setShowControls(prev => !prev)}
|
||||
/>
|
||||
) : null}
|
||||
<MiniButton
|
||||
title='Отображение списка конституент'
|
||||
icon={showList ? <IconList size='1.25rem' className='icon-primary' /> : <IconListOff size='1.25rem' />}
|
||||
onClick={onToggleList}
|
||||
icon={<IconList size='1.25rem' className={showList ? 'icon-primary' : ''} />}
|
||||
/>
|
||||
<MiniButton
|
||||
title='Дерево разбора выражения'
|
||||
|
|
|
@ -14,7 +14,7 @@ import useLocalStorage from '@/hooks/useLocalStorage';
|
|||
import { GraphColoringScheme, GraphFilterParams } from '@/models/miscellaneous';
|
||||
import { ConstituentaID, CstType } from '@/models/rsform';
|
||||
import { colorBgGraphNode } from '@/styling/color';
|
||||
import { storage, TIMEOUT_GRAPH_REFRESH } from '@/utils/constants';
|
||||
import { PARAMETER, storage } from '@/utils/constants';
|
||||
|
||||
import { useRSEdit } from '../RSEditContext';
|
||||
import GraphSelectors from './GraphSelectors';
|
||||
|
@ -141,7 +141,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
|
|||
setLayout(newLayout);
|
||||
setTimeout(() => {
|
||||
setToggleResetView(prev => !prev);
|
||||
}, TIMEOUT_GRAPH_REFRESH);
|
||||
}, PARAMETER.graphRefreshDelay);
|
||||
}
|
||||
|
||||
const handleChangeParams = useCallback(
|
||||
|
@ -173,7 +173,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
|
|||
}));
|
||||
setTimeout(() => {
|
||||
setToggleResetView(prev => !prev);
|
||||
}, TIMEOUT_GRAPH_REFRESH);
|
||||
}, PARAMETER.graphRefreshDelay);
|
||||
}, [setFilterParams, setToggleResetView]);
|
||||
|
||||
const graph = useMemo(
|
||||
|
|
|
@ -6,7 +6,7 @@ import GraphUI, { GraphCanvasRef, GraphEdge, GraphNode, LayoutTypes, useSelectio
|
|||
import { useConceptOptions } from '@/context/OptionsContext';
|
||||
import { ConstituentaID } from '@/models/rsform';
|
||||
import { graphDarkT, graphLightT } from '@/styling/color';
|
||||
import { resources } from '@/utils/constants';
|
||||
import { PARAMETER, resources } from '@/utils/constants';
|
||||
|
||||
interface TermGraphProps {
|
||||
nodes: GraphNode[];
|
||||
|
@ -25,8 +25,6 @@ interface TermGraphProps {
|
|||
toggleResetView: boolean;
|
||||
}
|
||||
|
||||
const TREE_SIZE_MILESTONE = 50;
|
||||
|
||||
function TermGraph({
|
||||
nodes,
|
||||
edges,
|
||||
|
@ -114,7 +112,7 @@ function TermGraph({
|
|||
maxNodeSize={8}
|
||||
cameraMode={orbit ? 'orbit' : is3D ? 'rotate' : 'pan'}
|
||||
layoutOverrides={
|
||||
layout.includes('tree') ? { nodeLevelRatio: nodes.length < TREE_SIZE_MILESTONE ? 3 : 1 } : undefined
|
||||
layout.includes('tree') ? { nodeLevelRatio: nodes.length < PARAMETER.smallTreeNodes ? 3 : 1 } : undefined
|
||||
}
|
||||
labelFontUrl={resources.graph_font}
|
||||
theme={darkMode ? graphDarkT : graphLightT}
|
||||
|
|
|
@ -14,7 +14,7 @@ import { useConceptOptions } from '@/context/OptionsContext';
|
|||
import { useRSForm } from '@/context/RSFormContext';
|
||||
import useQueryStrings from '@/hooks/useQueryStrings';
|
||||
import { ConstituentaID, IConstituenta, IConstituentaMeta } from '@/models/rsform';
|
||||
import { prefixes, TIMEOUT_UI_REFRESH } from '@/utils/constants';
|
||||
import { PARAMETER, prefixes } from '@/utils/constants';
|
||||
import { labelVersion } from '@/utils/labels';
|
||||
|
||||
import EditorConstituenta from './EditorConstituenta';
|
||||
|
@ -124,7 +124,7 @@ function RSTabs() {
|
|||
inline: 'nearest'
|
||||
});
|
||||
}
|
||||
}, TIMEOUT_UI_REFRESH);
|
||||
}, PARAMETER.refreshTimeout);
|
||||
}
|
||||
},
|
||||
[activeTab, navigateTab]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import clsx from 'clsx';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useConceptOptions } from '@/context/OptionsContext';
|
||||
import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform';
|
||||
|
@ -11,33 +11,22 @@ import { animateSideView } from '@/styling/animations';
|
|||
import ConstituentsSearch from './ConstituentsSearch';
|
||||
import ConstituentsTable from './ConstituentsTable';
|
||||
|
||||
// Height that should be left to accommodate navigation panel + bottom margin
|
||||
const LOCAL_NAVIGATION_H = '2.1rem';
|
||||
|
||||
// Window width cutoff for expression show
|
||||
const COLUMN_EXPRESSION_HIDE_THRESHOLD = 1500;
|
||||
|
||||
interface ViewConstituentsProps {
|
||||
expression: string;
|
||||
isBottom?: boolean;
|
||||
baseHeight: string;
|
||||
activeID?: ConstituentaID;
|
||||
schema?: IRSForm;
|
||||
onOpenEdit: (cstID: ConstituentaID) => void;
|
||||
}
|
||||
|
||||
function ViewConstituents({ expression, schema, activeID, isBottom, baseHeight, onOpenEdit }: ViewConstituentsProps) {
|
||||
const { noNavigation } = useConceptOptions();
|
||||
function ViewConstituents({ expression, schema, activeID, isBottom, onOpenEdit }: ViewConstituentsProps) {
|
||||
const { calculateHeight } = useConceptOptions();
|
||||
|
||||
const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []);
|
||||
|
||||
const maxHeight = useMemo(() => {
|
||||
const siblingHeight = `${baseHeight} - ${LOCAL_NAVIGATION_H}`;
|
||||
return noNavigation
|
||||
? `calc(min(100vh - 8.2rem, ${siblingHeight}))`
|
||||
: `calc(min(100vh - 11.7rem, ${siblingHeight}))`;
|
||||
}, [noNavigation, baseHeight]);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className={clsx(
|
||||
|
@ -58,7 +47,7 @@ function ViewConstituents({ expression, schema, activeID, isBottom, baseHeight,
|
|||
setFiltered={setFilteredData}
|
||||
/>
|
||||
<ConstituentsTable
|
||||
maxHeight={isBottom ? '12rem' : maxHeight}
|
||||
maxHeight={isBottom ? '12rem' : calculateHeight('8.2rem')}
|
||||
items={filteredData}
|
||||
activeID={activeID}
|
||||
onOpenEdit={onOpenEdit}
|
||||
|
|
|
@ -10,24 +10,16 @@ export const buildConstants = {
|
|||
};
|
||||
|
||||
/**
|
||||
* General UI timeout [in ms] for waiting for render.
|
||||
* Global application Parameters. The place where magic numbers are put to rest.
|
||||
*/
|
||||
export const TIMEOUT_UI_REFRESH = 100;
|
||||
export const PARAMETER = {
|
||||
smallScreen: 640, // == tailwind:xs
|
||||
smallTreeNodes: 50, // amount of nodes threshold for size increase for large graphs
|
||||
refreshTimeout: 100, // milliseconds delay for post-refresh actions
|
||||
graphRefreshDelay: 10, // milliseconds delay for graph viewpoint reset
|
||||
|
||||
/**
|
||||
* Threshold for small screen size optimizations.
|
||||
*/
|
||||
export const SMALL_SCREEN_WIDTH = 640; // == tailwind:xs
|
||||
|
||||
/**
|
||||
* Timeout [in ms] for graph refresh.
|
||||
*/
|
||||
export const TIMEOUT_GRAPH_REFRESH = 200;
|
||||
|
||||
/**
|
||||
* Exteor file extension for RSForm.
|
||||
*/
|
||||
export const EXTEOR_TRS_FILE = '.trs';
|
||||
logicLabel: 'LOGIC'
|
||||
};
|
||||
|
||||
/**
|
||||
* Numeric limitations.
|
||||
|
@ -36,6 +28,11 @@ export const limits = {
|
|||
library_alias_len: 12
|
||||
};
|
||||
|
||||
/**
|
||||
* Exteor file extension for RSForm.
|
||||
*/
|
||||
export const EXTEOR_TRS_FILE = '.trs';
|
||||
|
||||
/**
|
||||
* Regex patterns for data validation.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue
Block a user