Compare commits

...

2 Commits

Author SHA1 Message Date
DanSylvest
0447fd4d09 Merge remote-tracking branch 'leesolway/sig-panel-pr' into sig-panel-pr
# Conflicts:
#	assets/js/hooks/Mapper/mapRootProvider/hooks/useMapRootHandlers.ts
2025-10-10 09:54:28 +03:00
Lee Solway
be7bbe6872 Create a signature list panel + hook into live events 2025-10-04 12:04:02 +01:00
7 changed files with 214 additions and 1 deletions

View File

@@ -9,6 +9,7 @@ import { MapContextMenu } from '@/hooks/Mapper/components/mapRootContent/compone
import { useSkipContextMenu } from '@/hooks/Mapper/hooks/useSkipContextMenu';
import { MapSettings } from '@/hooks/Mapper/components/mapRootContent/components/MapSettings';
import { CharacterActivity } from '@/hooks/Mapper/components/mapRootContent/components/CharacterActivity';
import { WormholeSignaturesDialog } from '@/hooks/Mapper/components/mapRootContent/components/WormholeSignaturesDialog';
import { useCharacterActivityHandlers } from './hooks/useCharacterActivityHandlers';
import { TrackingDialog } from '@/hooks/Mapper/components/mapRootContent/components/TrackingDialog';
import { useMapEventListener } from '@/hooks/Mapper/events';
@@ -34,6 +35,7 @@ export const MapRootContent = ({}: MapRootContentProps) => {
const [showOnTheMap, setShowOnTheMap] = useState(false);
const [showMapSettings, setShowMapSettings] = useState(false);
const [showTrackingDialog, setShowTrackingDialog] = useState(false);
const [showWormholeSignatures, setShowWormholeSignatures] = useState(false);
/* Important Notice - this solution needs for use one instance of MapInterface */
const mapInterface = isReady ? <MapInterface /> : null;
@@ -47,6 +49,10 @@ export const MapRootContent = ({}: MapRootContentProps) => {
setShowTrackingDialog(true);
return true;
}
if (event.name === Commands.showWormholeSignatures) {
setShowWormholeSignatures(true);
return true;
}
});
useSkipContextMenu();
@@ -93,6 +99,12 @@ export const MapRootContent = ({}: MapRootContentProps) => {
{showTrackingDialog && (
<TrackingDialog visible={showTrackingDialog} onHide={() => setShowTrackingDialog(false)} />
)}
{showWormholeSignatures && (
<WormholeSignaturesDialog
visible={showWormholeSignatures}
onHide={() => setShowWormholeSignatures(false)}
/>
)}
{hasOldSettings && <OldSettingsDialog />}
</Layout>

View File

@@ -0,0 +1,175 @@
import { useMemo, useState } from 'react';
import { Dialog } from 'primereact/dialog';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { useMapRootState } from '@/hooks/Mapper/mapRootProvider';
import { WormholeDataRaw } from '@/hooks/Mapper/types';
import { WHClassView } from '@/hooks/Mapper/components/ui-kit';
import { kgToTons } from '@/hooks/Mapper/utils/kgToTons.ts';
import { WORMHOLE_CLASS_STYLES, WORMHOLES_ADDITIONAL_INFO } from '@/hooks/Mapper/components/map/constants.ts';
import clsx from 'clsx';
import { InputText } from 'primereact/inputtext';
import { IconField } from 'primereact/iconfield';
import { InputIcon } from 'primereact/inputicon';
export interface WormholeSignaturesDialogProps {
visible: boolean;
onHide: () => void;
}
const RespawnTag = ({ value }: { value: string }) => (
<span className="px-2 py-[2px] rounded bg-stone-800 text-stone-300 text-xs border border-stone-700">{value}</span>
);
export const WormholeSignaturesDialog = ({ visible, onHide }: WormholeSignaturesDialogProps) => {
const {
data: { wormholes },
} = useMapRootState();
const [filter, setFilter] = useState('');
const filtered = useMemo(() => {
const q = filter.trim().toLowerCase();
if (!q) return wormholes;
return wormholes.filter(w => {
const destInfo = WORMHOLES_ADDITIONAL_INFO[w.dest];
const spawnsLabels = w.src
.map(s => {
const group = s.split('-')[0];
const info = WORMHOLES_ADDITIONAL_INFO[group];
if (!info) return s;
return `${info.title} ${info.shortName}`.trim();
})
.join(' ');
return [
w.name,
destInfo?.title,
destInfo?.shortName,
spawnsLabels,
String(w.total_mass),
String(w.max_mass_per_jump),
w.lifetime,
w.respawn.join(','),
]
.filter(Boolean)
.join(' ')
.toLowerCase()
.includes(q);
});
}, [wormholes, filter]);
const renderName = (w: WormholeDataRaw) => (
<div className="flex items-center gap-2">
<WHClassView whClassName={w.name} noOffset useShortTitle />
</div>
);
const renderRespawn = (w: WormholeDataRaw) => (
<div className="flex gap-1 flex-wrap">
{w.respawn.map(r => (
<RespawnTag key={r} value={r} />
))}
</div>
);
const renderSpawns = (w: WormholeDataRaw) => (
<div className="flex gap-1 flex-wrap">
{w.src.map(s => {
const group = s.split('-')[0];
const info = WORMHOLES_ADDITIONAL_INFO[group];
if (!info)
return (
<span key={s} className="px-2 py-[2px] rounded bg-stone-800 text-stone-300 text-xs border border-stone-700">
{s}
</span>
);
const cls = WORMHOLE_CLASS_STYLES[String(info.wormholeClassID)] || '';
const label = `${info.shortName}`;
return (
<span key={s} className={clsx(cls, 'px-2 py-[2px] rounded text-xs border border-stone-700 bg-stone-900/40')}>
{label}
</span>
);
})}
</div>
);
return (
<Dialog
header="Wormhole Signatures Reference"
visible={visible}
draggable={true}
resizable={false}
style={{ width: '820px', height: '600px' }}
onHide={onHide}
contentClassName="!p-0 flex flex-col h-full"
>
<div className="p-3 flex items-center justify-between gap-2 border-b border-stone-800">
<div className="font-semibold text-sm text-stone-200">Reference list of all wormhole types</div>
<IconField iconPosition="right">
<InputIcon
className={clsx(
'pi pi-times',
filter
? 'cursor-pointer text-stone-400 hover:text-stone-200'
: 'text-stone-700 opacity-50 cursor-default',
)}
onClick={() => filter && setFilter('')}
role="button"
aria-label="Clear search"
aria-disabled={!filter}
title={filter ? 'Clear' : 'Nothing to clear'}
/>
<InputText className="w-64" placeholder="Search" value={filter} onChange={e => setFilter(e.target.value)} />
</IconField>
</div>
<div className="flex-1 p-2 overflow-x-hidden">
<DataTable
value={filtered}
size="small"
scrollable
scrollHeight="flex"
stripedRows
style={{ width: '100%', height: '100%' }}
tableStyle={{ tableLayout: 'fixed', width: '100%' }}
>
<Column
header="Type"
body={renderName}
style={{ width: '140px' }}
bodyClassName="whitespace-normal break-words"
/>
<Column
header="Spawns In"
body={renderSpawns}
style={{ width: '200px' }}
bodyClassName="whitespace-normal break-words"
/>
<Column
field="lifetime"
header="Lifetime"
style={{ width: '90px' }}
bodyClassName="whitespace-normal break-words"
/>
<Column
header="Total Mass"
style={{ width: '120px' }}
body={(w: WormholeDataRaw) => kgToTons(w.total_mass)}
bodyClassName="whitespace-normal break-words"
/>
<Column
header="Max/jump"
style={{ width: '120px' }}
body={(w: WormholeDataRaw) => kgToTons(w.max_mass_per_jump)}
bodyClassName="whitespace-normal break-words"
/>
<Column header="Respawn" body={renderRespawn} bodyClassName="whitespace-normal break-words" />
</DataTable>
</div>
</Dialog>
);
};

View File

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

View File

@@ -175,6 +175,9 @@ export const useMapRootHandlers = (ref: ForwardedRef<MapHandlers>) => {
pingCancelled(data as CommandPingCancelled);
break;
case Commands.showWormholeSignatures:
break;
default:
console.warn(`JOipP Interface handlers: Unknown command: ${type}`, data);
break;

View File

@@ -40,6 +40,7 @@ export enum Commands {
showTracking = 'show_tracking',
pingAdded = 'ping_added',
pingCancelled = 'ping_cancelled',
showWormholeSignatures = 'show_wormhole_signatures',
}
export type Command =
@@ -75,7 +76,8 @@ export type Command =
| Commands.updateTracking
| Commands.showTracking
| Commands.pingAdded
| Commands.pingCancelled;
| Commands.pingCancelled
| Commands.showWormholeSignatures;
export type CommandInit = {
systems: SolarSystemRawType[];
@@ -158,6 +160,7 @@ export type CommandUpdateTracking = {
};
export type CommandPingAdded = PingData[];
export type CommandPingCancelled = Pick<PingData, 'type' | 'id'>;
export type CommandShowWormholeSignatures = null;
export interface UserSettings {
primaryCharacterId?: string;
@@ -208,6 +211,7 @@ export interface CommandData {
[Commands.showTracking]: CommandShowTracking;
[Commands.pingAdded]: CommandPingAdded;
[Commands.pingCancelled]: CommandPingCancelled;
[Commands.showWormholeSignatures]: CommandShowWormholeSignatures;
}
export interface MapHandlers {

View File

@@ -194,6 +194,15 @@ defmodule WandererAppWeb.MapCoreEventHandler do
{:reply, %{user_settings: user_settings}, socket}
end
def handle_ui_event("show_wormhole_signatures", _event, socket) do
{:noreply,
socket
|> MapEventHandler.push_map_event(
"show_wormhole_signatures",
%{}
)}
end
def handle_ui_event(
"update_user_settings",
user_settings_form,

View File

@@ -32,6 +32,15 @@
<.icon name="hero-chart-bar-solid" class="w-6 h-6" />
</button>
<button
id="show-wormhole-signatures-button"
class="h-8 w-8 hover:text-white"
phx-click="show_wormhole_signatures"
title="Wormhole Signatures Reference"
>
<.icon name="hero-sparkles-solid" class="w-6 h-6" />
</button>
<.link
:if={(@user_permissions || %{}) |> Map.get(:delete_map, false)}
id={"map-audit-#{@map_slug}"}