fix(Map): Add Rally point. Change placement of settings in Map User Settings. Add ability to placement minimap.

This commit is contained in:
DanSylvest
2025-05-25 18:56:57 +03:00
parent 5719469452
commit a8dcdcf339
42 changed files with 578 additions and 206 deletions

View File

@@ -17,5 +17,6 @@ module.exports = {
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
'react/react-in-jsx-scope': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
"linebreak-style": "off",
},
};

View File

@@ -7,5 +7,5 @@
"semi": true,
"tabWidth": 2,
"useTabs": false,
"endOfLine": "lf"
"endOfLine": "auto"
}

View File

@@ -19,6 +19,8 @@ import { MapAddIcon, MapDeleteIcon } from '@/hooks/Mapper/icons';
import { PingType } from '@/hooks/Mapper/types';
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import clsx from 'clsx';
import { MenuItem } from 'primereact/menuitem';
import { MenuItemWithInfo, WdMenuItem } from '@/hooks/Mapper/components/ui-kit';
export const useContextMenuSystemItems = ({
onDeleteSystem,
@@ -46,12 +48,23 @@ export const useContextMenuSystemItems = ({
const getUserRoutes = useUserRoute({ userHubs, systemId, onUserHubToggle });
const {
data: { pings },
data: { pings, isSubscriptionActive },
} = useMapRootState();
const ping = useMemo(() => (pings.length === 1 ? pings[0] : undefined), [pings]);
const isShowPingBtn = useMemo(() => {
if (!isSubscriptionActive) {
return false;
}
return useMemo(() => {
if (pings.length === 0) {
return true;
}
return pings[0].solar_system_id === systemId;
}, [isSubscriptionActive, pings, systemId]);
return useMemo((): MenuItem[] => {
const system = systemId ? getSystemById(systems, systemId) : undefined;
const systemStaticInfo = getSystemStaticInfo(systemId)!;
@@ -95,12 +108,29 @@ export const useContextMenuSystemItems = ({
{ separator: true },
{
label: !hasPing ? 'Ping: RALLY' : 'Cancel: RALLY',
icon: clsx({
command: () => onTogglePing(PingType.Rally, systemId, hasPing),
disabled: !isShowPingBtn,
template: () => {
const iconClasses = clsx({
'pi text-cyan-400 hero-signal': !hasPing,
'pi text-red-400 hero-signal-slash': hasPing,
}),
command: () => onTogglePing(PingType.Rally, systemId, hasPing),
});
if (isShowPingBtn) {
return <WdMenuItem icon={iconClasses}>{!hasPing ? 'Ping: RALLY' : 'Cancel: RALLY'}</WdMenuItem>;
}
return (
<MenuItemWithInfo
infoTitle="Locked. Ping can be set only for one system."
infoClass="pi-lock text-stone-500 mr-[12px]"
>
<WdMenuItem disabled icon={iconClasses}>
{!hasPing ? 'Ping: RALLY' : 'Cancel: RALLY'}
</WdMenuItem>
</MenuItemWithInfo>
);
},
},
...(canLockSystem
? [
@@ -116,9 +146,24 @@ export const useContextMenuSystemItems = ({
? [
{ separator: true },
{
label: 'Delete',
icon: `text-red-400 ${PrimeIcons.TRASH}`,
command: onDeleteSystem,
disabled: hasPing,
template: () => {
if (!hasPing) {
return <WdMenuItem icon="text-red-400 pi pi-trash">Delete</WdMenuItem>;
}
return (
<MenuItemWithInfo
infoTitle="Locked. System can not be deleted until ping set."
infoClass="pi-lock text-stone-500 mr-[12px]"
>
<WdMenuItem disabled icon="text-red-400 pi pi-trash">
Delete
</WdMenuItem>
</MenuItemWithInfo>
);
},
},
]
: []),
@@ -133,8 +178,6 @@ export const useContextMenuSystemItems = ({
getUserRoutes,
hubs,
onHubToggle,
userHubs,
onUserHubToggle,
canLockSystem,
onLockToggle,
canDeleteSystem,
@@ -142,5 +185,6 @@ export const useContextMenuSystemItems = ({
onOpenSettings,
onTogglePing,
ping,
isShowPingBtn,
]);
};

View File

@@ -1,5 +1,5 @@
import { useCallback, useRef } from 'react';
import { LayoutEventBlocker, WdImageSize, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
import { LayoutEventBlocker, TooltipPosition, WdImageSize, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
import { ANOIK_ICON, DOTLAN_ICON, ZKB_ICON } from '@/hooks/Mapper/icons';
import classes from './FastSystemActions.module.scss';
@@ -59,9 +59,21 @@ export const FastSystemActions = ({
return (
<LayoutEventBlocker className={clsx('flex px-2 gap-2 justify-between items-center h-full')}>
<div className={clsx('flex gap-2 items-center h-full', classes.Links)}>
<WdImgButton tooltip={{ content: 'Open zkillboard' }} source={ZKB_ICON} onClick={handleOpenZKB} />
<WdImgButton tooltip={{ content: 'Open Anoikis' }} source={ANOIK_ICON} onClick={handleOpenAnoikis} />
<WdImgButton tooltip={{ content: 'Open Dotlan' }} source={DOTLAN_ICON} onClick={handleOpenDotlan} />
<WdImgButton
tooltip={{ position: TooltipPosition.top, content: 'Open zkillboard' }}
source={ZKB_ICON}
onClick={handleOpenZKB}
/>
<WdImgButton
tooltip={{ position: TooltipPosition.top, content: 'Open Anoikis' }}
source={ANOIK_ICON}
onClick={handleOpenAnoikis}
/>
<WdImgButton
tooltip={{ position: TooltipPosition.top, content: 'Open Dotlan' }}
source={DOTLAN_ICON}
onClick={handleOpenDotlan}
/>
</div>
<div className="flex gap-2 items-center pl-1">
@@ -69,14 +81,14 @@ export const FastSystemActions = ({
textSize={WdImageSize.off}
className={PrimeIcons.COPY}
onClick={copySystemNameToClipboard}
tooltip={{ content: 'Copy system name' }}
tooltip={{ position: TooltipPosition.top, content: 'Copy system name' }}
/>
{showEdit && (
<WdImgButton
textSize={WdImageSize.off}
className="pi pi-pen-to-square text-base"
onClick={onOpenSettings}
tooltip={{ content: 'Edit system name and description' }}
tooltip={{ position: TooltipPosition.top, content: 'Edit system name and description' }}
/>
)}
</div>

View File

@@ -33,6 +33,7 @@ import { ctxManager } from '@/hooks/Mapper/utils/contextManager.ts';
import { NodeSelectionMouseHandler } from '@/hooks/Mapper/components/contexts/types.ts';
import clsx from 'clsx';
import { useBackgroundVars } from './hooks/useBackgroundVars';
import type { PanelPosition } from '@reactflow/core';
const DEFAULT_VIEW_PORT = { zoom: 1, x: 0, y: 0 };
@@ -96,6 +97,7 @@ interface MapCompProps {
isSoftBackground?: boolean;
theme?: string;
pings: PingData[];
minimapPlacement?: PanelPosition;
}
const MapComp = ({
@@ -114,6 +116,7 @@ const MapComp = ({
theme,
onAddSystem,
pings,
minimapPlacement = 'bottom-right',
}: MapCompProps) => {
const { getNodes } = useReactFlow();
const [nodes, , onNodesChange] = useNodesState<Node<SolarSystemRawType>>(initialNodes);
@@ -273,7 +276,9 @@ const MapComp = ({
// onlyRenderVisibleElements
selectionMode={SelectionMode.Partial}
>
{isShowMinimap && <MiniMap pannable zoomable ariaLabel="Mini map" className={minimapClasses} />}
{isShowMinimap && (
<MiniMap pannable zoomable ariaLabel="Mini map" className={minimapClasses} position={minimapPlacement} />
)}
{isShowBackgroundPattern && <Background variant={variant} gap={gap} size={size} color={color} />}
</ReactFlow>
{/* <button className="z-auto btn btn-primary absolute top-20 right-20" onClick={handleGetPassages}>

View File

@@ -71,7 +71,10 @@ export const SolarSystemNodeTheme = memo((props: NodeProps<MapSolarSystemType>)
classes.RootCustomNode,
nodeVars.regionClass && classes[nodeVars.regionClass],
nodeVars.status !== undefined ? classes[STATUS_CLASSES[nodeVars.status]] : '',
{ [classes.selected]: nodeVars.selected },
{
[classes.selected]: nodeVars.selected,
[classes.rally]: nodeVars.isRally,
},
)}
onMouseDownCapture={e => nodeVars.dbClick(e)}
>

View File

@@ -115,35 +115,18 @@ export const useMapHandlers = (ref: ForwardedRef<MapHandlers>, onSelectionChange
}, 500);
break;
case Commands.pingAdded:
case Commands.pingCancelled:
case Commands.routes:
// do nothing here
break;
case Commands.signaturesUpdated:
// do nothing here
break;
case Commands.linkSignatureToSystem:
// do nothing here
break;
case Commands.detailedKillsUpdated:
// do nothing here
break;
case Commands.characterActivityData:
break;
case Commands.trackingCharactersData:
break;
case Commands.updateActivity:
break;
case Commands.updateTracking:
break;
case Commands.userSettingsUpdated:
// do nothing
break;
default:

View File

@@ -1,9 +1,12 @@
import classes from './MarkdownComment.module.scss';
import clsx from 'clsx';
import Markdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import { InfoDrawer, TimeAgo, TooltipPosition, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
import remarkBreaks from 'remark-breaks';
import {
InfoDrawer,
MarkdownTextViewer,
TimeAgo,
TooltipPosition,
WdImgButton,
} from '@/hooks/Mapper/components/ui-kit';
import { useGetCacheCharacter } from '@/hooks/Mapper/mapRootProvider/hooks/api';
import { useCallback, useRef, useState } from 'react';
import { WdTransition } from '@/hooks/Mapper/components/ui-kit/WdTransition/WdTransition.tsx';
@@ -13,7 +16,6 @@ import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { OutCommand } from '@/hooks/Mapper/types';
const TOOLTIP_PROPS = { content: 'Remove comment', position: TooltipPosition.top };
const REMARK_PLUGINS = [remarkGfm, remarkBreaks];
export interface MarkdownCommentProps {
text: string;
@@ -79,7 +81,7 @@ export const MarkdownComment = ({ text, time, characterEveId, id }: MarkdownComm
</div>
}
>
<Markdown remarkPlugins={REMARK_PLUGINS}>{text}</Markdown>
<MarkdownTextViewer>{text}</MarkdownTextViewer>
</InfoDrawer>
<ConfirmPopup

View File

@@ -9,6 +9,7 @@ import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
export interface CommentsEditorProps {}
// eslint-disable-next-line no-empty-pattern
export const CommentsEditor = ({}: CommentsEditorProps) => {
const [textVal, setTextVal] = useState('');

View File

@@ -0,0 +1,49 @@
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { useMemo } from 'react';
import { RoutesList } from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/RoutesList';
export const PingRoute = () => {
const {
data: { routes, pings, loadingPublicRoutes },
} = useMapRootState();
const route = useMemo(() => {
const [ping] = pings;
if (!ping) {
return null;
}
return routes?.routes.find(x => ping.solar_system_id === x.destination.toString()) ?? null;
}, [routes, pings]);
const preparedRoute = useMemo(() => {
if (!route) {
return null;
}
return {
...route,
mapped_systems:
route.systems?.map(solar_system_id =>
routes?.systems_static_data.find(
system_static_data => system_static_data.solar_system_id === solar_system_id,
),
) ?? [],
};
}, [route, routes?.systems_static_data]);
if (loadingPublicRoutes) {
return <span className="m-0 text-[12px]">Loading...</span>;
}
if (!preparedRoute || preparedRoute.origin === preparedRoute.destination) {
return null;
}
return (
<div className="m-0 flex gap-2 items-center text-[12px]">
{preparedRoute.has_connection && <div className="text-[12px]">{preparedRoute.systems?.length ?? 2}</div>}
<RoutesList data={preparedRoute} />
</div>
);
};

View File

@@ -1,9 +1,9 @@
import { Button } from 'primereact/button';
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Toast } from 'primereact/toast';
import clsx from 'clsx';
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { Commands, PingType } from '@/hooks/Mapper/types';
import { Commands, OutCommand, PingType } from '@/hooks/Mapper/types';
import {
CharacterCardById,
SystemView,
@@ -15,16 +15,39 @@ import {
import useRefState from 'react-usestateref';
import { PrimeIcons } from 'primereact/api';
import { emitMapEvent } from '@/hooks/Mapper/events';
import { ConfirmPopup } from 'primereact/confirmpopup';
import { PingRoute } from '@/hooks/Mapper/components/mapInterface/components/PingsInterface/PingRoute.tsx';
import { PingsPlacement } from '@/hooks/Mapper/mapRootProvider/types.ts';
const PING_PLACEMENT_MAP = {
[PingsPlacement.rightTop]: 'top-right',
[PingsPlacement.leftTop]: 'top-left',
[PingsPlacement.rightBottom]: 'bottom-right',
[PingsPlacement.leftBottom]: 'bottom-left',
};
const PING_PLACEMENT_MAP_OFFSETS = {
[PingsPlacement.rightTop]: { default: '!top-[56px]', withLeftMenu: '!top-[56px] !right-[64px]' },
[PingsPlacement.rightBottom]: { default: '!bottom-[15px]', withLeftMenu: '!bottom-[15px] !right-[64px]' },
[PingsPlacement.leftTop]: { default: '!top-[56px] !left-[64px]', withLeftMenu: '!top-[56px] !left-[64px]' },
[PingsPlacement.leftBottom]: { default: '!left-[64px] !bottom-[15px]', withLeftMenu: '!bottom-[15px]' },
};
const CLOSE_TOOLTIP_PROPS: WdImgButtonTooltip = {
content: 'Close',
content: 'Hide',
position: TooltipPosition.top,
className: '!leading-[0]',
};
const NAVIGATE_TOOLTIP_PROPS: WdImgButtonTooltip = {
content: 'Navigate To',
position: TooltipPosition.bottom,
position: TooltipPosition.top,
className: '!leading-[0]',
};
const DELETE_TOOLTIP_PROPS: WdImgButtonTooltip = {
content: 'Remove',
position: TooltipPosition.top,
className: '!leading-[0]',
};
@@ -56,12 +79,28 @@ export const PingsInterface = ({ hasLeftOffset }: PingsInterfaceProps) => {
const toast = useRef<Toast>(null);
const [isShow, setIsShow, isShowRef] = useRefState(false);
const cpRemoveBtnRef = useRef<HTMLElement>();
const [cpRemoveVisible, setCpRemoveVisible] = useState(false);
const {
data: { pings },
storedSettings: { interfaceSettings },
data: { pings, selectedSystems },
outCommand,
} = useMapRootState();
const selectedSystem = useMemo(() => {
if (selectedSystems.length !== 1) {
return null;
}
return selectedSystems[0];
}, [selectedSystems]);
const ping = useMemo(() => (pings.length === 1 ? pings[0] : null), [pings]);
const handleShowCP = useCallback(() => setCpRemoveVisible(true), []);
const handleHideCP = useCallback(() => setCpRemoveVisible(false), []);
const navigateTo = useCallback(() => {
if (!ping) {
return;
@@ -73,6 +112,17 @@ export const PingsInterface = ({ hasLeftOffset }: PingsInterfaceProps) => {
});
}, [ping]);
const removePing = useCallback(async () => {
if (!ping) {
return;
}
await outCommand({
type: OutCommand.cancelPing,
data: { type: ping.type, solar_system_id: ping.solar_system_id },
});
}, [outCommand, ping]);
useEffect(() => {
if (!ping) {
return;
@@ -105,16 +155,27 @@ export const PingsInterface = ({ hasLeftOffset }: PingsInterfaceProps) => {
setIsShow(false);
}, []);
const { placement, offsets } = useMemo(() => {
const rawPlacement =
interfaceSettings.pingsPlacement == null ? PingsPlacement.rightTop : interfaceSettings.pingsPlacement;
return {
placement: PING_PLACEMENT_MAP[rawPlacement],
offsets: PING_PLACEMENT_MAP_OFFSETS[rawPlacement],
};
}, [interfaceSettings]);
if (!ping) {
return null;
}
const isShowSelectedSystem = selectedSystem != null && selectedSystem !== ping.solar_system_id;
return (
<>
<Toast
className={clsx('!top-[56px]', {
['!right-[64px]']: hasLeftOffset,
})}
position={placement as never}
className={clsx('!max-w-[initial] w-[500px]', hasLeftOffset ? offsets.withLeftMenu : offsets.default)}
ref={toast}
content={({ message }) => (
<section
@@ -124,12 +185,35 @@ export const PingsInterface = ({ hasLeftOffset }: PingsInterfaceProps) => {
)}
>
<div className="flex gap-3">
<i className={clsx('pi text-violet-500 text-2xl', 'relative top-[2px]', ICONS[ping.type])}></i>
<i className={clsx('pi text-yellow-500 text-2xl', 'relative top-[2px]', ICONS[ping.type])}></i>
<div className="flex flex-col gap-1 w-full">
<div className="flex justify-between">
<div>
<div className="m-0 font-semibold text-base text-white">{TITLES[ping.type]}</div>
<div className="flex gap-1 items-center">
{isShowSelectedSystem && (
<>
<SystemView systemId={selectedSystem} />
<span className="pi pi-angle-double-right text-[10px] relative top-[1px] text-stone-400" />
</>
)}
<SystemView systemId={ping.solar_system_id} />
{isShowSelectedSystem && (
<WdImgButton
className={clsx(PrimeIcons.QUESTION_CIRCLE, 'ml-[2px] relative top-[-2px] !text-[10px]')}
tooltip={{
position: TooltipPosition.top,
content: (
<div className="flex flex-col gap-1">
The settings for the route are taken from the Routes settings and can be configured
through them.
</div>
),
}}
/>
)}
</div>
</div>
<div className="flex flex-col items-end">
<CharacterCardById className="" characterId={ping.character_eve_id} simpleMode />
@@ -137,6 +221,8 @@ export const PingsInterface = ({ hasLeftOffset }: PingsInterfaceProps) => {
</div>
</div>
{selectedSystem != null && <PingRoute />}
<p className="m-0 text-[13px] text-stone-200 min-h-[20px] pr-[16px]">{message.detail}</p>
</div>
@@ -148,13 +234,21 @@ export const PingsInterface = ({ hasLeftOffset }: PingsInterfaceProps) => {
</div>
{/*Button bar*/}
<div className="flex justify-end gap-2 h-0 relative top-[-16px]">
<div className="flex justify-end items-center gap-2 h-0 relative top-[-8px]">
<WdImgButton
className={clsx('pi-compass', 'hover:text-red-400 mt-[3px]')}
tooltip={NAVIGATE_TOOLTIP_PROPS}
onClick={navigateTo}
/>
{/*@ts-ignore*/}
<div ref={cpRemoveBtnRef}>
<WdImgButton
className={clsx('pi-trash', 'text-red-400 hover:text-red-300')}
tooltip={DELETE_TOOLTIP_PROPS}
onClick={handleShowCP}
/>
</div>
{/* TODO ADD solar system menu*/}
{/*<WdImgButton*/}
{/* className={clsx('pi-map-marker', 'hover:text-red-400 mt-[3px]')}*/}
@@ -176,6 +270,15 @@ export const PingsInterface = ({ hasLeftOffset }: PingsInterfaceProps) => {
onClick={handleClickShow}
disabled={isShow}
/>
<ConfirmPopup
target={cpRemoveBtnRef.current}
visible={cpRemoveVisible}
onHide={handleHideCP}
message="Are you sure you want to delete ping?"
icon="pi pi-exclamation-triangle text-orange-400"
accept={removePing}
/>
</>
);
};

View File

@@ -0,0 +1 @@
export * from './PingsInterface.tsx';

View File

@@ -2,3 +2,4 @@ export * from './Widget';
export * from './SystemSettingsDialog';
export * from './SystemCustomLabelDialog';
export * from './SystemLinkSignatureDialog';
export * from './PingsInterface';

View File

@@ -1,4 +1,4 @@
import React, { createContext, forwardRef, useContext, useImperativeHandle, useState } from 'react';
import React, { createContext, forwardRef, useContext } from 'react';
import {
RoutesImperativeHandle,
RoutesProviderInnerProps,
@@ -15,17 +15,14 @@ const RoutesContext = createContext<RoutesProviderInnerProps>({
data: {},
});
export const RoutesProvider = forwardRef<RoutesImperativeHandle, MapProviderProps>(({ children, ...props }, ref) => {
const [loading, setLoading] = useState(false);
// INFO: this component have imperative handler but now it not using.
export const RoutesProvider = forwardRef<RoutesImperativeHandle, MapProviderProps>(
({ children, ...props } /*, ref*/) => {
// useImperativeHandle(ref, () => ({}));
useImperativeHandle(ref, () => ({
stopLoading() {
setLoading(false);
return <RoutesContext.Provider value={{ ...props /*, loading, setLoading*/ }}>{children}</RoutesContext.Provider>;
},
}));
return <RoutesContext.Provider value={{ ...props, loading, setLoading }}>{children}</RoutesContext.Provider>;
});
);
RoutesProvider.displayName = 'RoutesProvider';
export const useRouteProvider = () => {

View File

@@ -3,16 +3,15 @@ import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import {
LayoutEventBlocker,
LoadingWrapper,
SystemViewStandalone,
SystemView,
TooltipPosition,
WdCheckbox,
WdImgButton,
} from '@/hooks/Mapper/components/ui-kit';
import { useLoadSystemStatic } from '@/hooks/Mapper/mapRootProvider/hooks/useLoadSystemStatic.ts';
import { forwardRef, MouseEvent, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { getSystemById } from '@/hooks/Mapper/helpers/getSystemById.ts';
import classes from './RoutesWidget.module.scss';
import { useLoadRoutes } from './hooks';
import { RoutesList } from './RoutesList';
import clsx from 'clsx';
import { Route } from '@/hooks/Mapper/types/routes.ts';
@@ -42,24 +41,13 @@ export const RoutesWidgetContent = () => {
const {
data: { selectedSystems, systems, isSubscriptionActive },
} = useMapRootState();
const { hubs = [], routesList, isRestricted } = useRouteProvider();
const { hubs = [], routesList, isRestricted, loading } = useRouteProvider();
const [systemId] = selectedSystems;
const { loading } = useLoadRoutes();
const { systems: systemStatics, loadSystems, lastUpdateKey } = useLoadSystemStatic({ systems: hubs ?? [] });
const { systems: systemStatics, loadSystems } = useLoadSystemStatic({ systems: hubs ?? [] });
const { open, ...systemCtxProps } = useContextMenuSystemInfoHandlers();
const preparedHubs = useMemo(() => {
return hubs.map(x => {
const sys = getSystemById(systems, x.toString());
return { ...systemStatics.get(parseInt(x))!, ...(sys && { customName: sys.name ?? '' }) };
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hubs, systems, systemStatics, lastUpdateKey]);
const preparedRoutes: Route[] = useMemo(() => {
return (
routesList?.routes
@@ -125,9 +113,7 @@ export const RoutesWidgetContent = () => {
<LoadingWrapper loading={loading}>
<div className={clsx(classes.RoutesGrid, 'px-2 py-2')}>
{preparedRoutes.map(route => {
const sys = preparedHubs.find(x => x.solar_system_id === route.destination)!;
// TODO do not delte this console log
// TODO do not delete this console log
// eslint-disable-next-line no-console
// console.log('JOipP', `Check sys [${route.destination}]:`, sys);
@@ -144,12 +130,12 @@ export const RoutesWidgetContent = () => {
}}
/>
<SystemViewStandalone
key={route.destination}
<SystemView
systemId={route.destination.toString()}
className={clsx('select-none text-center cursor-context-menu')}
hideRegion
compact
{...sys}
showCustomName
/>
</div>
<div className="text-right pl-1">{route.has_connection ? route.systems?.length ?? 2 : ''}</div>

View File

@@ -1,7 +1,8 @@
import { useCallback, useEffect, useRef } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { useRouteProvider } from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/RoutesProvider.tsx';
import { RoutesType } from '@/hooks/Mapper/mapRootProvider/types.ts';
import { LoadRoutesCommand } from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/types.ts';
import { RoutesList } from '@/hooks/Mapper/types/routes.ts';
function usePrevious<T>(value: T): T | undefined {
const ref = useRef<T>();
@@ -13,8 +14,22 @@ function usePrevious<T>(value: T): T | undefined {
return ref.current;
}
export const useLoadRoutes = () => {
const { data: routesSettings, loadRoutesCommand, hubs, routesList, loading, setLoading } = useRouteProvider();
type UseLoadRoutesProps = {
loadRoutesCommand: LoadRoutesCommand;
hubs: string[];
routesList: RoutesList | undefined;
data: RoutesType;
deps?: unknown[];
};
export const useLoadRoutes = ({
data: routesSettings,
loadRoutesCommand,
hubs,
routesList,
deps = [],
}: UseLoadRoutesProps) => {
const [loading, setLoading] = useState(false);
const {
data: { selectedSystems, systems, connections },
@@ -55,7 +70,8 @@ export const useLoadRoutes = () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
.map(x => routesSettings[x]),
...deps,
]);
return { loading, loadRoutes };
return { loading, loadRoutes, setLoading };
};

View File

@@ -10,17 +10,14 @@ export type RoutesWidgetProps = {
update: (d: RoutesType) => void;
hubs: string[];
routesList: RoutesList | undefined;
loading: boolean;
loadRoutesCommand: LoadRoutesCommand;
addHubCommand: AddHubCommand;
toggleHubCommand: ToggleHubCommand;
isRestricted?: boolean;
};
export type RoutesProviderInnerProps = RoutesWidgetProps & {
loading: boolean;
setLoading(loading: boolean): void;
};
export type RoutesProviderInnerProps = RoutesWidgetProps;
export type RoutesImperativeHandle = {
stopLoading: () => void;

View File

@@ -2,7 +2,6 @@ import { Commands, OutCommand } from '@/hooks/Mapper/types';
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import {
AddHubCommand,
LoadRoutesCommand,
RoutesImperativeHandle,
} from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/types.ts';
import { useCallback, useRef } from 'react';
@@ -13,24 +12,11 @@ export const WRoutesPublic = () => {
const {
outCommand,
storedSettings: { settingsRoutes, settingsRoutesUpdate },
data: { hubs, routes },
data: { hubs, routes, loadingPublicRoutes },
} = useMapRootState();
const ref = useRef<RoutesImperativeHandle>(null);
const loadRoutesCommand: LoadRoutesCommand = useCallback(
async (systemId, routesSettings) => {
outCommand({
type: OutCommand.getRoutes,
data: {
system_id: systemId,
routes_settings: routesSettings,
},
});
},
[outCommand],
);
const addHubCommand: AddHubCommand = useCallback(
async systemId => {
if (hubs.includes(systemId)) {
@@ -72,10 +58,10 @@ export const WRoutesPublic = () => {
ref={ref}
title="Routes"
data={settingsRoutes}
loading={loadingPublicRoutes}
update={settingsRoutesUpdate}
hubs={hubs}
routesList={routes}
loadRoutesCommand={loadRoutesCommand}
addHubCommand={addHubCommand}
toggleHubCommand={toggleHubCommand}
/>

View File

@@ -8,6 +8,7 @@ import {
import { useCallback, useRef } from 'react';
import { RoutesWidget } from '@/hooks/Mapper/components/mapInterface/widgets';
import { useMapEventListener } from '@/hooks/Mapper/events';
import { useLoadRoutes } from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/hooks';
export const WRoutesUser = () => {
const {
@@ -61,9 +62,17 @@ export const WRoutesUser = () => {
[userHubs, outCommand],
);
// INFO: User routes loading only if open widget with user routes
const { loading, setLoading } = useLoadRoutes({
data: settingsRoutes,
hubs: userHubs,
loadRoutesCommand,
routesList: userRoutes,
});
useMapEventListener(event => {
if (event.name === Commands.userRoutes) {
ref.current?.stopLoading();
setLoading(false);
}
return true;
});
@@ -76,7 +85,7 @@ export const WRoutesUser = () => {
update={settingsRoutesUpdate}
hubs={userHubs}
routesList={userRoutes}
loadRoutesCommand={loadRoutesCommand}
loading={loading}
addHubCommand={addHubCommand}
toggleHubCommand={toggleHubCommand}
isRestricted

View File

@@ -13,7 +13,7 @@ import { useCharacterActivityHandlers } from './hooks/useCharacterActivityHandle
import { TrackingDialog } from '@/hooks/Mapper/components/mapRootContent/components/TrackingDialog';
import { useMapEventListener } from '@/hooks/Mapper/events';
import { Commands } from '@/hooks/Mapper/types';
import { PingsInterface } from '@/hooks/Mapper/components/mapInterface/components/PingsInterface/PingsInterface.tsx';
import { PingsInterface } from '@/hooks/Mapper/components/mapInterface/components';
export interface MapRootContentProps {}

View File

@@ -4,13 +4,7 @@ import { useCallback, useRef, useState } from 'react';
import { TabPanel, TabView } from 'primereact/tabview';
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { OutCommand } from '@/hooks/Mapper/types';
import {
CONNECTIONS_CHECKBOXES_PROPS,
SIGNATURES_CHECKBOXES_PROPS,
SYSTEMS_CHECKBOXES_PROPS,
THEME_SETTING,
UI_CHECKBOXES_PROPS,
} from './constants.ts';
import { CONNECTIONS_CHECKBOXES_PROPS, SIGNATURES_CHECKBOXES_PROPS, SYSTEMS_CHECKBOXES_PROPS } from './constants.ts';
import {
MapSettingsProvider,
useMapSettings,
@@ -34,6 +28,8 @@ export const MapSettingsComp = ({ visible, onHide }: MapSettingsProps) => {
refVars.current = { outCommand, onHide, visible };
const handleShow = useCallback(async () => {
// TODO: need fix it - add type?
// @ts-ignore
const { user_settings } = await refVars.current.outCommand({
type: OutCommand.getUserSettings,
data: null,
@@ -88,17 +84,9 @@ export const MapSettingsComp = ({ visible, onHide }: MapSettingsProps) => {
{renderSettingsList(SIGNATURES_CHECKBOXES_PROPS)}
</TabPanel>
<TabPanel header="User Interface" headerClassName={styles.verticalTabHeader}>
{renderSettingsList(UI_CHECKBOXES_PROPS)}
</TabPanel>
<TabPanel header="Widgets" className="h-full" headerClassName={styles.verticalTabHeader}>
<WidgetsSettings />
</TabPanel>
<TabPanel header="Theme" headerClassName={styles.verticalTabHeader}>
{renderSettingItem(THEME_SETTING)}
</TabPanel>
</TabView>
</div>
</div>

View File

@@ -88,8 +88,9 @@ export const MapSettingsProvider = ({ children }: { children: ReactNode }) => {
if (item.type === 'dropdown' && item.options) {
return (
<div key={item.prop.toString()} className="flex items-center gap-2 mt-2">
<label className="text-sm">{item.label}:</label>
<div key={item.prop.toString()} className="grid grid-cols-[auto_1fr_auto] items-center">
<label className="text-[var(--gray-200)] text-[13px] select-none">{item.label}:</label>
<div className="border-b-2 border-dotted border-[#3f3f3f] h-px mx-3" />
<Dropdown
className="text-sm"
value={currentValue}

View File

@@ -1,13 +1,34 @@
import { COMMON_CHECKBOXES_PROPS } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/constants.ts';
import {
MINI_MAP_PLACEMENT,
PINGS_PLACEMENT,
THEME_SETTING,
UI_CHECKBOXES_PROPS,
} from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/constants.ts';
import { useMapSettings } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/MapSettingsProvider.tsx';
import { SettingsListItem } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings/types.ts';
import { useCallback } from 'react';
export const CommonSettings = () => {
const { renderSettingItem } = useMapSettings();
const renderSettingsList = (list: SettingsListItem[]) => {
const renderSettingsList = useCallback(
(list: SettingsListItem[]) => {
return list.map(renderSettingItem);
};
},
[renderSettingItem],
);
return <div className="w-full h-full flex flex-col gap-1">{renderSettingsList(COMMON_CHECKBOXES_PROPS)}</div>;
return (
<div className="flex flex-col h-full gap-1">
<div>
<div className="w-full h-full flex flex-col gap-1">{renderSettingsList(UI_CHECKBOXES_PROPS)}</div>
</div>
<div className="border-b-2 border-dotted border-stone-700/50 h-px my-3" />
<div className="grid grid-cols-[1fr_auto]">{renderSettingItem(MINI_MAP_PLACEMENT)}</div>
<div className="grid grid-cols-[1fr_auto]">{renderSettingItem(PINGS_PLACEMENT)}</div>
<div className="grid grid-cols-[1fr_auto]">{renderSettingItem(THEME_SETTING)}</div>
</div>
);
};

View File

@@ -10,9 +10,9 @@ interface PrettySwitchboxProps {
export const PrettySwitchbox = ({ checked, setChecked, label }: PrettySwitchboxProps) => {
return (
<label className={styles.CheckboxContainer}>
<span>{label}</span>
<div />
<label className="grid grid-cols-[auto_1fr_auto] items-center">
<span className="text-[var(--gray-200)] text-[13px] select-none">{label}</span>
<div className="border-b-2 border-dotted border-[#3f3f3f] h-px mx-3" />
<div className={styles.smallInputSwitch}>
<WdCheckbox size="m" label={''} value={checked} onChange={e => setChecked(e.checked ?? false)} />
</div>

View File

@@ -1,6 +1,6 @@
import { SettingsListItem, UserSettingsRemoteProps } from './types.ts';
import { InterfaceStoredSettingsProps } from '@/hooks/Mapper/mapRootProvider';
import { AvailableThemes } from '@/hooks/Mapper/mapRootProvider/types.ts';
import { AvailableThemes, MiniMapPlacement, PingsPlacement } from '@/hooks/Mapper/mapRootProvider/types.ts';
export const DEFAULT_REMOTE_SETTINGS = {
[UserSettingsRemoteProps.link_signature_on_splash]: false,
@@ -14,13 +14,13 @@ export const UserSettingsRemoteList = [
UserSettingsRemoteProps.delete_connection_with_sigs,
];
export const COMMON_CHECKBOXES_PROPS: SettingsListItem[] = [
{
prop: InterfaceStoredSettingsProps.isShowMinimap,
label: 'Show Minimap',
type: 'checkbox',
},
];
// export const COMMON_CHECKBOXES_PROPS: SettingsListItem[] = [
// // {
// // prop: InterfaceStoredSettingsProps.isShowMinimap,
// // label: 'Show Minimap',
// // type: 'checkbox',
// // },
// ];
export const SYSTEMS_CHECKBOXES_PROPS: SettingsListItem[] = [
{
@@ -90,3 +90,32 @@ export const THEME_SETTING: SettingsListItem = {
type: 'dropdown',
options: THEME_OPTIONS,
};
export const MINI_MAP_PLACEMENT_OPTIONS = [
{ label: 'Right Bottom', value: MiniMapPlacement.rightBottom },
{ label: 'Right Top', value: MiniMapPlacement.rightTop },
{ label: 'Left Top', value: MiniMapPlacement.leftTop },
{ label: 'Left Bottom', value: MiniMapPlacement.leftBottom },
{ label: 'Hide', value: MiniMapPlacement.hide },
];
export const MINI_MAP_PLACEMENT: SettingsListItem = {
prop: 'minimapPlacement',
label: 'Minimap Placement',
type: 'dropdown',
options: MINI_MAP_PLACEMENT_OPTIONS,
};
export const PINGS_PLACEMENT_OPTIONS = [
{ label: 'Right Top', value: PingsPlacement.rightTop },
{ label: 'Left Top', value: PingsPlacement.leftTop },
{ label: 'Left Bottom', value: PingsPlacement.leftBottom },
{ label: 'Right Bottom', value: PingsPlacement.rightBottom },
];
export const PINGS_PLACEMENT: SettingsListItem = {
prop: 'pingsPlacement',
label: 'Pings Placement',
type: 'dropdown',
options: PINGS_PLACEMENT_OPTIONS,
};

View File

@@ -1,4 +1,4 @@
import { InterfaceStoredSettings } from '@/hooks/Mapper/mapRootProvider';
import { InterfaceStoredSettings } from '@/hooks/Mapper/mapRootProvider/types.ts';
export enum UserSettingsRemoteProps {
link_signature_on_splash = 'link_signature_on_splash',

View File

@@ -27,15 +27,6 @@ export const RightBar = ({
const canTrackCharacters = useMapCheckPermissions([UserPermission.TRACK_CHARACTER]);
const isShowMinimap = interfaceSettings.isShowMinimap === undefined ? true : interfaceSettings.isShowMinimap;
const toggleMinimap = useCallback(() => {
setInterfaceSettings(x => ({
...x,
isShowMinimap: !x.isShowMinimap,
}));
}, [setInterfaceSettings]);
const toggleKSpace = useCallback(() => {
setInterfaceSettings(x => ({
...x,
@@ -113,16 +104,6 @@ export const RightBar = ({
</button>
</WdTooltipWrapper>
<WdTooltipWrapper content={isShowMinimap ? 'Hide minimap' : 'Show minimap'} position={TooltipPosition.left}>
<button
className="btn bg-transparent text-gray-400 hover:text-white border-transparent hover:bg-transparent py-2 h-auto min-h-auto"
type="button"
onClick={toggleMinimap}
>
<i className={isShowMinimap ? 'pi pi-eye' : 'pi pi-eye-slash'}></i>
</button>
</WdTooltipWrapper>
<WdTooltipWrapper content="Switch to menu" position={TooltipPosition.left}>
<button
className="btn bg-transparent text-gray-400 hover:text-white border-transparent hover:bg-transparent py-2 h-auto min-h-auto"

View File

@@ -1,5 +1,5 @@
import { Map, MAP_ROOT_ID } from '@/hooks/Mapper/components/map/Map.tsx';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { OutCommand, OutCommandHandler, SolarSystemConnection } from '@/hooks/Mapper/types';
import { MapRootData, useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { OnMapAddSystemCallback, OnMapSelectionChange } from '@/hooks/Mapper/components/map/map.types.ts';
@@ -10,7 +10,6 @@ import {
SystemLinkSignatureDialog,
SystemSettingsDialog,
} from '@/hooks/Mapper/components/mapInterface/components';
import classes from './MapWrapper.module.scss';
import { Connections } from '@/hooks/Mapper/components/mapRootContent/components/Connections';
import { ContextMenuSystemMultiple, useContextMenuSystemMultipleHandlers } from '../contexts/ContextMenuSystemMultiple';
import { getSystemById } from '@/hooks/Mapper/helpers';
@@ -27,9 +26,12 @@ import {
SearchOnSubmitCallback,
} from '@/hooks/Mapper/components/mapInterface/components/AddSystemDialog';
import { useHotkey } from '../../hooks/useHotkey';
import { STORED_INTERFACE_DEFAULT_VALUES } from '@/hooks/Mapper/mapRootProvider/constants.ts';
import { PingType } from '@/hooks/Mapper/types/ping.ts';
import { SystemPingDialog } from '@/hooks/Mapper/components/mapInterface/components/SystemPingDialog';
import { MiniMapPlacement } from '@/hooks/Mapper/mapRootProvider/types.ts';
import { MINIMAP_PLACEMENT_MAP } from '@/hooks/Mapper/constants.ts';
import type { PanelPosition } from '@reactflow/core';
import { MINI_MAP_PLACEMENT_OFFSETS } from './constants.ts';
// TODO: INFO - this component needs for abstract work with Map instance
export const MapWrapper = () => {
@@ -51,13 +53,13 @@ export const MapWrapper = () => {
const {
isShowMenu,
isShowMinimap = STORED_INTERFACE_DEFAULT_VALUES.isShowMinimap,
isShowKSpace,
isThickConnections,
isShowBackgroundPattern,
isShowUnsplashedSignatures,
isSoftBackground,
theme,
minimapPlacement,
} = interfaceSettings;
const { deleteSystems } = useDeleteSystems();
@@ -111,6 +113,8 @@ export const MapWrapper = () => {
event => {
switch (event.type) {
case OutCommand.openSettings:
// TODO - need fix it
// @ts-ignore
setOpenSettings(event.data.system_id);
break;
default:
@@ -143,11 +147,13 @@ export const MapWrapper = () => {
const handleDeleteSelected = useCallback(() => {
const restDel = getNodes()
.filter(x => x.selected && !x.data.locked)
.filter(x => !pings.some(p => x.data.id === p.solar_system_id))
.map(x => x.data.id);
if (restDel.length > 0) {
ref.current.deleteSystems(restDel);
}
}, [getNodes]);
}, [getNodes, pings]);
const onAddSystem: OnMapAddSystemCallback = useCallback(({ coordinates }) => {
setOpenAddSystem(coordinates);
@@ -213,6 +219,22 @@ export const MapWrapper = () => {
outCommand({ type: OutCommand.loadSignatures, data: {} });
}, [isShowUnsplashedSignatures, systems]);
const { showMinimap, minimapPosition, minimapClasses } = useMemo(() => {
const rawPlacement = minimapPlacement == null ? MiniMapPlacement.rightBottom : minimapPlacement;
if (rawPlacement === MiniMapPlacement.hide) {
return { minimapPosition: undefined, showMinimap: false, minimapClasses: '' };
}
const mmClasses = MINI_MAP_PLACEMENT_OFFSETS[rawPlacement];
return {
minimapPosition: MINIMAP_PLACEMENT_MAP[rawPlacement] as PanelPosition,
showMinimap: true,
minimapClasses: isShowMenu ? mmClasses.default : mmClasses.withLeftMenu,
};
}, [minimapPlacement, isShowMenu]);
return (
<>
<Map
@@ -222,8 +244,8 @@ export const MapWrapper = () => {
onConnectionInfoClick={handleConnectionDbClick}
onSystemContextMenu={handleSystemContextMenu}
onSelectionContextMenu={handleSystemMultipleContext}
minimapClasses={!isShowMenu ? classes.MiniMap : undefined}
isShowMinimap={isShowMinimap}
minimapClasses={minimapClasses}
isShowMinimap={showMinimap}
showKSpaceBG={isShowKSpace}
isThickConnections={isThickConnections}
isShowBackgroundPattern={isShowBackgroundPattern}
@@ -231,6 +253,7 @@ export const MapWrapper = () => {
theme={theme}
pings={pings}
onAddSystem={onAddSystem}
minimapPlacement={minimapPosition}
/>
{openSettings != null && (

View File

@@ -0,0 +1,8 @@
import { MiniMapPlacement } from '@/hooks/Mapper/mapRootProvider/types.ts';
export const MINI_MAP_PLACEMENT_OFFSETS = {
[MiniMapPlacement.rightTop]: { default: '!top-[48px]', withLeftMenu: '!top-[48px] !right-[58px]' },
[MiniMapPlacement.rightBottom]: { default: '!bottom-[0px]', withLeftMenu: '!bottom-[0px] !right-[58px]' },
[MiniMapPlacement.leftTop]: { default: '!top-[48px] !left-[56px]', withLeftMenu: '!top-[48px] !left-[56px]' },
[MiniMapPlacement.leftBottom]: { default: '!left-[56px] !bottom-[0px]', withLeftMenu: '!left-[56px] !bottom-[0px]' },
};

View File

@@ -0,0 +1,11 @@
import Markdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import remarkBreaks from 'remark-breaks';
const REMARK_PLUGINS = [remarkGfm, remarkBreaks];
type MarkdownTextViewerProps = { children: string };
export const MarkdownTextViewer = ({ children }: MarkdownTextViewerProps) => {
return <Markdown remarkPlugins={REMARK_PLUGINS}>{children}</Markdown>;
};

View File

@@ -0,0 +1,21 @@
import { ReactNode } from 'react';
import { WithChildren } from '@/hooks/Mapper/types/common.ts';
import { WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit/WdTooltipWrapper';
import { TooltipPosition } from '@/hooks/Mapper/components/ui-kit/WdTooltip';
import clsx from 'clsx';
type MenuItemWithInfoProps = { infoTitle: ReactNode; infoClass?: string } & WithChildren;
export const MenuItemWithInfo = ({ children, infoClass, infoTitle }: MenuItemWithInfoProps) => {
return (
<div className="flex justify-between w-full h-full items-center">
{children}
<WdTooltipWrapper
content={infoTitle}
position={TooltipPosition.top}
className="!opacity-100 !pointer-events-auto"
>
<div className={clsx('pi text-orange-400', infoClass)} />
</WdTooltipWrapper>
</div>
);
};

View File

@@ -1,5 +1,4 @@
import { WithClassName } from '@/hooks/Mapper/types/common.ts';
import { SystemViewStandalone } from '@/hooks/Mapper/components/ui-kit';
import { SystemViewStandalone, SystemViewStandaloneProps } from '@/hooks/Mapper/components/ui-kit';
import { useLoadSystemStatic } from '@/hooks/Mapper/mapRootProvider/hooks/useLoadSystemStatic.ts';
import { useMemo } from 'react';
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
@@ -8,18 +7,11 @@ import { SolarSystemStaticInfoRaw } from '@/hooks/Mapper/types';
export type SystemViewProps = {
systemId: string;
systemInfo?: SolarSystemStaticInfoRaw;
hideRegion?: boolean;
useSystemsCache?: boolean;
showCustomName?: boolean;
} & WithClassName;
} & Pick<SystemViewStandaloneProps, 'className' | 'compact' | 'hideRegion'>;
export const SystemView = ({
systemId,
systemInfo: customSystemInfo,
hideRegion,
className,
showCustomName,
}: SystemViewProps) => {
export const SystemView = ({ systemId, systemInfo: customSystemInfo, showCustomName, ...rest }: SystemViewProps) => {
const memSystems = useMemo(() => [systemId], [systemId]);
const { systems, loading } = useLoadSystemStatic({ systems: memSystems });
@@ -47,13 +39,8 @@ export const SystemView = ({
}
if (!mapSystemInfo) {
return <SystemViewStandalone hideRegion={hideRegion} className={className} {...systemInfo} />;
return <SystemViewStandalone {...rest} {...systemInfo} />;
}
return (
<div>
<SystemViewStandalone hideRegion={hideRegion} className={className} {...systemInfo} />
<span>{systemInfo.solar_system_name}</span>
</div>
);
return <SystemViewStandalone customName={mapSystemInfo.name ?? undefined} {...rest} {...systemInfo} />;
};

View File

@@ -0,0 +1,16 @@
import { WithChildren } from '@/hooks/Mapper/types/common.ts';
import clsx from 'clsx';
type WdMenuItemProps = { icon?: string; disabled?: boolean } & WithChildren;
export const WdMenuItem = ({ children, icon, disabled }: WdMenuItemProps) => {
return (
<a
className={clsx('flex gap-[6px] w-full h-full items-center px-[12px] !py-0 ml-[-2px]', 'p-menuitem-link', {
'p-disabled': disabled,
})}
>
{icon && <div className={clsx('min-w-[20px]', icon)}></div>}
<div className="w-full">{children}</div>
</a>
);
};

View File

@@ -18,3 +18,6 @@ export * from './WdRadioButton';
export * from './WdEveEntityPortrait';
export * from './WdTransition';
export * from './LoadingWrapper';
export * from './WdMenuItem';
export * from './MenuItemWithInfo';
export * from './MarkdownTextViewer.tsx';

View File

@@ -1,3 +1,5 @@
import { PingsPlacement } from '@/hooks/Mapper/mapRootProvider/types.ts';
export enum SESSION_KEY {
viewPort = 'viewPort',
windows = 'windows',
@@ -139,3 +141,10 @@ export const K162_TYPES_MAP: { [key: string]: K162Type } = K162_TYPES.reduce(
(acc, x) => ({ ...acc, [x.value]: x }),
{},
);
export const MINIMAP_PLACEMENT_MAP = {
[PingsPlacement.rightTop]: 'top-right',
[PingsPlacement.leftTop]: 'top-left',
[PingsPlacement.rightBottom]: 'bottom-right',
[PingsPlacement.leftBottom]: 'bottom-left',
};

View File

@@ -22,6 +22,7 @@ import { DetailedKill } from '../types/kills';
import { InterfaceStoredSettings, RoutesType } from '@/hooks/Mapper/mapRootProvider/types.ts';
import { DEFAULT_ROUTES_SETTINGS, STORED_INTERFACE_DEFAULT_VALUES } from '@/hooks/Mapper/mapRootProvider/constants.ts';
import { useMapUserSettings } from '@/hooks/Mapper/mapRootProvider/hooks/useMapUserSettings.ts';
import { useGlobalHooks } from '@/hooks/Mapper/mapRootProvider/hooks/useGlobalHooks.ts';
export type MapRootData = MapUnionTypes & {
selectedSystems: string[];
@@ -34,6 +35,7 @@ export type MapRootData = MapUnionTypes & {
loading?: boolean;
};
trackingCharactersData: TrackingCharacter[];
loadingPublicRoutes: boolean;
};
const INITIAL_DATA: MapRootData = {
@@ -67,11 +69,11 @@ const INITIAL_DATA: MapRootData = {
mainCharacterEveId: null,
followingCharacterEveId: null,
pings: [],
loadingPublicRoutes: false,
};
export enum InterfaceStoredSettingsProps {
isShowMenu = 'isShowMenu',
isShowMinimap = 'isShowMinimap',
isShowKSpace = 'isShowKSpace',
isThickConnections = 'isThickConnections',
isShowUnsplashedSignatures = 'isShowUnsplashedSignatures',
@@ -144,6 +146,7 @@ type MapRootProviderProps = {
// eslint-disable-next-line react/display-name
const MapRootHandlers = forwardRef(({ children }: WithChildren, fwdRef: ForwardedRef<any>) => {
useMapRootHandlers(fwdRef);
useGlobalHooks();
return <>{children}</>;
});

View File

@@ -1,14 +1,21 @@
import { AvailableThemes, InterfaceStoredSettings, RoutesType } from '@/hooks/Mapper/mapRootProvider/types.ts';
import {
AvailableThemes,
InterfaceStoredSettings,
MiniMapPlacement,
PingsPlacement,
RoutesType,
} from '@/hooks/Mapper/mapRootProvider/types.ts';
export const STORED_INTERFACE_DEFAULT_VALUES: InterfaceStoredSettings = {
isShowMenu: false,
isShowMinimap: true,
isShowKSpace: false,
isThickConnections: false,
isShowUnsplashedSignatures: false,
isShowBackgroundPattern: true,
isSoftBackground: false,
theme: AvailableThemes.default,
pingsPlacement: PingsPlacement.rightTop,
minimapPlacement: MiniMapPlacement.rightBottom,
};
export const DEFAULT_ROUTES_SETTINGS: RoutesType = {

View File

@@ -70,6 +70,9 @@ export const useCommandsSystems = () => {
const updateSystemSignatures = useCallback(
async (systemId: string) => {
const { update, systemSignatures } = ref.current;
// TODO need to fix it
// @ts-ignore
const { signatures } = await outCommand({
type: OutCommand.getSignatures,
data: { system_id: `${systemId}` },

View File

@@ -0,0 +1,6 @@
import { useLoadPublicRoutes } from './useLoadPublicRoutes';
/* TODO this hook needs for call some actions which should affect all mapper*/
export const useGlobalHooks = () => {
useLoadPublicRoutes();
};

View File

@@ -0,0 +1,46 @@
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { LoadRoutesCommand } from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/types.ts';
import { useCallback, useEffect } from 'react';
import { Commands, OutCommand } from '@/hooks/Mapper/types';
import { useLoadRoutes } from '@/hooks/Mapper/components/mapInterface/widgets/RoutesWidget/hooks';
import { useMapEventListener } from '@/hooks/Mapper/events';
export const useLoadPublicRoutes = () => {
const {
outCommand,
storedSettings: { settingsRoutes },
data: { hubs, routes, pings },
update,
} = useMapRootState();
const loadRoutesCommand: LoadRoutesCommand = useCallback(
async (systemId, routesSettings) => {
outCommand({
type: OutCommand.getRoutes,
data: {
system_id: systemId,
routes_settings: routesSettings,
},
});
},
[outCommand],
);
const { loading, setLoading } = useLoadRoutes({
data: settingsRoutes,
hubs: hubs,
loadRoutesCommand,
routesList: routes,
deps: [pings],
});
useEffect(() => {
update({ loadingPublicRoutes: loading });
}, [loading, update]);
useMapEventListener(event => {
if (event.name === Commands.routes) {
setLoading(false);
}
});
};

View File

@@ -8,7 +8,7 @@ import {
} from '@/hooks/Mapper/components/mapInterface/constants.tsx';
import { WindowProps } from '@/hooks/Mapper/components/ui-kit/WindowManager/types.ts';
import { useCallback, useEffect, useRef } from 'react';
import { SNAP_GAP, WindowsManagerOnChange } from '@/hooks/Mapper/components/ui-kit/WindowManager';
import { /*SNAP_GAP,*/ WindowsManagerOnChange } from '@/hooks/Mapper/components/ui-kit/WindowManager';
export type StoredWindowProps = Omit<WindowProps, 'content'>;
export type WindowStoreInfo = {
@@ -17,7 +17,7 @@ export type WindowStoreInfo = {
visible: WidgetsIds[];
viewPort?: { w: number; h: number } | undefined;
};
export type UpdateWidgetSettingsFunc = (widgets: WindowProps[]) => void;
// export type UpdateWidgetSettingsFunc = (widgets: WindowProps[]) => void;
export type ToggleWidgetVisibility = (widgetId: WidgetsIds) => void;
export const getDefaultWidgetProps = () => ({
@@ -112,9 +112,6 @@ export const useStoreWidgets = () => {
const resetWidgets = useCallback(() => ref.current.setWindowsSettings(getDefaultWidgetProps()), []);
// eslint-disable-next-line no-console
console.log('JOipP', `windowsSettings`, windowsSettings);
return {
windowsSettings,
updateWidgetSettings,

View File

@@ -3,15 +3,31 @@ export enum AvailableThemes {
pathfinder = 'pathfinder',
}
export enum MiniMapPlacement {
rightTop = 'rightTop',
rightBottom = 'rightBottom',
leftTop = 'leftTop',
leftBottom = 'leftBottom',
hide = 'hide',
}
export enum PingsPlacement {
rightTop = 'rightTop',
rightBottom = 'rightBottom',
leftTop = 'leftTop',
leftBottom = 'leftBottom',
}
export type InterfaceStoredSettings = {
isShowMenu: boolean;
isShowMinimap: boolean;
isShowKSpace: boolean;
isThickConnections: boolean;
isShowUnsplashedSignatures: boolean;
isShowBackgroundPattern: boolean;
isSoftBackground: boolean;
theme: AvailableThemes;
minimapPlacement: MiniMapPlacement;
pingsPlacement: PingsPlacement;
};
export type RoutesType = {