Merge pull request #117 from guarzo/guarzo/import

Clean-up theme swap logic for nodes
This commit is contained in:
Aleksei Chichenkov
2025-01-14 17:15:53 +03:00
committed by GitHub
13 changed files with 372 additions and 234 deletions

View File

@@ -1,7 +1,6 @@
import { ForwardedRef, forwardRef, MouseEvent, useCallback, useEffect, useMemo } from 'react';
import ReactFlow, {
Background,
ConnectionMode,
Edge,
MiniMap,
Node,
@@ -23,12 +22,10 @@ import {
ContextMenuConnection,
ContextMenuRoot,
SolarSystemEdge,
SolarSystemNodeDefault,
SolarSystemNodeTheme,
useContextMenuConnectionHandlers,
useContextMenuRootHandlers,
} from './components';
import { wrapNode } from './utils/wrapNode';
import { getBehaviorForTheme } from './helpers/getThemeBehavior';
import { OnMapAddSystemCallback, OnMapSelectionChange } from './map.types';
import { SESSION_KEY } from '@/hooks/Mapper/constants.ts';
import { SolarSystemConnection, SolarSystemRawType } from '@/hooks/Mapper/types';
@@ -77,9 +74,6 @@ const initialEdges = [
},
];
const edgeTypes = {
floating: SolarSystemEdge,
};
@@ -123,23 +117,20 @@ const MapComp = ({
const [nodes, , onNodesChange] = useNodesState<Node<SolarSystemRawType>>(initialNodes);
const [edges, , onEdgesChange] = useEdgesState<Edge<SolarSystemConnection>>(initialEdges);
const nodeTypes = useMemo(() => {
return {
custom:
theme !== '' && theme !== 'default'
? wrapNode(SolarSystemNodeTheme)
: wrapNode(SolarSystemNodeDefault),
};
}, [theme]);
useMapHandlers(refn, onSelectionChange);
useUpdateNodes(nodes);
const { handleRootContext, ...rootCtxProps } = useContextMenuRootHandlers({ onAddSystem });
const { handleConnectionContext, ...connectionCtxProps } = useContextMenuConnectionHandlers();
const { update } = useMapState();
const { variant, gap, size, color } = useBackgroundVars(theme);
const { isPanAndDrag, nodeComponent, connectionMode } = getBehaviorForTheme(theme || 'default');
// You can create nodeTypes dynamically based on the node component
const nodeTypes = useMemo(() => {
return {
custom: nodeComponent,
};
}, [nodeComponent]);
const onConnect: OnConnect = useCallback(
params => {
@@ -228,7 +219,7 @@ const MapComp = ({
onNodesChange(nextChanges);
},
[getNode, onManualDelete, onNodesChange],
[getNode, getNodes, onManualDelete, onNodesChange],
);
useEffect(() => {
@@ -253,7 +244,7 @@ const MapComp = ({
defaultViewport={getViewPortFromStore()}
edgeTypes={edgeTypes}
nodeTypes={nodeTypes}
connectionMode={ConnectionMode.Loose}
connectionMode={connectionMode}
snapToGrid
nodeDragThreshold={10}
onNodeDragStop={handleDragStop}
@@ -286,6 +277,12 @@ const MapComp = ({
maxZoom={1.5}
elevateNodesOnSelect
deleteKeyCode={['Delete']}
{...(isPanAndDrag
? {
selectionOnDrag: true,
panOnDrag: [2],
}
: {})}
// TODO need create clear example with problem with that flag
// if system is not visible edge not drawing (and any render in Custom node is not happening)
// onlyRenderVisibleElements

View File

@@ -9,6 +9,7 @@ export type MapData = MapUnionTypes & {
visibleNodes: Set<string>;
showKSpaceBG: boolean;
isThickConnections: boolean;
linkedSigEveId: string;
};
interface MapProviderProps {

View File

@@ -6,7 +6,14 @@ $pastel-green: #88b04b;
$pastel-yellow: #ffdd59;
$dark-bg: #2d2d2d;
$text-color: #ffffff;
$tooltip-bg: #202020; // Dark background for tooltips
$tooltip-bg: #202020;
$node-bg-color: #202020;
$node-soft-bg-color: #202020;
$text-color: #ffffff;
$tag-color: #38BDF8;
$region-name: #D6D3D1;
$custom-name: #93C5FD;
.RootCustomNode {
display: flex;

View File

@@ -1,12 +1,10 @@
import { memo } from 'react';
import { Handle, Position } from 'reactflow';
import { MapSolarSystemType } from '../../map.types';
import { Handle, Position, NodeProps } from 'reactflow';
import clsx from 'clsx';
import classes from './SolarSystemNodeDefault.module.scss';
import { PrimeIcons } from 'primereact/api';
import { useSolarSystemNode } from '../../hooks/useSolarSystemNode';
import {
MARKER_BOOKMARK_BG_STYLES,
STATUS_CLASSES,
@@ -15,64 +13,36 @@ import {
import { WormholeClassComp } from '@/hooks/Mapper/components/map/components/WormholeClassComp';
import { UnsplashedSignature } from '@/hooks/Mapper/components/map/components/UnsplashedSignature';
export const SolarSystemNodeDefault = memo(props => {
const {
charactersInSystem,
classTitle,
classTitleColor,
customName,
effectName,
hasUserCharacters,
hubs,
visible,
labelCustom,
labelsInfo,
locked,
isShattered,
isThickConnections,
isWormhole,
killsCount,
killsActivityType,
regionClass,
regionName,
status,
selected,
tag,
showHandlers,
systemName,
sortedStatics,
solarSystemId,
unsplashedLeft,
unsplashedRight,
dbClick: handleDbClick,
} = useSolarSystemNode(props);
// eslint-disable-next-line react/display-name
export const SolarSystemNodeDefault = memo((props: NodeProps<MapSolarSystemType>) => {
const nodeVars = useSolarSystemNode(props);
return (
<>
{visible && (
{nodeVars.visible && (
<div className={classes.Bookmarks}>
{labelCustom !== '' && (
{nodeVars.labelCustom !== '' && (
<div className={clsx(classes.Bookmark, MARKER_BOOKMARK_BG_STYLES.custom)}>
<span className="[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)] ">{labelCustom}</span>
<span className="[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)] ">{nodeVars.labelCustom}</span>
</div>
)}
{isShattered && (
{nodeVars.isShattered && (
<div className={clsx(classes.Bookmark, MARKER_BOOKMARK_BG_STYLES.shattered)}>
<span className={clsx('pi pi-chart-pie', classes.icon)} />
</div>
)}
{killsCount && (
<div className={clsx(classes.Bookmark, MARKER_BOOKMARK_BG_STYLES[killsActivityType!])}>
{nodeVars.killsCount && (
<div className={clsx(classes.Bookmark, MARKER_BOOKMARK_BG_STYLES[nodeVars.killsActivityType!])}>
<div className={clsx(classes.BookmarkWithIcon)}>
<span className={clsx(PrimeIcons.BOLT, classes.icon)} />
<span className={clsx(classes.text)}>{killsCount}</span>
<span className={clsx(classes.text)}>{nodeVars.killsCount}</span>
</div>
</div>
)}
{labelsInfo.map(x => (
{nodeVars.labelsInfo.map(x => (
<div key={x.id} className={clsx(classes.Bookmark, MARKER_BOOKMARK_BG_STYLES[x.id])}>
{x.shortName}
</div>
@@ -81,19 +51,30 @@ export const SolarSystemNodeDefault = memo(props => {
)}
<div
className={clsx(classes.RootCustomNode, regionClass && classes[regionClass], classes[STATUS_CLASSES[status]], {
[classes.selected]: selected,
})}
className={clsx(
classes.RootCustomNode,
nodeVars.regionClass && classes[nodeVars.regionClass],
classes[STATUS_CLASSES[nodeVars.status]],
{
[classes.selected]: nodeVars.selected,
},
)}
>
{visible && (
{nodeVars.visible && (
<>
<div className={classes.HeadRow}>
<div className={clsx(classes.classTitle, classTitleColor, '[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)]')}>
{classTitle ?? '-'}
<div
className={clsx(
classes.classTitle,
nodeVars.classTitleColor,
'[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)]',
)}
>
{nodeVars.classTitle ?? '-'}
</div>
{tag != null && tag !== '' && (
<div className={clsx(classes.TagTitle, 'text-sky-400 font-medium')}>{tag}</div>
{nodeVars.tag != null && nodeVars.tag !== '' && (
<div className={clsx(classes.TagTitle, 'text-sky-400 font-medium')}>{nodeVars.tag}</div>
)}
<div
@@ -102,53 +83,55 @@ export const SolarSystemNodeDefault = memo(props => {
'[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)] flex-grow overflow-hidden text-ellipsis whitespace-nowrap font-sans',
)}
>
{systemName}
{nodeVars.systemName}
</div>
{isWormhole && (
{nodeVars.isWormhole && (
<div className={classes.statics}>
{sortedStatics.map(whClass => (
{nodeVars.sortedStatics.map(whClass => (
<WormholeClassComp key={whClass} id={whClass} />
))}
</div>
)}
{effectName !== null && isWormhole && (
<div className={clsx(classes.effect, EFFECT_BACKGROUND_STYLES[effectName])} />
{nodeVars.effectName !== null && nodeVars.isWormhole && (
<div className={clsx(classes.effect, EFFECT_BACKGROUND_STYLES[nodeVars.effectName])} />
)}
</div>
<div className={clsx(classes.BottomRow, 'flex items-center justify-between')}>
{customName && (
{nodeVars.customName && (
<div className="[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)] text-blue-300 whitespace-nowrap overflow-hidden text-ellipsis mr-0.5">
{customName}
{nodeVars.customName}
</div>
)}
{!isWormhole && !customName && (
{!nodeVars.isWormhole && !nodeVars.customName && (
<div className="[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)] text-stone-300 whitespace-nowrap overflow-hidden text-ellipsis mr-0.5">
{regionName}
{nodeVars.regionName}
</div>
)}
{isWormhole && !customName && <div />}
{nodeVars.isWormhole && !nodeVars.customName && <div />}
<div className="flex items-center justify-end">
<div className="flex gap-1 items-center">
{locked && <i className={PrimeIcons.LOCK} style={{ fontSize: '0.45rem', fontWeight: 'bold' }} />}
{nodeVars.locked && (
<i className={PrimeIcons.LOCK} style={{ fontSize: '0.45rem', fontWeight: 'bold' }} />
)}
{hubs.includes(solarSystemId.toString()) && (
{nodeVars.hubs.includes(nodeVars.solarSystemId.toString()) && (
<i className={PrimeIcons.MAP_MARKER} style={{ fontSize: '0.45rem', fontWeight: 'bold' }} />
)}
{charactersInSystem.length > 0 && (
{nodeVars.charactersInSystem.length > 0 && (
<div
className={clsx(classes.localCounter, {
['text-amber-300']: hasUserCharacters,
['text-amber-300']: nodeVars.hasUserCharacters,
})}
>
<i className="pi pi-users" style={{ fontSize: '0.50rem' }} />
<span className="font-sans">{charactersInSystem.length}</span>
<span className="font-sans">{nodeVars.charactersInSystem.length}</span>
</div>
)}
</div>
@@ -158,19 +141,19 @@ export const SolarSystemNodeDefault = memo(props => {
)}
</div>
{visible && (
{nodeVars.visible && (
<>
{unsplashedLeft.length > 0 && (
{nodeVars.unsplashedLeft.length > 0 && (
<div className={classes.Unsplashed}>
{unsplashedLeft.map(sig => (
{nodeVars.unsplashedLeft.map(sig => (
<UnsplashedSignature key={sig.sig_id} signature={sig} />
))}
</div>
)}
{unsplashedRight.length > 0 && (
{nodeVars.unsplashedRight.length > 0 && (
<div className={clsx(classes.Unsplashed, classes['Unsplashed--right'])}>
{unsplashedRight.map(sig => (
{nodeVars.unsplashedRight.map(sig => (
<UnsplashedSignature key={sig.sig_id} signature={sig} />
))}
</div>
@@ -178,44 +161,44 @@ export const SolarSystemNodeDefault = memo(props => {
</>
)}
<div onMouseDownCapture={handleDbClick} className={classes.Handlers}>
<div onMouseDownCapture={nodeVars.dbClick} className={classes.Handlers}>
<Handle
type="source"
className={clsx(classes.Handle, classes.HandleTop, {
[classes.selected]: selected,
[classes.Tick]: isThickConnections,
[classes.selected]: nodeVars.selected,
[classes.Tick]: nodeVars.isThickConnections,
})}
style={{ visibility: showHandlers ? 'visible' : 'hidden' }}
style={{ visibility: nodeVars.showHandlers ? 'visible' : 'hidden' }}
position={Position.Top}
id="a"
/>
<Handle
type="source"
className={clsx(classes.Handle, classes.HandleRight, {
[classes.selected]: selected,
[classes.Tick]: isThickConnections,
[classes.selected]: nodeVars.selected,
[classes.Tick]: nodeVars.isThickConnections,
})}
style={{ visibility: showHandlers ? 'visible' : 'hidden' }}
style={{ visibility: nodeVars.showHandlers ? 'visible' : 'hidden' }}
position={Position.Right}
id="b"
/>
<Handle
type="source"
className={clsx(classes.Handle, classes.HandleBottom, {
[classes.selected]: selected,
[classes.Tick]: isThickConnections,
[classes.selected]: nodeVars.selected,
[classes.Tick]: nodeVars.isThickConnections,
})}
style={{ visibility: showHandlers ? 'visible' : 'hidden' }}
style={{ visibility: nodeVars.showHandlers ? 'visible' : 'hidden' }}
position={Position.Bottom}
id="c"
/>
<Handle
type="source"
className={clsx(classes.Handle, classes.HandleLeft, {
[classes.selected]: selected,
[classes.Tick]: isThickConnections,
[classes.selected]: nodeVars.selected,
[classes.Tick]: nodeVars.isThickConnections,
})}
style={{ visibility: showHandlers ? 'visible' : 'hidden' }}
style={{ visibility: nodeVars.showHandlers ? 'visible' : 'hidden' }}
position={Position.Left}
id="d"
/>

View File

@@ -6,7 +6,7 @@ $pastel-green: #88b04b;
$pastel-yellow: #ffdd59;
$dark-bg: #2d2d2d;
$text-color: #ffffff;
$tooltip-bg: #202020; // Dark background for tooltips
$tooltip-bg: #202020;
.RootCustomNode {
display: flex;
@@ -160,6 +160,9 @@ $tooltip-bg: #202020; // Dark background for tooltips
z-index: 1;
display: flex;
left: 4px;
font-family: var(--rf-node-font-family, inherit) !important;
font-weight: var(--rf-node-font-weight, inherit) !important;
& > .Bookmark {
min-width: 13px;
@@ -254,32 +257,28 @@ $tooltip-bg: #202020; // Dark background for tooltips
font-weight: 500;
position: relative;
top: 1px;
font-family: var(--rf-node-font-family, inherit) !important;
font-weight: var(--rf-node-font-weight, inherit) !important;
.classTitle {
font-size: 11px;
font-weight: bold;
font-family: var(--rf-node-font-family, inherit) !important;
font-weight: var(--rf-node-font-weight, inherit) !important;
text-shadow: 0 0 2px rgb(0 0 0 / 73%);
}
.TagTitle {
font-size: 11px;
font-weight: medium;
text-shadow: 0 0 2px rgba(231, 146, 52, 0.73);
color: var(--rf-tag-color, #38BDF8);
}
/* Firefox kostyl */
@-moz-document url-prefix() {
.classSystemName {
font-family: inherit !important;
font-weight: bold;
font-family: var(--rf-node-font-family, inherit) !important;
font-weight: var(--rf-node-font-weight, inherit) !important;
}
}
.classSystemName {
font-family: inherit !important;
font-weight: bold;
font-family: var(--rf-node-font-family, inherit) !important;
font-weight: var(--rf-node-font-weight, inherit) !important;
}
.solarSystemName {
@@ -291,22 +290,42 @@ $tooltip-bg: #202020; // Dark background for tooltips
justify-content: space-between;
align-items: center;
height: 19px;
font-family: var(--rf-node-font-family, inherit) !important;
font-weight: var(--rf-node-font-weight, inherit) !important;
.tagTitle {
font-size: 11px;
font-weight: medium;
text-shadow: 0 0 2px rgba(231, 146, 52, 0.73);
font-family: var(--rf-node-font-family, inherit) !important;
font-weight: var(--rf-node-font-weight, inherit) !important;
color: var(--rf-tag-color, #38BDF8);
}
.regionName {
color: var(--rf-region-name, #D6D3D1)
color: var(--rf-region-name, #D6D3D1);
font-family: var(--rf-node-font-family, inherit) !important;
font-weight: var(--rf-node-font-weight, inherit) !important;
}
.customName {
color: var(--rf-custom-name, #93C5FD)
color: var(--rf-custom-name, #93C5FD);
font-family: var(--rf-node-font-family, inherit) !important;
font-weight: var(--rf-node-font-weight, inherit) !important;
}
.localCounter {
display: flex;
//align-items: center;
color: var(--rf-has-user-characters, #fbbf24);
font-family: var(--rf-node-font-family, inherit) !important;
font-weight: var(--rf-node-font-weight, inherit) !important;
gap: 2px;
.hasUserCharacters {
color: var(--rf-has-user-characters, #fbbf24);
font-family: var(--rf-node-font-family, inherit) !important;
font-weight: var(--rf-node-font-weight, inherit) !important;
}
& > i {

View File

@@ -1,12 +1,10 @@
import { memo } from 'react';
import { Handle, Position } from 'reactflow';
import { MapSolarSystemType } from '../../map.types';
import { Handle, Position, NodeProps } from 'reactflow';
import clsx from 'clsx';
import classes from './SolarSystemNodeTheme.module.scss';
import { PrimeIcons } from 'primereact/api';
import { useSolarSystemNode } from '../../hooks/useSolarSystemNode';
import {
MARKER_BOOKMARK_BG_STYLES,
STATUS_CLASSES,
@@ -15,64 +13,35 @@ import {
import { WormholeClassComp } from '@/hooks/Mapper/components/map/components/WormholeClassComp';
import { UnsplashedSignature } from '@/hooks/Mapper/components/map/components/UnsplashedSignature';
export const SolarSystemNodeTheme = memo(props => {
const {
charactersInSystem,
classTitle,
classTitleColor,
customName,
effectName,
hasUserCharacters,
hubs,
visible,
labelCustom,
labelsInfo,
locked,
isShattered,
isThickConnections,
isWormhole,
killsCount,
killsActivityType,
regionClass,
regionName,
status,
selected,
tag,
showHandlers,
systemName,
sortedStatics,
solarSystemId,
unsplashedLeft,
unsplashedRight,
dbClick: handleDbClick,
} = useSolarSystemNode(props);
export const SolarSystemNodeTheme = memo((props: NodeProps<MapSolarSystemType>) => {
const nodeVars = useSolarSystemNode(props);
return (
<>
{visible && (
{nodeVars.visible && (
<div className={classes.Bookmarks}>
{labelCustom !== '' && (
{nodeVars.labelCustom !== '' && (
<div className={clsx(classes.Bookmark, MARKER_BOOKMARK_BG_STYLES.custom)}>
<span className="[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)] ">{labelCustom}</span>
<span className="[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)] ">{nodeVars.labelCustom}</span>
</div>
)}
{isShattered && (
{nodeVars.isShattered && (
<div className={clsx(classes.Bookmark, MARKER_BOOKMARK_BG_STYLES.shattered)}>
<span className={clsx('pi pi-chart-pie', classes.icon)} />
</div>
)}
{killsCount && (
<div className={clsx(classes.Bookmark, MARKER_BOOKMARK_BG_STYLES[killsActivityType!])}>
{nodeVars.killsCount && (
<div className={clsx(classes.Bookmark, MARKER_BOOKMARK_BG_STYLES[nodeVars.killsActivityType!])}>
<div className={clsx(classes.BookmarkWithIcon)}>
<span className={clsx(PrimeIcons.BOLT, classes.icon)} />
<span className={clsx(classes.text)}>{killsCount}</span>
<span className={clsx(classes.text)}>{nodeVars.killsCount}</span>
</div>
</div>
)}
{labelsInfo.map(x => (
{nodeVars.labelsInfo.map(x => (
<div key={x.id} className={clsx(classes.Bookmark, MARKER_BOOKMARK_BG_STYLES[x.id])}>
{x.shortName}
</div>
@@ -81,18 +50,31 @@ export const SolarSystemNodeTheme = memo(props => {
)}
<div
className={clsx(classes.RootCustomNode, regionClass && classes[regionClass], classes[STATUS_CLASSES[status]], {
[classes.selected]: selected,
})}
className={clsx(
classes.RootCustomNode,
nodeVars.regionClass && classes[nodeVars.regionClass],
classes[STATUS_CLASSES[nodeVars.status]],
{
[classes.selected]: nodeVars.selected,
},
)}
>
{visible && (
{nodeVars.visible && (
<>
<div className={classes.HeadRow}>
<div className={clsx(classes.classTitle, classTitleColor, '[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)]')}>
{classTitle ?? '-'}
<div
className={clsx(
classes.classTitle,
nodeVars.classTitleColor,
'[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)]',
)}
>
{nodeVars.classTitle ?? '-'}
</div>
{tag != null && tag !== '' && <div className={clsx(classes.TagTitle)}>{tag}</div>}
{nodeVars.tag != null && nodeVars.tag !== '' && (
<div className={clsx(classes.TagTitle)}>{nodeVars.tag}</div>
)}
<div
className={clsx(
@@ -100,63 +82,65 @@ export const SolarSystemNodeTheme = memo(props => {
'[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)] flex-grow overflow-hidden text-ellipsis whitespace-nowrap',
)}
>
{systemName}
{nodeVars.systemName}
</div>
{isWormhole && (
{nodeVars.isWormhole && (
<div className={classes.statics}>
{sortedStatics.map(whClass => (
{nodeVars.sortedStatics.map(whClass => (
<WormholeClassComp key={whClass} id={whClass} />
))}
</div>
)}
{effectName !== null && isWormhole && (
<div className={clsx(classes.effect, EFFECT_BACKGROUND_STYLES[effectName])} />
{nodeVars.effectName !== null && nodeVars.isWormhole && (
<div className={clsx(classes.effect, EFFECT_BACKGROUND_STYLES[nodeVars.effectName])} />
)}
</div>
<div className={clsx(classes.BottomRow, 'flex items-center justify-between')}>
{customName && (
{nodeVars.customName && (
<div
className={clsx(
classes.CustomName,
'[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)] whitespace-nowrap overflow-hidden text-ellipsis mr-0.5',
)}
>
{customName}
{nodeVars.customName}
</div>
)}
{!isWormhole && !customName && (
{!nodeVars.isWormhole && !nodeVars.customName && (
<div
className={clsx(
classes.RegionName,
'[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)] whitespace-nowrap overflow-hidden text-ellipsis mr-0.5',
)}
>
{regionName}
{nodeVars.regionName}
</div>
)}
{isWormhole && !customName && <div />}
{nodeVars.isWormhole && !nodeVars.customName && <div />}
<div className="flex items-center justify-end">
<div className="flex gap-1 items-center">
{locked && <i className={PrimeIcons.LOCK} style={{ fontSize: '0.45rem', fontWeight: 'bold' }} />}
{nodeVars.locked && (
<i className={PrimeIcons.LOCK} style={{ fontSize: '0.45rem', fontWeight: 'bold' }} />
)}
{hubs.includes(solarSystemId.toString()) && (
{nodeVars.hubs.includes(nodeVars.solarSystemId.toString()) && (
<i className={PrimeIcons.MAP_MARKER} style={{ fontSize: '0.45rem', fontWeight: 'bold' }} />
)}
{charactersInSystem.length > 0 && (
{nodeVars.charactersInSystem.length > 0 && (
<div
className={clsx(classes.localCounter, {
[classes.hasUserCharacters]: hasUserCharacters,
[classes.hasUserCharacters]: nodeVars.hasUserCharacters,
})}
>
<i className="pi pi-users" style={{ fontSize: '0.50rem' }} />
<span className="font-sans">{charactersInSystem.length}</span>
<span className="font-sans">{nodeVars.charactersInSystem.length}</span>
</div>
)}
</div>
@@ -166,19 +150,19 @@ export const SolarSystemNodeTheme = memo(props => {
)}
</div>
{visible && (
{nodeVars.visible && (
<>
{unsplashedLeft.length > 0 && (
{nodeVars.unsplashedLeft.length > 0 && (
<div className={classes.Unsplashed}>
{unsplashedLeft.map(sig => (
{nodeVars.unsplashedLeft.map(sig => (
<UnsplashedSignature key={sig.sig_id} signature={sig} />
))}
</div>
)}
{unsplashedRight.length > 0 && (
{nodeVars.unsplashedRight.length > 0 && (
<div className={clsx(classes.Unsplashed, classes['Unsplashed--right'])}>
{unsplashedRight.map(sig => (
{nodeVars.unsplashedRight.map(sig => (
<UnsplashedSignature key={sig.sig_id} signature={sig} />
))}
</div>
@@ -186,44 +170,44 @@ export const SolarSystemNodeTheme = memo(props => {
</>
)}
<div onMouseDownCapture={handleDbClick} className={classes.Handlers}>
<div onMouseDownCapture={nodeVars.dbClick} className={classes.Handlers}>
<Handle
type="source"
className={clsx(classes.Handle, classes.HandleTop, {
[classes.selected]: selected,
[classes.Tick]: isThickConnections,
[classes.selected]: nodeVars.selected,
[classes.Tick]: nodeVars.isThickConnections,
})}
style={{ visibility: showHandlers ? 'visible' : 'hidden' }}
style={{ visibility: nodeVars.showHandlers ? 'visible' : 'hidden' }}
position={Position.Top}
id="a"
/>
<Handle
type="source"
className={clsx(classes.Handle, classes.HandleRight, {
[classes.selected]: selected,
[classes.Tick]: isThickConnections,
[classes.selected]: nodeVars.selected,
[classes.Tick]: nodeVars.isThickConnections,
})}
style={{ visibility: showHandlers ? 'visible' : 'hidden' }}
style={{ visibility: nodeVars.showHandlers ? 'visible' : 'hidden' }}
position={Position.Right}
id="b"
/>
<Handle
type="source"
className={clsx(classes.Handle, classes.HandleBottom, {
[classes.selected]: selected,
[classes.Tick]: isThickConnections,
[classes.selected]: nodeVars.selected,
[classes.Tick]: nodeVars.isThickConnections,
})}
style={{ visibility: showHandlers ? 'visible' : 'hidden' }}
style={{ visibility: nodeVars.showHandlers ? 'visible' : 'hidden' }}
position={Position.Bottom}
id="c"
/>
<Handle
type="source"
className={clsx(classes.Handle, classes.HandleLeft, {
[classes.selected]: selected,
[classes.Tick]: isThickConnections,
[classes.selected]: nodeVars.selected,
[classes.Tick]: nodeVars.isThickConnections,
})}
style={{ visibility: showHandlers ? 'visible' : 'hidden' }}
style={{ visibility: nodeVars.showHandlers ? 'visible' : 'hidden' }}
position={Position.Left}
id="d"
/>

View File

@@ -0,0 +1,32 @@
import { SolarSystemNodeDefault, SolarSystemNodeTheme } from '../components/SolarSystemNode';
import type { NodeProps } from 'reactflow';
import type { ComponentType } from 'react';
import { MapSolarSystemType } from '../map.types';
import { ConnectionMode } from 'reactflow';
export type SolarSystemNodeComponent = ComponentType<NodeProps<MapSolarSystemType>>;
interface ThemeBehavior {
isPanAndDrag: boolean;
nodeComponent: SolarSystemNodeComponent;
connectionMode: ConnectionMode;
}
const THEME_BEHAVIORS: {
[key: string]: ThemeBehavior;
} = {
default: {
isPanAndDrag: false,
nodeComponent: SolarSystemNodeDefault,
connectionMode: ConnectionMode.Loose,
},
pathfinder: {
isPanAndDrag: true,
nodeComponent: SolarSystemNodeTheme,
connectionMode: ConnectionMode.Loose,
},
};
export function getBehaviorForTheme(themeName: string) {
return THEME_BEHAVIORS[themeName] ?? THEME_BEHAVIORS.default;
}

View File

@@ -1,5 +1,6 @@
import { useMemo } from 'react';
import { MapSolarSystemType } from '../map.types';
import { NodeProps } from 'reactflow';
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { useMapGetOption } from '@/hooks/Mapper/mapRootProvider/hooks/api';
import { useMapState } from '@/hooks/Mapper/components/map/MapProvider';
@@ -30,19 +31,9 @@ function sortedLabels(labels: string[]) {
return LABELS_ORDER.filter(x => labels.includes(x)).map(x => LABELS_INFO[x]);
}
export function useSolarSystemNode(props: any) {
const { data, selected, id } = props;
const {
system_static_info,
system_signatures,
locked,
name,
tag,
status,
labels,
temporary_name,
linked_sig_eve_id: linkedSigEveId = '',
} = data;
export function useSolarSystemNode(props: NodeProps<MapSolarSystemType>) {
const { id, data, selected } = props;
const { system_static_info, system_signatures, locked, name, tag, status, labels, temporary_name } = data;
const {
system_class,
@@ -57,7 +48,6 @@ export function useSolarSystemNode(props: any) {
solar_system_name,
} = system_static_info;
// Global map state
const {
interfaceSettings,
data: { systemSignatures: mapSystemSignatures },
@@ -81,11 +71,11 @@ export function useSolarSystemNode(props: any) {
visibleNodes,
showKSpaceBG,
isThickConnections,
linkedSigEveId,
},
outCommand,
} = useMapState();
// logic
const visible = useMemo(() => visibleNodes.has(id), [id, visibleNodes]);
const systemSignatures = useMemo(
@@ -174,10 +164,9 @@ export function useSolarSystemNode(props: any) {
}, [isShowUnsplashedSignatures, systemSignatures]);
const nodeVars = {
// original props
id,
selected,
// computed
visible,
isWormhole,
classTitleColor,

View File

@@ -1,11 +0,0 @@
// wrapNode.ts
import { NodeProps } from 'reactflow';
import { SolarSystemNodeProps } from '../components/SolarSystemNode';
export function wrapNode<T>(
SolarSystemNode: React.FC<SolarSystemNodeProps<T>>
): React.FC<NodeProps<T>> {
return function NodeAdapter(props) {
return <SolarSystemNode {...props} />;
};
}