Add link to node from map display. Closes #189.

This commit is contained in:
Jack Kingsman
2026-04-16 11:58:39 -07:00
parent 56fc589e0b
commit b1cd6e1aa9
5 changed files with 108 additions and 4 deletions
+18 -1
View File
@@ -20,7 +20,11 @@ import type {
} from '../types';
import type { RawPacketStatsSessionState } from '../utils/rawPacketStats';
import { CONTACT_TYPE_REPEATER, CONTACT_TYPE_ROOM } from '../types';
import { isPrefixOnlyContact, isUnknownFullKeyContact } from '../utils/pubkey';
import {
getContactDisplayName,
isPrefixOnlyContact,
isUnknownFullKeyContact,
} from '../utils/pubkey';
const RepeaterDashboard = lazy(() =>
import('./RepeaterDashboard').then((m) => ({ default: m.RepeaterDashboard }))
@@ -65,6 +69,7 @@ interface ConversationPaneProps {
channelKey: string,
pathHashModeOverride: number | null
) => Promise<void>;
onSelectConversation: (conversation: Conversation) => void;
onOpenContactInfo: (publicKey: string, fromChannel?: boolean) => void;
onOpenChannelInfo: (channelKey: string) => void;
onSenderClick: (sender: string) => void;
@@ -137,6 +142,7 @@ export function ConversationPane({
onDeleteChannel,
onSetChannelFloodScopeOverride,
onSetChannelPathHashModeOverride,
onSelectConversation,
onOpenContactInfo,
onOpenChannelInfo,
onSenderClick,
@@ -197,6 +203,17 @@ export function ConversationPane({
focusedKey={activeConversation.mapFocusKey}
rawPackets={rawPackets}
config={config}
onSelectContact={(contact) =>
onSelectConversation({
type: 'contact',
id: contact.public_key,
name: getContactDisplayName(
contact.name,
contact.public_key,
contact.last_advert
),
})
}
/>
</Suspense>
</div>
+25 -2
View File
@@ -21,6 +21,9 @@ interface MapViewProps {
focusedKey?: string | null;
rawPackets?: RawPacket[];
config?: RadioConfig | null;
/** When provided, the contact name in each popup becomes a clickable link
* that opens the conversation for that contact (DM, repeater, or room). */
onSelectContact?: (contact: Contact) => void;
}
// --- Tile layer presets ---
@@ -379,7 +382,13 @@ function ParticleOverlay({ particles }: { particles: MapParticle[] }) {
// --- Main component ---
export function MapView({ contacts, focusedKey, rawPackets, config }: MapViewProps) {
export function MapView({
contacts,
focusedKey,
rawPackets,
config,
onSelectContact,
}: MapViewProps) {
const [sevenDaysAgo] = useState(() => Date.now() / 1000 - 7 * 24 * 60 * 60);
const [darkMap, setDarkMap] = useState(getSavedDarkMap);
const tile = darkMap ? TILE_DARK : TILE_LIGHT;
@@ -839,7 +848,21 @@ export function MapView({ contacts, focusedKey, rawPackets, config }: MapViewPro
🛜
</span>
)}
{displayName}
{onSelectContact ? (
<button
type="button"
className="p-0 bg-transparent border-0 font-inherit text-primary underline hover:text-primary/80 cursor-pointer"
onClick={(event) => {
event.stopPropagation();
onSelectContact(contact);
}}
title={`Open conversation with ${displayName}`}
>
{displayName}
</button>
) : (
displayName
)}
</div>
<div className="text-xs text-gray-500 mt-1">Last heard: {lastHeardLabel}</div>
<div className="text-xs text-gray-400 mt-1 font-mono">