mirror of
https://github.com/ajvpot/meshexplorer.git
synced 2026-07-06 01:30:58 +02:00
support for changing the app name, info modal
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
import React, { createContext, useContext, useState, useEffect, useRef, useLayoutEffect, ReactNode } from "react";
|
||||
import { getChannelIdFromKey } from "../lib/meshcore";
|
||||
import Modal from "./Modal";
|
||||
|
||||
// Config shape
|
||||
type NodeType = "meshcore" | "meshtastic";
|
||||
@@ -269,19 +270,10 @@ function validateMeshcoreKey(key: string): string | null {
|
||||
|
||||
function MeshcoreKeyModal({ config, setConfig, onClose }: { config: Config, setConfig: (c: Config) => void, onClose: () => void }) {
|
||||
return (
|
||||
<div className="fixed inset-0 z-[3000] flex items-center justify-center bg-black bg-opacity-40">
|
||||
<div className="bg-white dark:bg-neutral-900 rounded-lg shadow-lg p-6 min-w-[350px] max-w-[90vw] max-h-[60vh] overflow-auto border border-gray-200 dark:border-neutral-700 relative">
|
||||
<button
|
||||
className="absolute top-2 right-2 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200"
|
||||
onClick={onClose}
|
||||
aria-label="Close key modal"
|
||||
>
|
||||
<svg width="24" height="24" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
|
||||
</button>
|
||||
<h2 className="text-lg font-semibold mb-4">Meshcore Private Keys</h2>
|
||||
<p className="mb-4 text-sm text-gray-600 dark:text-gray-300">
|
||||
These keys will be used to decrypt messages. <b>Your keys are never shared with the server</b>, so your messages remain secure.
|
||||
</p>
|
||||
<Modal isOpen={true} onClose={onClose} title="Meshcore Private Keys" maxWidth="90vw">
|
||||
<p className="mb-4 text-sm text-gray-600 dark:text-gray-300">
|
||||
These keys will be used to decrypt messages. <b>Your keys are never shared with the server</b>, so your messages remain secure.
|
||||
</p>
|
||||
<div className="flex flex-col gap-1 mb-2 p-2 border rounded bg-gray-100 dark:bg-neutral-700 opacity-80">
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
@@ -389,7 +381,6 @@ function MeshcoreKeyModal({ config, setConfig, onClose }: { config: Config, setC
|
||||
>
|
||||
Add Meshcore Key
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { Cog6ToothIcon, InformationCircleIcon } from "@heroicons/react/24/outlin
|
||||
import { useConfig } from "./ConfigContext";
|
||||
import React, { useState } from "react";
|
||||
import InfoModal from "./InfoModal";
|
||||
import { getAppName } from "../lib/api";
|
||||
|
||||
interface HeaderProps {
|
||||
configButtonRef?: React.Ref<HTMLButtonElement>;
|
||||
@@ -17,7 +18,7 @@ export default function Header({ configButtonRef }: HeaderProps) {
|
||||
<>
|
||||
<header className="w-full flex items-center justify-between px-6 py-3 bg-white dark:bg-neutral-900 shadow z-20">
|
||||
<nav className="flex gap-6 items-center">
|
||||
<Link href="/" className="font-bold text-lg">MeshExplorer</Link>
|
||||
<Link href="/" className="font-bold text-lg">{getAppName()}</Link>
|
||||
<Link href="/messages">Messages</Link>
|
||||
<Link href="/stats">Stats</Link>
|
||||
</nav>
|
||||
@@ -25,7 +26,7 @@ export default function Header({ configButtonRef }: HeaderProps) {
|
||||
<button
|
||||
onClick={() => setInfoModalOpen(true)}
|
||||
className="flex items-center gap-2 px-3 py-2 rounded hover:bg-neutral-100 dark:hover:bg-neutral-800"
|
||||
aria-label="Open information about MeshExplorer"
|
||||
aria-label={`Open information about ${getAppName()}`}
|
||||
>
|
||||
<InformationCircleIcon className="h-6 w-6" />
|
||||
<span className="hidden sm:inline">Info</span>
|
||||
@@ -41,7 +42,7 @@ export default function Header({ configButtonRef }: HeaderProps) {
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
{infoModalOpen && <InfoModal onClose={() => setInfoModalOpen(false)} />}
|
||||
<InfoModal isOpen={infoModalOpen} onClose={() => setInfoModalOpen(false)} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,28 +1,20 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { getAppName } from "../lib/api";
|
||||
import Modal from "./Modal";
|
||||
|
||||
interface InfoModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export default function InfoModal({ onClose }: InfoModalProps) {
|
||||
export default function InfoModal({ isOpen, onClose }: InfoModalProps) {
|
||||
return (
|
||||
<div className="fixed inset-0 z-[3000] flex items-center justify-center bg-black bg-opacity-40">
|
||||
<div className="bg-white dark:bg-neutral-900 rounded-lg shadow-lg p-6 min-w-[350px] max-w-[500px] max-h-[60vh] overflow-auto border border-gray-200 dark:border-neutral-700 relative">
|
||||
<button
|
||||
className="absolute top-2 right-2 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200"
|
||||
onClick={onClose}
|
||||
aria-label="Close info modal"
|
||||
>
|
||||
<svg width="24" height="24" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
|
||||
</button>
|
||||
|
||||
<h2 className="text-lg font-semibold mb-4">About MeshExplorer</h2>
|
||||
|
||||
<div className="space-y-4">
|
||||
<Modal isOpen={isOpen} onClose={onClose} title={`About ${getAppName()}`}>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-300 mb-3">
|
||||
MeshExplorer is a web-based visualization tool for exploring and monitoring mesh networks.
|
||||
{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.
|
||||
</p>
|
||||
</div>
|
||||
@@ -40,10 +32,29 @@ export default function InfoModal({ onClose }: InfoModalProps) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-gray-200 dark:border-neutral-700 pt-4">
|
||||
<h3 className="text-md font-medium mb-2">Community</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-300 mb-3">
|
||||
Connect with the Puget Mesh community, a volunteer group supporting AREDN, Meshtastic, and other off-grid mesh networks in the Puget Sound Region.
|
||||
</p>
|
||||
<a
|
||||
href="https://pugetmesh.org/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-2 px-3 py-2 bg-green-600 text-white rounded hover:bg-green-700 text-sm"
|
||||
>
|
||||
<svg className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
Visit Puget Mesh
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-gray-200 dark:border-neutral-700 pt-4">
|
||||
<h3 className="text-md font-medium mb-2">Contributing</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-300 mb-3">
|
||||
MeshExplorer is open source and welcomes contributions from the community.
|
||||
{getAppName()} is open source and welcomes contributions from the community.
|
||||
</p>
|
||||
<a
|
||||
href="https://github.com/ajvpot/meshexplorer"
|
||||
@@ -58,7 +69,6 @@ export default function InfoModal({ onClose }: InfoModalProps) {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -7,6 +7,15 @@ export function getApiBaseUrl(): string {
|
||||
return process.env.NEXT_PUBLIC_API_URL || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the application name.
|
||||
* If NEXT_PUBLIC_APP_NAME is set, it will be used as the application name.
|
||||
* Otherwise, "MeshExplorer" will be used as the default.
|
||||
*/
|
||||
export function getAppName(): string {
|
||||
return process.env.NEXT_PUBLIC_APP_NAME || 'MeshExplorer';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a full API URL by combining the base URL with the endpoint path.
|
||||
* @param endpoint - The API endpoint path (e.g., '/api/stats/total-nodes')
|
||||
|
||||
Reference in New Issue
Block a user