mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-12-12 18:56:01 +00:00
fix: prevent constant full signature widget rerender (#195)
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import React from 'react';
|
||||
import { SystemView, WdCheckbox, WdImgButton, TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { PrimeIcons } from 'primereact/api';
|
||||
import { CheckboxChangeEvent } from 'primereact/checkbox';
|
||||
import { InfoDrawer, LayoutEventBlocker } from '@/hooks/Mapper/components/ui-kit';
|
||||
import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper';
|
||||
|
||||
export type HeaderProps = {
|
||||
systemId: string;
|
||||
isNotSelectedSystem: boolean;
|
||||
sigCount: number;
|
||||
isCompact: boolean;
|
||||
lazyDeleteValue: boolean;
|
||||
onLazyDeleteChange: (checked: boolean) => void;
|
||||
pendingCount: number;
|
||||
onUndoClick: () => void;
|
||||
onSettingsClick: () => void;
|
||||
};
|
||||
|
||||
function HeaderImpl({
|
||||
systemId,
|
||||
isNotSelectedSystem,
|
||||
sigCount,
|
||||
isCompact,
|
||||
lazyDeleteValue,
|
||||
onLazyDeleteChange,
|
||||
pendingCount,
|
||||
onUndoClick,
|
||||
onSettingsClick,
|
||||
}: HeaderProps) {
|
||||
return (
|
||||
<div className="flex justify-between items-center text-xs w-full h-full">
|
||||
<div className="flex justify-between items-center gap-1">
|
||||
{!isCompact && (
|
||||
<div className="flex whitespace-nowrap text-ellipsis overflow-hidden text-stone-400">
|
||||
{sigCount ? `[${sigCount}] ` : ''}Signatures {isNotSelectedSystem ? '' : 'in'}
|
||||
</div>
|
||||
)}
|
||||
{!isNotSelectedSystem && <SystemView systemId={systemId} className="select-none text-center" hideRegion />}
|
||||
</div>
|
||||
|
||||
<LayoutEventBlocker className="flex gap-2.5">
|
||||
<WdTooltipWrapper content="Enable Lazy delete">
|
||||
<WdCheckbox
|
||||
size="xs"
|
||||
labelSide="left"
|
||||
label={isCompact ? '' : 'Lazy delete'}
|
||||
value={lazyDeleteValue}
|
||||
classNameLabel="text-stone-400 hover:text-stone-200 transition duration-300 whitespace-nowrap text-ellipsis overflow-hidden"
|
||||
onChange={(event: CheckboxChangeEvent) => onLazyDeleteChange(!!event.checked)}
|
||||
/>
|
||||
</WdTooltipWrapper>
|
||||
|
||||
{pendingCount > 0 && (
|
||||
<WdImgButton
|
||||
className={PrimeIcons.UNDO}
|
||||
style={{ color: 'red' }}
|
||||
tooltip={{ content: `Undo pending changes (${pendingCount})` }}
|
||||
onClick={onUndoClick}
|
||||
/>
|
||||
)}
|
||||
|
||||
<WdImgButton
|
||||
className={PrimeIcons.QUESTION_CIRCLE}
|
||||
tooltip={{
|
||||
position: TooltipPosition.left,
|
||||
content: (
|
||||
<div className="flex flex-col gap-1">
|
||||
<InfoDrawer title={<b className="text-slate-50">How to add/update signature?</b>}>
|
||||
In game you need to select one or more signatures <br /> in the list in{' '}
|
||||
<b className="text-sky-500">Probe scanner</b>. <br /> Use next hotkeys:
|
||||
<br />
|
||||
<b className="text-sky-500">Shift + LMB</b> or <b className="text-sky-500">Ctrl + LMB</b>
|
||||
<br /> or <b className="text-sky-500">Ctrl + A</b> for select all
|
||||
<br /> and then use <b className="text-sky-500">Ctrl + C</b>, after you need to go <br />
|
||||
here, select Solar system and paste it with <b className="text-sky-500">Ctrl + V</b>
|
||||
</InfoDrawer>
|
||||
<InfoDrawer title={<b className="text-slate-50">How to select?</b>}>
|
||||
For selecting any signature, click on it <br /> with hotkeys{' '}
|
||||
<b className="text-sky-500">Shift + LMB</b> or <b className="text-sky-500">Ctrl + LMB</b>
|
||||
</InfoDrawer>
|
||||
<InfoDrawer title={<b className="text-slate-50">How to delete?</b>}>
|
||||
To delete any signature, first select it <br /> and then press <b className="text-sky-500">Del</b>
|
||||
</InfoDrawer>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
|
||||
<WdImgButton className={PrimeIcons.SLIDERS_H} onClick={onSettingsClick} />
|
||||
</LayoutEventBlocker>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const SystemSignaturesHeader = React.memo(HeaderImpl);
|
||||
@@ -1,13 +1,5 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Widget } from '@/hooks/Mapper/components/mapInterface/components';
|
||||
import {
|
||||
InfoDrawer,
|
||||
LayoutEventBlocker,
|
||||
SystemView,
|
||||
TooltipPosition,
|
||||
WdCheckbox,
|
||||
WdImgButton,
|
||||
} from '@/hooks/Mapper/components/ui-kit';
|
||||
import { SystemSignaturesContent } from './SystemSignaturesContent';
|
||||
import {
|
||||
COSMIC_ANOMALY,
|
||||
@@ -21,13 +13,11 @@ import {
|
||||
SystemSignatureSettingsDialog,
|
||||
} from './SystemSignatureSettingsDialog';
|
||||
import { SignatureGroup, SystemSignature } from '@/hooks/Mapper/types';
|
||||
import { PrimeIcons } from 'primereact/api';
|
||||
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
|
||||
import { CheckboxChangeEvent } from 'primereact/checkbox';
|
||||
import useMaxWidth from '@/hooks/Mapper/hooks/useMaxWidth';
|
||||
import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper';
|
||||
import { useHotkey } from '@/hooks/Mapper/hooks';
|
||||
import { COMPACT_MAX_WIDTH } from './constants';
|
||||
import { renderHeaderLabel } from './renders';
|
||||
|
||||
const SIGNATURE_SETTINGS_KEY = 'wanderer_system_signature_settings_v5_5';
|
||||
export const SHOW_DESCRIPTION_COLUMN_SETTING = 'show_description_column_setting';
|
||||
@@ -58,7 +48,9 @@ const SETTINGS: Setting[] = [
|
||||
{ key: SignatureGroup.CombatSite, name: 'Show Combat Sites', value: true, isFilter: true },
|
||||
];
|
||||
|
||||
const getDefaultSettings = (): Setting[] => [...SETTINGS];
|
||||
function getDefaultSettings(): Setting[] {
|
||||
return [...SETTINGS];
|
||||
}
|
||||
|
||||
export const SystemSignatures: React.FC = () => {
|
||||
const {
|
||||
@@ -85,7 +77,8 @@ export const SystemSignatures: React.FC = () => {
|
||||
|
||||
const [sigCount, setSigCount] = useState<number>(0);
|
||||
const [pendingSigs, setPendingSigs] = useState<SystemSignature[]>([]);
|
||||
const [undoPending, setUndoPending] = useState<() => void>(() => () => {});
|
||||
|
||||
const undoPendingFnRef = useRef<() => void>(() => {});
|
||||
|
||||
const handleSigCountChange = useCallback((count: number) => {
|
||||
setSigCount(count);
|
||||
@@ -96,7 +89,7 @@ export const SystemSignatures: React.FC = () => {
|
||||
|
||||
const lazyDeleteValue = useMemo(
|
||||
() => currentSettings.find(setting => setting.key === LAZY_DELETE_SIGNATURES_SETTING)?.value || false,
|
||||
[currentSettings],
|
||||
[currentSettings]
|
||||
);
|
||||
|
||||
const handleSettingsChange = useCallback((newSettings: Setting[]) => {
|
||||
@@ -106,93 +99,59 @@ export const SystemSignatures: React.FC = () => {
|
||||
|
||||
const handleLazyDeleteChange = useCallback((value: boolean) => {
|
||||
setCurrentSettings(prevSettings =>
|
||||
prevSettings.map(setting => (setting.key === LAZY_DELETE_SIGNATURES_SETTING ? { ...setting, value } : setting)),
|
||||
prevSettings.map(setting => (setting.key === LAZY_DELETE_SIGNATURES_SETTING ? { ...setting, value } : setting))
|
||||
);
|
||||
}, []);
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const isCompact = useMaxWidth(containerRef, COMPACT_MAX_WIDTH);
|
||||
|
||||
useHotkey(true, ['z'], (event: KeyboardEvent) => {
|
||||
useHotkey(true, ['z'], event => {
|
||||
if (pendingSigs.length > 0) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
undoPending();
|
||||
undoPendingFnRef.current();
|
||||
setPendingSigs([]);
|
||||
}
|
||||
});
|
||||
|
||||
const handleUndoClick = useCallback(() => {
|
||||
undoPending();
|
||||
undoPendingFnRef.current();
|
||||
setPendingSigs([]);
|
||||
}, [undoPending]);
|
||||
}, []);
|
||||
|
||||
const handleSettingsButtonClick = useCallback(() => {
|
||||
setVisible(true);
|
||||
}, []);
|
||||
|
||||
const renderLabel = () => (
|
||||
<div className="flex justify-between items-center text-xs w-full h-full" ref={containerRef}>
|
||||
<div className="flex justify-between items-center gap-1">
|
||||
{!isCompact && (
|
||||
<div className="flex whitespace-nowrap text-ellipsis overflow-hidden text-stone-400">
|
||||
{sigCount ? `[${sigCount}] ` : ''}Signatures {isNotSelectedSystem ? '' : 'in'}
|
||||
</div>
|
||||
)}
|
||||
{!isNotSelectedSystem && <SystemView systemId={systemId} className="select-none text-center" hideRegion />}
|
||||
</div>
|
||||
<LayoutEventBlocker className="flex gap-2.5">
|
||||
<WdTooltipWrapper content="Enable Lazy delete">
|
||||
<WdCheckbox
|
||||
size="xs"
|
||||
labelSide="left"
|
||||
label={isCompact ? '' : 'Lazy delete'}
|
||||
value={lazyDeleteValue}
|
||||
classNameLabel="text-stone-400 hover:text-stone-200 transition duration-300 whitespace-nowrap text-ellipsis overflow-hidden"
|
||||
onChange={(event: CheckboxChangeEvent) => handleLazyDeleteChange(!!event.checked)}
|
||||
/>
|
||||
</WdTooltipWrapper>
|
||||
{pendingSigs.length > 0 && (
|
||||
<WdImgButton
|
||||
className={PrimeIcons.UNDO}
|
||||
style={{ color: 'red' }}
|
||||
tooltip={{ content: `Undo pending changes (${pendingSigs.length})` }}
|
||||
onClick={handleUndoClick}
|
||||
/>
|
||||
)}
|
||||
<WdImgButton
|
||||
className={PrimeIcons.QUESTION_CIRCLE}
|
||||
tooltip={{
|
||||
position: TooltipPosition.left,
|
||||
content: (
|
||||
<div className="flex flex-col gap-1">
|
||||
<InfoDrawer title={<b className="text-slate-50">How to add/update signature?</b>}>
|
||||
In game you need to select one or more signatures <br /> in the list in{' '}
|
||||
<b className="text-sky-500">Probe scanner</b>. <br /> Use next hotkeys:
|
||||
<br />
|
||||
<b className="text-sky-500">Shift + LMB</b> or <b className="text-sky-500">Ctrl + LMB</b>
|
||||
<br /> or <b className="text-sky-500">Ctrl + A</b> for select all
|
||||
<br /> and then use <b className="text-sky-500">Ctrl + C</b>, after you need to go <br />
|
||||
here, select Solar system and paste it with <b className="text-sky-500">Ctrl + V</b>
|
||||
</InfoDrawer>
|
||||
<InfoDrawer title={<b className="text-slate-50">How to select?</b>}>
|
||||
For selecting any signature, click on it <br /> with hotkeys{' '}
|
||||
<b className="text-sky-500">Shift + LMB</b> or <b className="text-sky-500">Ctrl + LMB</b>
|
||||
</InfoDrawer>
|
||||
<InfoDrawer title={<b className="text-slate-50">How to delete?</b>}>
|
||||
To delete any signature, first select it <br /> and then press <b className="text-sky-500">Del</b>
|
||||
</InfoDrawer>
|
||||
</div>
|
||||
) as React.ReactNode,
|
||||
}}
|
||||
/>
|
||||
<WdImgButton className={PrimeIcons.SLIDERS_H} onClick={handleSettingsButtonClick} />
|
||||
</LayoutEventBlocker>
|
||||
</div>
|
||||
);
|
||||
const handlePendingChange = useCallback((newPending: SystemSignature[], newUndo: () => void) => {
|
||||
setPendingSigs(prev => {
|
||||
if (newPending.length === prev.length && newPending.every(np => prev.some(pp => pp.eve_id === np.eve_id))) {
|
||||
return prev;
|
||||
}
|
||||
return newPending;
|
||||
});
|
||||
undoPendingFnRef.current = newUndo;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Widget label={renderLabel()}>
|
||||
<Widget
|
||||
label={
|
||||
<div ref={containerRef} className="w-full">
|
||||
{renderHeaderLabel({
|
||||
systemId,
|
||||
isNotSelectedSystem,
|
||||
isCompact,
|
||||
sigCount,
|
||||
lazyDeleteValue,
|
||||
pendingCount: pendingSigs.length,
|
||||
onLazyDeleteChange: handleLazyDeleteChange,
|
||||
onUndoClick: handleUndoClick,
|
||||
onSettingsClick: handleSettingsButtonClick,
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{isNotSelectedSystem ? (
|
||||
<div className="w-full h-full flex justify-center items-center select-none text-center text-stone-400/80 text-sm">
|
||||
System is not selected
|
||||
@@ -203,10 +162,7 @@ export const SystemSignatures: React.FC = () => {
|
||||
settings={currentSettings}
|
||||
onLazyDeleteChange={handleLazyDeleteChange}
|
||||
onCountChange={handleSigCountChange}
|
||||
onPendingChange={(pending, undo) => {
|
||||
setPendingSigs(pending);
|
||||
setUndoPending(() => undo);
|
||||
}}
|
||||
onPendingChange={handlePendingChange}
|
||||
/>
|
||||
)}
|
||||
{visible && (
|
||||
|
||||
@@ -5,3 +5,4 @@ export * from './renderAddedTimeLeft';
|
||||
export * from './renderUpdatedTimeLeft';
|
||||
export * from './renderLinkedSystem';
|
||||
export * from './renderInfoColumn';
|
||||
export * from './renderHeaderLabel';
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { SystemSignaturesHeader, HeaderProps } from '../SystemSignatureHeader/SystemSignatureHeader';
|
||||
|
||||
export function renderHeaderLabel(props: HeaderProps) {
|
||||
return <SystemSignaturesHeader {...props} />;
|
||||
}
|
||||
Reference in New Issue
Block a user