M: Refactor tooltips loading

This commit is contained in:
Ivan 2025-02-26 20:34:58 +03:00
parent efbeb2a343
commit a470a6c475
13 changed files with 84 additions and 63 deletions

View File

@ -1,24 +1,9 @@
'use client'; 'use client';
import React, { Suspense } from 'react';
import { Tooltip } from '@/components/Container'; import { Tooltip } from '@/components/Container';
import { Loader } from '@/components/Loader';
import { useTooltipsStore } from '@/stores/tooltips';
import { globalIDs } from '@/utils/constants'; import { globalIDs } from '@/utils/constants';
const InfoConstituenta = React.lazy(() =>
import('@/features/rsform/components/InfoConstituenta').then(module => ({ default: module.InfoConstituenta }))
);
const InfoOperation = React.lazy(() =>
import('@/features/oss/components/InfoOperation').then(module => ({ default: module.InfoOperation }))
);
export const GlobalTooltips = () => { export const GlobalTooltips = () => {
const hoverCst = useTooltipsStore(state => state.activeCst);
const hoverOperation = useTooltipsStore(state => state.activeOperation);
return ( return (
<> <>
<Tooltip <Tooltip
@ -34,27 +19,6 @@ export const GlobalTooltips = () => {
layer='z-topmost' layer='z-topmost'
className='max-w-[calc(min(40rem,100dvw-2rem))] text-justify' className='max-w-[calc(min(40rem,100dvw-2rem))] text-justify'
/> />
<Tooltip
clickable
id={globalIDs.constituenta_tooltip}
layer='z-topmost'
className='max-w-[30rem]'
hidden={!hoverCst}
>
<Suspense fallback={<Loader />}>
{hoverCst ? <InfoConstituenta data={hoverCst} onClick={event => event.stopPropagation()} /> : null}
</Suspense>
</Tooltip>
<Tooltip
id={globalIDs.operation_tooltip}
layer='z-topmost'
className='max-w-[35rem] max-h-[40rem] dense'
hidden={!hoverOperation}
>
<Suspense fallback={<Loader />}>
{hoverOperation ? <InfoOperation operation={hoverOperation} /> : null}
</Suspense>
</Tooltip>
</> </>
); );
}; };

View File

@ -0,0 +1,20 @@
import { Tooltip } from '@/components/Container';
import { globalIDs } from '@/utils/constants';
import { useOperationTooltipStore } from '../stores/operationTooltip';
import { InfoOperation } from './InfoOperation';
export function OperationTooltip() {
const hoverOperation = useOperationTooltipStore(state => state.activeOperation);
return (
<Tooltip
id={globalIDs.operation_tooltip}
layer='z-topmost'
className='max-w-[35rem] max-h-[40rem] dense'
hidden={!hoverOperation}
>
{hoverOperation ? <InfoOperation operation={hoverOperation} /> : null}
</Tooltip>
);
}

View File

@ -14,13 +14,13 @@ import {
import { Overlay } from '@/components/Container'; import { Overlay } from '@/components/Container';
import { useMainHeight } from '@/stores/appLayout'; import { useMainHeight } from '@/stores/appLayout';
import { useDialogsStore } from '@/stores/dialogs'; import { useDialogsStore } from '@/stores/dialogs';
import { useTooltipsStore } from '@/stores/tooltips';
import { PARAMETER } from '@/utils/constants'; import { PARAMETER } from '@/utils/constants';
import { useMutatingOss } from '../../../backend/useMutatingOss'; import { useMutatingOss } from '../../../backend/useMutatingOss';
import { useUpdatePositions } from '../../../backend/useUpdatePositions'; import { useUpdatePositions } from '../../../backend/useUpdatePositions';
import { GRID_SIZE } from '../../../models/ossAPI'; import { GRID_SIZE } from '../../../models/ossAPI';
import { type OssNode } from '../../../models/ossLayout'; import { type OssNode } from '../../../models/ossLayout';
import { useOperationTooltipStore } from '../../../stores/operationTooltip';
import { useOSSGraphStore } from '../../../stores/ossGraph'; import { useOSSGraphStore } from '../../../stores/ossGraph';
import { useOssEdit } from '../OssEditContext'; import { useOssEdit } from '../OssEditContext';
@ -47,7 +47,7 @@ export function OssFlow() {
const isProcessing = useMutatingOss(); const isProcessing = useMutatingOss();
const setHoverOperation = useTooltipsStore(state => state.setActiveOperation); const setHoverOperation = useOperationTooltipStore(state => state.setActiveOperation);
const showGrid = useOSSGraphStore(state => state.showGrid); const showGrid = useOSSGraphStore(state => state.showGrid);
const edgeAnimate = useOSSGraphStore(state => state.edgeAnimate); const edgeAnimate = useOSSGraphStore(state => state.edgeAnimate);

View File

@ -3,11 +3,11 @@
import { Overlay } from '@/components/Container'; import { Overlay } from '@/components/Container';
import { IconConsolidation, IconRSForm } from '@/components/Icons'; import { IconConsolidation, IconRSForm } from '@/components/Icons';
import { Indicator } from '@/components/View'; import { Indicator } from '@/components/View';
import { useTooltipsStore } from '@/stores/tooltips';
import { globalIDs } from '@/utils/constants'; import { globalIDs } from '@/utils/constants';
import { OperationType } from '../../../../backend/types'; import { OperationType } from '../../../../backend/types';
import { type OssNodeInternal } from '../../../../models/ossLayout'; import { type OssNodeInternal } from '../../../../models/ossLayout';
import { useOperationTooltipStore } from '../../../../stores/operationTooltip';
// characters - threshold for long labels - small font // characters - threshold for long labels - small font
const LONG_LABEL_CHARS = 14; const LONG_LABEL_CHARS = 14;
@ -17,7 +17,7 @@ interface NodeCoreProps {
} }
export function NodeCore({ node }: NodeCoreProps) { export function NodeCore({ node }: NodeCoreProps) {
const setHover = useTooltipsStore(state => state.setActiveOperation); const setHover = useOperationTooltipStore(state => state.setActiveOperation);
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;

View File

@ -6,6 +6,7 @@ import { useParams } from 'react-router';
import { z } from 'zod'; import { z } from 'zod';
import { urls, useBlockNavigation, useConceptNavigation } from '@/app'; import { urls, useBlockNavigation, useConceptNavigation } from '@/app';
import { ConstituentaTooltip } from '@/features/rsform/components';
import { isAxiosError } from '@/backend/apiTransport'; import { isAxiosError } from '@/backend/apiTransport';
import { TextURL } from '@/components/Control'; import { TextURL } from '@/components/Control';
@ -13,6 +14,8 @@ import { type ErrorData } from '@/components/InfoError';
import { useQueryStrings } from '@/hooks/useQueryStrings'; import { useQueryStrings } from '@/hooks/useQueryStrings';
import { useModificationStore } from '@/stores/modification'; import { useModificationStore } from '@/stores/modification';
import { OperationTooltip } from '../../components/OperationTooltip';
import { OssEditState, OssTabID } from './OssEditContext'; import { OssEditState, OssTabID } from './OssEditContext';
import { OssTabs } from './OssTabs'; import { OssTabs } from './OssTabs';
@ -43,6 +46,8 @@ export function OssPage() {
return ( return (
<ErrorBoundary FallbackComponent={ProcessError}> <ErrorBoundary FallbackComponent={ProcessError}>
<OperationTooltip />
<ConstituentaTooltip />
<OssEditState itemID={urlData.id}> <OssEditState itemID={urlData.id}>
<OssTabs activeTab={urlData.tab} /> <OssTabs activeTab={urlData.tab} />
</OssEditState> </OssEditState>

View File

@ -0,0 +1,13 @@
import { create } from 'zustand';
import { type IOperation } from '../models/oss';
interface OperationTooltipStore {
activeOperation: IOperation | null;
setActiveOperation: (value: IOperation | null) => void;
}
export const useOperationTooltipStore = create<OperationTooltipStore>()(set => ({
activeOperation: null,
setActiveOperation: value => set({ activeOperation: value })
}));

View File

@ -1,12 +1,12 @@
import clsx from 'clsx'; import clsx from 'clsx';
import { type Styling } from '@/components/props'; import { type Styling } from '@/components/props';
import { useTooltipsStore } from '@/stores/tooltips';
import { APP_COLORS } from '@/styling/colors'; import { APP_COLORS } from '@/styling/colors';
import { globalIDs } from '@/utils/constants'; import { globalIDs } from '@/utils/constants';
import { colorFgCstStatus } from '../colors'; import { colorFgCstStatus } from '../colors';
import { CstClass, type IConstituenta } from '../models/rsform'; import { CstClass, type IConstituenta } from '../models/rsform';
import { useCstTooltipStore } from '../stores/cstTooltip';
interface BadgeConstituentaProps extends Styling { interface BadgeConstituentaProps extends Styling {
/** Prefix for tooltip ID. */ /** Prefix for tooltip ID. */
@ -20,7 +20,7 @@ interface BadgeConstituentaProps extends Styling {
* Displays a badge with a constituenta alias and information tooltip. * Displays a badge with a constituenta alias and information tooltip.
*/ */
export function BadgeConstituenta({ value, prefixID, className, style }: BadgeConstituentaProps) { export function BadgeConstituenta({ value, prefixID, className, style }: BadgeConstituentaProps) {
const setActiveCst = useTooltipsStore(state => state.setActiveCst); const setActiveCst = useCstTooltipStore(state => state.setActiveCst);
return ( return (
<div <div

View File

@ -0,0 +1,21 @@
import { Tooltip } from '@/components/Container';
import { globalIDs } from '@/utils/constants';
import { useCstTooltipStore } from '../stores/cstTooltip';
import { InfoConstituenta } from './InfoConstituenta';
export function ConstituentaTooltip() {
const hoverCst = useCstTooltipStore(state => state.activeCst);
return (
<Tooltip
clickable
id={globalIDs.constituenta_tooltip}
layer='z-topmost'
className='max-w-[30rem]'
hidden={!hoverCst}
>
{hoverCst ? <InfoConstituenta data={hoverCst} onClick={event => event.stopPropagation()} /> : null}
</Tooltip>
);
}

View File

@ -1,3 +1,4 @@
export { ConstituentaTooltip } from './ConstituentaTooltip';
export { PickMultiConstituenta } from './PickMultiConstituenta'; export { PickMultiConstituenta } from './PickMultiConstituenta';
export { PickSubstitutions } from './PickSubstitutions'; export { PickSubstitutions } from './PickSubstitutions';
export { ToolbarRSFormCard } from './ToolbarRSFormCard'; export { ToolbarRSFormCard } from './ToolbarRSFormCard';

View File

@ -7,12 +7,12 @@ import { MiniButton } from '@/components/Control';
import { IconDropArrow, IconDropArrowUp } from '@/components/Icons'; import { IconDropArrow, IconDropArrowUp } from '@/components/Icons';
import { useWindowSize } from '@/hooks/useWindowSize'; import { useWindowSize } from '@/hooks/useWindowSize';
import { useFitHeight } from '@/stores/appLayout'; import { useFitHeight } from '@/stores/appLayout';
import { useTooltipsStore } from '@/stores/tooltips';
import { APP_COLORS } from '@/styling/colors'; import { APP_COLORS } from '@/styling/colors';
import { globalIDs, PARAMETER, prefixes } from '@/utils/constants'; import { globalIDs, PARAMETER, prefixes } from '@/utils/constants';
import { colorBgGraphNode } from '../../../colors'; import { colorBgGraphNode } from '../../../colors';
import { type IConstituenta } from '../../../models/rsform'; import { type IConstituenta } from '../../../models/rsform';
import { useCstTooltipStore } from '../../../stores/cstTooltip';
import { useTermGraphStore } from '../../../stores/termGraph'; import { useTermGraphStore } from '../../../stores/termGraph';
import { useRSEdit } from '../RSEditContext'; import { useRSEdit } from '../RSEditContext';
@ -28,7 +28,7 @@ export function ViewHidden({ items }: ViewHiddenProps) {
const localSelected = items.filter(id => selected.includes(id)); const localSelected = items.filter(id => selected.includes(id));
const isFolded = useTermGraphStore(state => state.foldHidden); const isFolded = useTermGraphStore(state => state.foldHidden);
const toggleFolded = useTermGraphStore(state => state.toggleFoldHidden); const toggleFolded = useTermGraphStore(state => state.toggleFoldHidden);
const setActiveCst = useTooltipsStore(state => state.setActiveCst); const setActiveCst = useCstTooltipStore(state => state.setActiveCst);
const hiddenHeight = useFitHeight(windowSize.isSmall ? '10.4rem + 2px' : '12.5rem + 2px'); const hiddenHeight = useFitHeight(windowSize.isSmall ? '10.4rem + 2px' : '12.5rem + 2px');
function handleClick(event: React.MouseEvent<Element>, cstID: number) { function handleClick(event: React.MouseEvent<Element>, cstID: number) {

View File

@ -14,6 +14,8 @@ import { type ErrorData } from '@/components/InfoError';
import { useQueryStrings } from '@/hooks/useQueryStrings'; import { useQueryStrings } from '@/hooks/useQueryStrings';
import { useModificationStore } from '@/stores/modification'; import { useModificationStore } from '@/stores/modification';
import { ConstituentaTooltip } from '../../components/ConstituentaTooltip';
import { RSEditState, RSTabID } from './RSEditContext'; import { RSEditState, RSTabID } from './RSEditContext';
import { RSTabs } from './RSTabs'; import { RSTabs } from './RSTabs';
@ -57,6 +59,7 @@ export function RSFormPage() {
<ProcessError error={error as ErrorData} isArchive={!!urlData.version} itemID={urlData.id} /> <ProcessError error={error as ErrorData} isArchive={!!urlData.version} itemID={urlData.id} />
)} )}
> >
<ConstituentaTooltip />
<RSEditState itemID={urlData.id} activeVersion={urlData.version} activeTab={urlData.tab}> <RSEditState itemID={urlData.id} activeVersion={urlData.version} activeTab={urlData.tab}>
<RSTabs activeID={urlData.activeID} activeTab={urlData.tab} /> <RSTabs activeID={urlData.activeID} activeTab={urlData.tab} />
</RSEditState> </RSEditState>

View File

@ -0,0 +1,13 @@
import { create } from 'zustand';
import { type IConstituenta } from '../models/rsform';
interface CstTooltipStore {
activeCst: IConstituenta | null;
setActiveCst: (value: IConstituenta | null) => void;
}
export const useCstTooltipStore = create<CstTooltipStore>()(set => ({
activeCst: null,
setActiveCst: value => set({ activeCst: value })
}));

View File

@ -1,19 +0,0 @@
import { create } from 'zustand';
import { type IOperation } from '@/features/oss';
import { type IConstituenta } from '@/features/rsform';
interface TooltipsStore {
activeCst: IConstituenta | null;
setActiveCst: (value: IConstituenta | null) => void;
activeOperation: IOperation | null;
setActiveOperation: (value: IOperation | null) => void;
}
export const useTooltipsStore = create<TooltipsStore>()(set => ({
activeCst: null,
setActiveCst: value => set({ activeCst: value }),
activeOperation: null,
setActiveOperation: value => set({ activeOperation: value })
}));