F: Simplify termgraph tooltip

This commit is contained in:
Ivan 2025-02-25 13:19:35 +03:00
parent 0d899f6258
commit 4352ba93b6
3 changed files with 28 additions and 26 deletions

View File

@ -15,7 +15,6 @@ import {
import { Overlay } from '@/components/Container'; import { Overlay } from '@/components/Container';
import { useMainHeight } from '@/stores/appLayout'; import { useMainHeight } from '@/stores/appLayout';
import { useTooltipsStore } from '@/stores/tooltips';
import { APP_COLORS } from '@/styling/colors'; import { APP_COLORS } from '@/styling/colors';
import { PARAMETER } from '@/utils/constants'; import { PARAMETER } from '@/utils/constants';
@ -43,7 +42,7 @@ export const ZOOM_MIN = 0.25;
export function TGFlow() { export function TGFlow() {
const mainHeight = useMainHeight(); const mainHeight = useMainHeight();
const flow = useReactFlow(); const { fitView, viewportInitialized } = useReactFlow();
const store = useStoreApi(); const store = useStoreApi();
const { addSelectedNodes } = store.getState(); const { addSelectedNodes } = store.getState();
const isProcessing = useMutatingRSForm(); const isProcessing = useMutatingRSForm();
@ -62,8 +61,6 @@ export function TGFlow() {
const coloring = useTermGraphStore(state => state.coloring); const coloring = useTermGraphStore(state => state.coloring);
const setColoring = useTermGraphStore(state => state.setColoring); const setColoring = useTermGraphStore(state => state.setColoring);
const setActiveCst = useTooltipsStore(state => state.setActiveCst);
const [nodes, setNodes, onNodesChange] = useNodesState([]); const [nodes, setNodes, onNodesChange] = useNodesState([]);
const [edges, setEdges] = useEdgesState([]); const [edges, setEdges] = useEdgesState([]);
@ -108,8 +105,7 @@ export function TGFlow() {
position: { x: 0, y: 0 }, position: { x: 0, y: 0 },
data: { data: {
fill: focusCst === cst ? APP_COLORS.bgPurple : colorBgGraphNode(cst, coloring), fill: focusCst === cst ? APP_COLORS.bgPurple : colorBgGraphNode(cst, coloring),
label: cst.alias, cst: cst
description: !filter.noText ? cst.term_resolved : ''
} }
}); });
} }
@ -148,12 +144,12 @@ export function TGFlow() {
}, [schema, focusCst, coloring, filter]); }, [schema, focusCst, coloring, filter]);
useEffect(() => { useEffect(() => {
if (!needReset || !flow.viewportInitialized) { if (!needReset || !viewportInitialized) {
return; return;
} }
setNeedReset(false); setNeedReset(false);
resetNodes(); resetNodes();
}, [needReset, schema, resetNodes, flow.viewportInitialized]); }, [needReset, schema, resetNodes, viewportInitialized]);
function handleSetSelected(newSelection: number[]) { function handleSetSelected(newSelection: number[]) {
setSelected(newSelection); setSelected(newSelection);
@ -193,7 +189,7 @@ export function TGFlow() {
} }
setSelected([]); setSelected([]);
setTimeout(() => { setTimeout(() => {
flow.fitView({ duration: PARAMETER.zoomDuration }); fitView({ duration: PARAMETER.zoomDuration });
}, PARAMETER.minimalTimeout); }, PARAMETER.minimalTimeout);
} }
@ -209,13 +205,6 @@ export function TGFlow() {
navigateCst(cstID); navigateCst(cstID);
} }
function handleNodeEnter(cstID: number) {
const cst = schema.cstByID.get(cstID);
if (cst) {
setActiveCst(cst);
}
}
return ( return (
<> <>
<Overlay position='cc-tab-tools' className='flex flex-col items-center rounded-b-2xl cc-blur'> <Overlay position='cc-tab-tools' className='flex flex-col items-center rounded-b-2xl cc-blur'>
@ -269,7 +258,6 @@ export function TGFlow() {
edgeTypes={TGEdgeTypes} edgeTypes={TGEdgeTypes}
maxZoom={ZOOM_MAX} maxZoom={ZOOM_MAX}
minZoom={ZOOM_MIN} minZoom={ZOOM_MIN}
onNodeMouseEnter={(_, node) => handleNodeEnter(Number(node.id))}
onNodeDoubleClick={(event, node) => handleNodeDoubleClick(event, Number(node.id))} onNodeDoubleClick={(event, node) => handleNodeDoubleClick(event, Number(node.id))}
onNodeContextMenu={(event, node) => handleNodeContextMenu(event, Number(node.id))} onNodeContextMenu={(event, node) => handleNodeContextMenu(event, Number(node.id))}
/> />

View File

@ -2,6 +2,9 @@
import { Handle, Position } from 'reactflow'; import { Handle, Position } from 'reactflow';
import { type IConstituenta } from '@/features/rsform/models/rsform';
import { useTermGraphStore } from '@/features/rsform/stores/termGraph';
import { APP_COLORS } from '@/styling/colors'; import { APP_COLORS } from '@/styling/colors';
import { globalIDs } from '@/utils/constants'; import { globalIDs } from '@/utils/constants';
@ -14,8 +17,7 @@ const FONT_SIZE_MIN = 10;
export interface TGNodeData { export interface TGNodeData {
fill: string; fill: string;
label: string; cst: IConstituenta;
description: string;
} }
/** /**
@ -31,6 +33,10 @@ interface TGNodeInternal {
} }
export function TGNode(node: TGNodeInternal) { export function TGNode(node: TGNodeInternal) {
const filter = useTermGraphStore(state => state.filter);
const label = node.data.cst.alias;
const description = !filter.noText ? node.data.cst.term_resolved : '';
return ( return (
<> <>
<Handle type='target' position={Position.Top} style={{ opacity: 0 }} /> <Handle type='target' position={Position.Top} style={{ opacity: 0 }} />
@ -38,9 +44,10 @@ export function TGNode(node: TGNodeInternal) {
className='w-full h-full cursor-default flex items-center justify-center rounded-full' className='w-full h-full cursor-default flex items-center justify-center rounded-full'
style={{ style={{
backgroundColor: !node.selected ? node.data.fill : APP_COLORS.bgActiveSelection, backgroundColor: !node.selected ? node.data.fill : APP_COLORS.bgActiveSelection,
fontSize: node.data.label.length > LABEL_THRESHOLD ? FONT_SIZE_MED : FONT_SIZE_MAX fontSize: label.length > LABEL_THRESHOLD ? FONT_SIZE_MED : FONT_SIZE_MAX
}} }}
data-tooltip-id={globalIDs.constituenta_tooltip} data-tooltip-id={globalIDs.tooltip}
data-tooltip-html={describeCstNode(node.data.cst)}
> >
<div <div
style={{ style={{
@ -49,19 +56,19 @@ export function TGNode(node: TGNodeInternal) {
WebkitTextStrokeColor: APP_COLORS.bgDefault WebkitTextStrokeColor: APP_COLORS.bgDefault
}} }}
> >
{node.data.label} {label}
</div> </div>
</div> </div>
<Handle type='source' position={Position.Bottom} style={{ opacity: 0 }} /> <Handle type='source' position={Position.Bottom} style={{ opacity: 0 }} />
{node.data.description ? ( {description ? (
<div <div
className='mt-1 w-[150px] px-1 text-center translate-x-[calc(-50%+20px)]' className='mt-1 w-[150px] px-1 text-center translate-x-[calc(-50%+20px)]'
style={{ style={{
fontSize: node.data.description.length > DESCRIPTION_THRESHOLD ? FONT_SIZE_MIN : FONT_SIZE_MED fontSize: description.length > DESCRIPTION_THRESHOLD ? FONT_SIZE_MIN : FONT_SIZE_MED
}} }}
> >
<div className='absolute top-0 px-1 left-0 text-center w-full line-clamp-3 hover:line-clamp-none'> <div className='absolute top-0 px-1 left-0 text-center w-full line-clamp-3 hover:line-clamp-none'>
{node.data.description} {description}
</div> </div>
<div <div
aria-hidden='true' aria-hidden='true'
@ -71,10 +78,15 @@ export function TGNode(node: TGNodeInternal) {
WebkitTextStrokeColor: APP_COLORS.bgDefault WebkitTextStrokeColor: APP_COLORS.bgDefault
}} }}
> >
{node.data.description} {description}
</div> </div>
</div> </div>
) : null} ) : null}
</> </>
); );
} }
// ====== INTERNAL ======
function describeCstNode(cst: IConstituenta) {
return `${cst.alias}: ${cst.term_resolved}</br>Типизация: ${cst.parse.typification}`;
}

View File

@ -5,6 +5,8 @@
/** Semantic colors for application. */ /** Semantic colors for application. */
// prettier-ignore // prettier-ignore
export const APP_COLORS = { export const APP_COLORS = {
bgDefaultLight: '#fafafa',
bgDefaultDark: '#171717',
bgDefault: 'var(--clr-prim-100)', bgDefault: 'var(--clr-prim-100)',
bgInput: 'var(--clr-prim-0)', bgInput: 'var(--clr-prim-0)',
bgControls: 'var(--clr-prim-200)', bgControls: 'var(--clr-prim-200)',