mirror of
https://github.com/ajvpot/meshexplorer.git
synced 2026-08-06 08:32:45 +02:00
release-prep: remove meshtastic from web app
Meshtastic was UI-filtering only (no meshtastic data backend). Drop it as a node type/option, and simplify the map marker/cluster/popup rendering now that every node is meshcore. Update product copy to MeshCore-only. The nodeTypes query plumbing stays (the unified view's type is always 'meshcore'). Production build passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,7 @@ const geistMono = Geist_Mono({
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "MeshExplorer",
|
||||
description: "A real-time map, chat client, and packet analysis tool for mesh networks using MeshCore and Meshtastic.",
|
||||
description: "A real-time map, chat client, and packet analysis tool for MeshCore mesh networks.",
|
||||
icons: {
|
||||
icon: { url: "/favicon.svg", type: "image/svg+xml" },
|
||||
apple: { url: "/favicon.svg", type: "image/svg+xml" }
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function InfoModal({ isOpen, onClose }: InfoModalProps) {
|
||||
<div>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-300 mb-3">
|
||||
{getAppName()} is a web-based visualization tool for exploring and monitoring mesh networks.
|
||||
It provides real-time mapping of network nodes, message tracking, and statistical analysis for MeshCore and Meshtastic networks.
|
||||
It provides real-time mapping of network nodes, message tracking, and statistical analysis for MeshCore networks.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -23,19 +23,13 @@ interface PopupContentProps {
|
||||
// Individual node marker component
|
||||
export function NodeMarker({ node, showNodeNames = true, isSelected = false, isLoadingNeighbors = false }: NodeMarkerProps) {
|
||||
const getMarkerClass = () => {
|
||||
let baseClass = "custom-node-marker";
|
||||
|
||||
if (node.type === "meshtastic") {
|
||||
baseClass += " custom-node-marker--green";
|
||||
} else if (node.type === "meshcore") {
|
||||
baseClass += " custom-node-marker--blue custom-node-marker--top";
|
||||
}
|
||||
|
||||
let baseClass = "custom-node-marker custom-node-marker--blue custom-node-marker--top";
|
||||
|
||||
// Only add loading class when actually loading neighbors
|
||||
if (isLoadingNeighbors) {
|
||||
baseClass += " custom-node-marker--loading";
|
||||
}
|
||||
|
||||
|
||||
return baseClass;
|
||||
};
|
||||
|
||||
@@ -43,7 +37,7 @@ export function NodeMarker({ node, showNodeNames = true, isSelected = false, isL
|
||||
<div className="custom-node-marker-container">
|
||||
{showNodeNames && node.short_name && (
|
||||
<div className="custom-node-label">
|
||||
{node.type === "meshcore" ? getNameIconLabel(node.name || node.short_name) : node.short_name}
|
||||
{getNameIconLabel(node.name || node.short_name)}
|
||||
</div>
|
||||
)}
|
||||
<div className={getMarkerClass()}></div>
|
||||
@@ -51,29 +45,11 @@ export function NodeMarker({ node, showNodeNames = true, isSelected = false, isL
|
||||
);
|
||||
}
|
||||
|
||||
// Cluster marker component with pie chart
|
||||
// Cluster marker component
|
||||
export function ClusterMarker({ children }: ClusterMarkerProps) {
|
||||
let meshtasticCount = 0;
|
||||
let meshcoreCount = 0;
|
||||
|
||||
// Convert children to array if it's not already
|
||||
const childrenArray = Array.isArray(children) ? children : [children];
|
||||
|
||||
childrenArray.forEach((marker: any) => {
|
||||
const node = marker.options && marker.options.nodeData;
|
||||
if (node?.type === 'meshtastic') meshtasticCount++;
|
||||
else if (node?.type === 'meshcore') meshcoreCount++;
|
||||
});
|
||||
|
||||
const total = meshtasticCount + meshcoreCount;
|
||||
const percentMeshcore = total ? meshcoreCount / total : 0;
|
||||
const percentMeshtastic = total ? meshtasticCount / total : 0;
|
||||
|
||||
// Pie chart SVG calculations
|
||||
const r = 13.5;
|
||||
const c = 2 * Math.PI * r;
|
||||
const meshcoreArc = percentMeshcore * c;
|
||||
const meshtasticArc = percentMeshtastic * c;
|
||||
const total = childrenArray.length;
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
@@ -94,35 +70,11 @@ export function ClusterMarker({ children }: ClusterMarkerProps) {
|
||||
r="13.5"
|
||||
cx="15"
|
||||
cy="15"
|
||||
fill="#fff"
|
||||
fill="#2563eb"
|
||||
stroke="#fff"
|
||||
strokeWidth="3"
|
||||
opacity="0.7"
|
||||
/>
|
||||
<circle
|
||||
r="13.5"
|
||||
cx="15"
|
||||
cy="15"
|
||||
fill="transparent"
|
||||
stroke="#2563eb"
|
||||
strokeWidth="27"
|
||||
strokeDasharray={`${meshcoreArc} ${c - meshcoreArc}`}
|
||||
strokeDashoffset="0"
|
||||
transform="rotate(-90 15 15)"
|
||||
opacity="0.7"
|
||||
/>
|
||||
<circle
|
||||
r="13.5"
|
||||
cx="15"
|
||||
cy="15"
|
||||
fill="transparent"
|
||||
stroke="#22c55e"
|
||||
strokeWidth="27"
|
||||
strokeDasharray={`${meshtasticArc} ${c - meshtasticArc}`}
|
||||
strokeDashoffset={`-${meshcoreArc}`}
|
||||
transform="rotate(-90 15 15)"
|
||||
opacity="0.7"
|
||||
/>
|
||||
</svg>
|
||||
<span style={{
|
||||
position: "absolute",
|
||||
@@ -149,9 +101,9 @@ export function ClusterMarker({ children }: ClusterMarkerProps) {
|
||||
export function PopupContent({ node, target = '_self' }: PopupContentProps) {
|
||||
return (
|
||||
<div>
|
||||
<div><b>ID:</b> {node.type === "meshcore" ? formatPublicKey(node.node_id) : node.node_id}</div>
|
||||
<div><b>ID:</b> {formatPublicKey(node.node_id)}</div>
|
||||
<div><b>Full Name:</b> {node.name ?? "-"}</div>
|
||||
<div><b>Short Name:</b> {node.type === "meshcore" && node.short_name ? getNameIconLabel(node.name || node.short_name) : (node.short_name ?? "-")}</div>
|
||||
<div><b>Short Name:</b> {node.short_name ? getNameIconLabel(node.name || node.short_name) : "-"}</div>
|
||||
<div><b>Type:</b> {node.type ?? "-"}</div>
|
||||
<div><b>Lat:</b> {node.latitude}</div>
|
||||
<div><b>Lng:</b> {node.longitude}</div>
|
||||
@@ -172,30 +124,26 @@ export function PopupContent({ node, target = '_self' }: PopupContentProps) {
|
||||
) : (
|
||||
<div><b>First seen:</b> -</div>
|
||||
)}
|
||||
{node.type === "meshcore" && (
|
||||
<div style={{marginTop: '8px', paddingTop: '8px', borderTop: '1px solid #e5e7eb'}}>
|
||||
<a
|
||||
href={`/meshcore/node/${node.node_id}`}
|
||||
target={target}
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
padding: '4px 8px',
|
||||
backgroundColor: '#3b82f6',
|
||||
color: 'white',
|
||||
textDecoration: 'none',
|
||||
borderRadius: '4px',
|
||||
fontSize: '12px',
|
||||
fontWeight: '500'
|
||||
}}
|
||||
onMouseOver={(e) => e.currentTarget.style.backgroundColor = '#2563eb'}
|
||||
onMouseOut={(e) => e.currentTarget.style.backgroundColor = '#3b82f6'}
|
||||
>
|
||||
View Node Details →
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
<div style={{marginTop: '8px', paddingTop: '8px', borderTop: '1px solid #e5e7eb'}}>
|
||||
<a
|
||||
href={`/meshcore/node/${node.node_id}`}
|
||||
target={target}
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
padding: '4px 8px',
|
||||
backgroundColor: '#3b82f6',
|
||||
color: 'white',
|
||||
textDecoration: 'none',
|
||||
borderRadius: '4px',
|
||||
fontSize: '12px',
|
||||
fontWeight: '500'
|
||||
}}
|
||||
onMouseOver={(e) => e.currentTarget.style.backgroundColor = '#2563eb'}
|
||||
onMouseOut={(e) => e.currentTarget.style.backgroundColor = '#3b82f6'}
|
||||
>
|
||||
View Node Details →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -78,11 +78,11 @@ export default function MapLayerSettingsComponent({ onSettingsChange }: MapLayer
|
||||
<label key={nodeType.key} className="flex items-center gap-2 mb-1 ml-6 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={settings.nodeTypes.includes(nodeType.key as "meshcore" | "meshtastic")}
|
||||
checked={settings.nodeTypes.includes(nodeType.key as "meshcore")}
|
||||
onChange={(e) => {
|
||||
const currentTypes = settings.nodeTypes;
|
||||
if (e.target.checked) {
|
||||
updateSetting('nodeTypes', [...currentTypes, nodeType.key as "meshcore" | "meshtastic"]);
|
||||
updateSetting('nodeTypes', [...currentTypes, nodeType.key as "meshcore"]);
|
||||
} else {
|
||||
updateSetting('nodeTypes', currentTypes.filter(t => t !== nodeType.key));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
import { useLocalStorage } from './useLocalStorage';
|
||||
|
||||
type NodeType = "meshcore" | "meshtastic";
|
||||
type NodeType = "meshcore";
|
||||
|
||||
export interface MapLayerSettings {
|
||||
showNodes: boolean;
|
||||
@@ -41,5 +41,4 @@ export const TILE_LAYERS = [
|
||||
|
||||
export const NODE_TYPE_OPTIONS = [
|
||||
{ key: "meshcore", label: "Meshcore" },
|
||||
{ key: "meshtastic", label: "Meshtastic" },
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user