ConceptPortal-public/rsconcept/frontend/src/dialogs/DlgShowAST.tsx

92 lines
3.1 KiB
TypeScript
Raw Normal View History

'use client';
2023-09-04 20:37:55 +03:00
import { useCallback, useMemo, useState } from 'react';
2023-08-01 21:55:18 +03:00
2024-03-20 15:27:32 +03:00
import GraphUI, { GraphEdge, GraphNode } from '@/components/ui/GraphUI';
import Modal, { ModalProps } from '@/components/ui/Modal';
2024-05-17 15:48:54 +03:00
import Overlay from '@/components/ui/Overlay';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
2024-05-17 15:48:54 +03:00
import { HelpTopic } from '@/models/miscellaneous';
import { SyntaxTree } from '@/models/rslang';
import { graphDarkT, graphLightT } from '@/styling/color';
import { colorBgSyntaxTree } from '@/styling/color';
2024-10-29 12:06:43 +03:00
import { resources } from '@/utils/constants';
import { labelSyntaxTree } from '@/utils/labels';
2023-07-29 03:31:21 +03:00
2023-12-28 14:04:44 +03:00
interface DlgShowASTProps extends Pick<ModalProps, 'hideWindow'> {
syntaxTree: SyntaxTree;
expression: string;
2023-07-29 03:31:21 +03:00
}
2023-08-01 21:55:18 +03:00
function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
2024-04-01 19:07:20 +03:00
const { darkMode, colors } = useConceptOptions();
2023-09-04 20:37:55 +03:00
const [hoverID, setHoverID] = useState<number | undefined>(undefined);
2023-12-28 14:04:44 +03:00
const hoverNode = useMemo(() => syntaxTree.find(node => node.uid === hoverID), [hoverID, syntaxTree]);
2023-08-01 21:55:18 +03:00
const nodes: GraphNode[] = useMemo(
2023-12-28 14:04:44 +03:00
() =>
syntaxTree.map(node => ({
2024-09-26 22:40:11 +03:00
id: String(syntaxTree.length - node.uid), // invert order of IDs to force correct ordering in graph layout
2023-12-28 14:04:44 +03:00
label: labelSyntaxTree(node),
fill: colorBgSyntaxTree(node, colors)
})),
[syntaxTree, colors]
);
2023-08-01 21:55:18 +03:00
2023-12-28 14:04:44 +03:00
const edges: GraphEdge[] = useMemo(() => {
2023-08-01 21:55:18 +03:00
const result: GraphEdge[] = [];
syntaxTree.forEach(node => {
if (node.parent !== node.uid) {
2023-08-01 21:55:18 +03:00
result.push({
id: String(node.uid),
2024-09-26 22:40:11 +03:00
source: String(syntaxTree.length - node.parent),
target: String(syntaxTree.length - node.uid)
2023-08-01 21:55:18 +03:00
});
}
});
return result;
}, [syntaxTree]);
2023-07-29 03:31:21 +03:00
2024-09-26 22:40:11 +03:00
const handleHoverIn = useCallback((node: GraphNode) => setHoverID(syntaxTree.length - Number(node.id)), [syntaxTree]);
2023-09-04 20:37:55 +03:00
2023-12-28 14:04:44 +03:00
const handleHoverOut = useCallback(() => setHoverID(undefined), []);
2023-09-04 20:37:55 +03:00
2023-07-29 03:31:21 +03:00
return (
2024-09-18 15:53:55 +03:00
<Modal
readonly
hideWindow={hideWindow}
className='flex flex-col justify-stretch w-[calc(100dvw-3rem)] h-[calc(100dvh-6rem)]'
2024-10-29 12:06:43 +03:00
helpTopic={HelpTopic.UI_FORMULA_TREE}
2024-09-18 15:53:55 +03:00
>
<Overlay
position='top-2 right-1/2 translate-x-1/2'
className='px-2 py-1 rounded-2xl cc-blur max-w-[60ch] text-lg text-center'
style={{ backgroundColor: colors.bgBlur }}
>
2023-12-28 14:04:44 +03:00
{!hoverNode ? expression : null}
{hoverNode ? (
<div>
<span>{expression.slice(0, hoverNode.start)}</span>
<span className='clr-selected'>{expression.slice(hoverNode.start, hoverNode.finish)}</span>
<span>{expression.slice(hoverNode.finish)}</span>
</div>
) : null}
2024-09-18 15:53:55 +03:00
</Overlay>
<div className='flex-grow relative'>
2023-12-28 14:04:44 +03:00
<GraphUI
2024-04-03 15:51:57 +03:00
animated={false}
2023-12-28 14:04:44 +03:00
nodes={nodes}
edges={edges}
layoutType='hierarchicalTd'
labelFontUrl={resources.graph_font}
theme={darkMode ? graphDarkT : graphLightT}
onNodePointerOver={handleHoverIn}
onNodePointerOut={handleHoverOut}
/>
</div>
</Modal>
);
2023-07-29 03:31:21 +03:00
}
2023-12-28 14:04:44 +03:00
export default DlgShowAST;