From f89afb397f20950468107a1db65c227ba2168790 Mon Sep 17 00:00:00 2001 From: Matthew Davies Date: Wed, 11 Sep 2024 22:52:01 -0700 Subject: [PATCH] you wanted dark mode? --- frontend/index.html | 2 +- frontend/src/components/HardwareImg.tsx | 2 +- frontend/src/components/HeardBy.tsx | 5 +- frontend/src/components/Layout.tsx | 98 ++++++++++++++----- frontend/src/pages/Chat.tsx | 26 ++--- frontend/src/pages/Map.tsx | 41 +++++--- frontend/src/pages/MeshLog.tsx | 10 +- frontend/src/pages/MqttLog.tsx | 14 ++- frontend/src/pages/Neighbors.tsx | 74 ++++++++++----- frontend/src/pages/Node.tsx | 30 ++++-- frontend/src/pages/NodeMap.tsx | 30 ++++-- frontend/src/pages/Nodes.tsx | 120 +++++++++++++++--------- frontend/src/pages/Telemetry.tsx | 59 +++++++----- frontend/src/pages/Traceroutes.tsx | 52 ++++++++-- frontend/src/slices/appSlice.ts | 27 ++---- 15 files changed, 405 insertions(+), 185 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index 796f71b..67a2fff 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1,5 +1,5 @@ - + diff --git a/frontend/src/components/HardwareImg.tsx b/frontend/src/components/HardwareImg.tsx index dfa1300..a97f933 100644 --- a/frontend/src/components/HardwareImg.tsx +++ b/frontend/src/components/HardwareImg.tsx @@ -18,7 +18,7 @@ export const HardwareImg = ({ model }: { model: number }) => { src={`${import.meta.env.BASE_URL}images/hardware/${image}`} alt={modelName} title={modelName} - className="w-8 h-8 object-cover" + className="w-8 h-8 object-cover dark:brightness-5" /> ); }; diff --git a/frontend/src/components/HeardBy.tsx b/frontend/src/components/HeardBy.tsx index c1582b6..c8d44f4 100644 --- a/frontend/src/components/HeardBy.tsx +++ b/frontend/src/components/HeardBy.tsx @@ -9,7 +9,10 @@ export const HeardBy = () => { <> {" "} that have been heard by the mesh by{" "} - + {config?.server?.node_id} {" "} ({config?.server?.node_id}) diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index 26d15b0..61347bc 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -16,15 +16,20 @@ export const Layout = ({ children }: { children: React.ReactNode }) => { return ( <> -
-
+
+
{config?.mesh?.name?.split(" ").map((word, index) => ( - // eslint-disable-next-line react/no-array-index-key -
+
{word[0]} - {word.slice(1)} + + {word.slice(1)} +
))}
@@ -33,7 +38,10 @@ export const Layout = ({ children }: { children: React.ReactNode }) => {
{config?.mesh?.description}
@@ -41,12 +49,15 @@ export const Layout = ({ children }: { children: React.ReactNode }) => {
-
+
{ }, [channels]); return ( -
-
Chat
+
+
Chat

Chat

{channels.map(([id, channel]) => ( @@ -91,28 +91,28 @@ export const Chat = () => {

Channel {selectedChannel}

- +
- - - - - - - @@ -129,8 +129,10 @@ export const Chat = () => { : null; return ( - // eslint-disable-next-line react/no-array-index-key - +
+ Time + From + Via + To + Hops + DX + Message
{format( new Date(message.timestamp * 1000), diff --git a/frontend/src/pages/Map.tsx b/frontend/src/pages/Map.tsx index e1e4e53..47a9f20 100644 --- a/frontend/src/pages/Map.tsx +++ b/frontend/src/pages/Map.tsx @@ -145,12 +145,31 @@ export function Map() { ]); const initialZoom = JSON.parse(localStorage.getItem("savedZoom") ?? "9.5"); + const tileLayer = new TileLayer({ + source: new OSM(), + }); + + if ( + window.matchMedia && + window.matchMedia("(prefers-color-scheme: dark)").matches + ) { + tileLayer.on("prerender", (evt) => { + if (evt.context) { + const context = evt.context as CanvasRenderingContext2D; + context.filter = "grayscale(80%) invert(100%) "; + context.globalCompositeOperation = "source-over"; + } + }); + tileLayer.on("postrender", (evt) => { + if (evt.context) { + const context = evt.context as CanvasRenderingContext2D; + context.filter = "none"; + } + }); + } + const map = new OlMap({ - layers: [ - new TileLayer({ - source: new OSM(), - }), - ], + layers: [tileLayer], target: mapRef.current as HTMLElement, view: new View({ center: initialCenter, @@ -431,16 +450,16 @@ export function Map() { panel += "Elsewhere
"; const nodeId = parseInt(node.id, 16); - panel += `Armooo's MeshView
`; - panel += `Bay Mesh Explorer
`; - panel += `Liam's Map
`; - panel += `MeshMap
`; @@ -477,7 +496,7 @@ export function Map() { return (
-
+
NODE NAME @@ -491,7 +510,7 @@ export function Map() {
-
+
LEGEND
Heard A diff --git a/frontend/src/pages/MeshLog.tsx b/frontend/src/pages/MeshLog.tsx index ef7533d..63b68e2 100644 --- a/frontend/src/pages/MeshLog.tsx +++ b/frontend/src/pages/MeshLog.tsx @@ -17,11 +17,15 @@ export const MeshLog = () => { since this server was last restarted are shown.

- +
- - + + diff --git a/frontend/src/pages/MqttLog.tsx b/frontend/src/pages/MqttLog.tsx index e9990ba..f19d977 100644 --- a/frontend/src/pages/MqttLog.tsx +++ b/frontend/src/pages/MqttLog.tsx @@ -19,12 +19,18 @@ export const MqttLog = () => { are shown.

-
TimestampMessage + Timestamp + + Message +
+
- - - + + + diff --git a/frontend/src/pages/Neighbors.tsx b/frontend/src/pages/Neighbors.tsx index 8cb6674..956414e 100644 --- a/frontend/src/pages/Neighbors.tsx +++ b/frontend/src/pages/Neighbors.tsx @@ -44,35 +44,49 @@ export const Neighbors = () => {
TimestampTopicMessage + Timestamp + + Topic + + Message +
- - - - - - - - - + + + + - @@ -81,13 +95,16 @@ export const Neighbors = () => { {activeNodesWithNeighbors.map((node) => { const id = node.id.replace("!", ""); return ( - + @@ -96,11 +113,15 @@ export const Neighbors = () => { style={{ color: node.shortname === "UNK" ? "#777" : "#000" }} align="center" > - {node.shortname} + + {node.shortname} + @@ -117,7 +138,10 @@ export const Neighbors = () => {
+ ID + Name + Neighbors Seen
- + + Short LongHeardHeard ByInterval + + Long + + Heard + + Heard By + + Interval + Last + Since
- + {node.longname}
{nodes[neighborIdHex] ? ( - + {nodes[neighborIdHex].shortname} ) : ( @@ -148,9 +172,12 @@ export const Neighbors = () => { // eslint-disable-next-line react/no-array-index-key
- + {nnode.shortname} - + SNR: {neighbor.snr} @@ -200,7 +227,12 @@ export const Neighbors = () => {


- Download JSON + + Download JSON + ); }; diff --git a/frontend/src/pages/Node.tsx b/frontend/src/pages/Node.tsx index 5493c1b..e958f32 100644 --- a/frontend/src/pages/Node.tsx +++ b/frontend/src/pages/Node.tsx @@ -25,7 +25,13 @@ export const Node = () => { return ( <>
- Nodes > {node.shortname} + + Nodes + {" "} + > {node.shortname}
@@ -122,6 +128,7 @@ export const Node = () => { href={`https://meshview.armooo.net/packet_list/${convertNodeIdFromHexToInt(node.id)}`} target="_blank" rel="noreferrer" + className="dark:text-indigo-400 dark:visited:text-indigo-400 dark:hover:text-indigo-500" > Armooo's MeshView @@ -130,6 +137,7 @@ export const Node = () => { href={`https://app.bayme.sh/node/${node.id}`} target="_blank" rel="noreferrer" + className="dark:text-indigo-400 dark:visited:text-indigo-400 dark:hover:text-indigo-500" > Bay Mesh Explorer @@ -138,6 +146,7 @@ export const Node = () => { href={`https://meshtastic.liamcottle.net/?node_id=${convertNodeIdFromHexToInt(node.id)}`} target="_blank" rel="noreferrer" + className="dark:text-indigo-400 dark:visited:text-indigo-400 dark:hover:text-indigo-500" > Liam's Map @@ -146,6 +155,7 @@ export const Node = () => { href={`https://meshmap.net/#${convertNodeIdFromHexToInt(node.id)}`} target="_blank" rel="noreferrer" + className="dark:text-indigo-400 dark:visited:text-indigo-400 dark:hover:text-indigo-500" > MeshMap @@ -156,7 +166,7 @@ export const Node = () => {

Details

- +
@@ -311,7 +321,7 @@ export const Node = () => {

Heard (zero hop)

- +
{node.neighborinfo ? ( node.neighborinfo?.neighbors?.map((neighbor, index) => { @@ -322,7 +332,12 @@ export const Node = () => {
{nnode ? ( - {nnode.shortname} + + {nnode.shortname} + ) : ( UNK )} @@ -352,7 +367,7 @@ export const Node = () => {

Heard By (zero hop)

- +
{Object.entries(nodes).map( ([iid, nnode], index) => @@ -366,7 +381,10 @@ export const Node = () => {
{iid in nodes ? ( - + {nodes[iid].shortname} ) : ( diff --git a/frontend/src/pages/NodeMap.tsx b/frontend/src/pages/NodeMap.tsx index 2bddf6a..0f8a924 100644 --- a/frontend/src/pages/NodeMap.tsx +++ b/frontend/src/pages/NodeMap.tsx @@ -56,14 +56,32 @@ export const NodeMap = ({ node }: { node: INode }) => { useEffect(() => { if (olMap) return; if (!node.position || !mapRef) return; - console.log("mount"); + + const tileLayer = new TileLayer({ + source: new OSM(), + }); + + if ( + window.matchMedia && + window.matchMedia("(prefers-color-scheme: dark)").matches + ) { + tileLayer.on("prerender", (evt) => { + if (evt.context) { + const context = evt.context as CanvasRenderingContext2D; + context.filter = "grayscale(80%) invert(100%) "; + context.globalCompositeOperation = "source-over"; + } + }); + tileLayer.on("postrender", (evt) => { + if (evt.context) { + const context = evt.context as CanvasRenderingContext2D; + context.filter = "none"; + } + }); + } const map = new OlMap({ - layers: [ - new TileLayer({ - source: new OSM(), - }), - ], + layers: [tileLayer], target: mapRef.current as HTMLElement, view: new View({ center: fromLonLat([node.position.longitude, node.position.latitude]), diff --git a/frontend/src/pages/Nodes.tsx b/frontend/src/pages/Nodes.tsx index 4c3fba7..3ad4840 100644 --- a/frontend/src/pages/Nodes.tsx +++ b/frontend/src/pages/Nodes.tsx @@ -94,7 +94,6 @@ export const Nodes = () => { } else { setSort({ by: column, dir: "asc" }); } - console.log("Sorting by %s %s", sort.by, sort.dir); } return ( @@ -106,100 +105,113 @@ export const Nodes = () => { of {Object.entries(nodes).length} seen nodes - +
- - - - + - - - - + - - - - - - - - - - @@ -258,20 +279,30 @@ export const Nodes = () => { {node.position.altitude || ""}
+ ID + Name + HW Role + Role + Last Position + Neighbors Telemetry + Seen
- Hex + + + Hex + + - - + + + + Coordinates + DX + Count + Battery + Voltage + Air Util TX + Channel Util + @@ -214,11 +226,16 @@ export const Nodes = () => { align="center" valign="middle" > - + {id ? ( - {id.replace("!", "")} + + {id.replace("!", "")} + ) : ( id )} @@ -228,14 +245,18 @@ export const Nodes = () => { style={{ color: node.shortname === "UNK" ? "#777" : "#000" }} > {id ? ( - {node.shortname} + + {node.shortname} + ) : ( node.shortname )} {node.longname} - {node.position && node.position.latitude && node.position.longitude ? ( - Yes + {node.position && + node.position.latitude && + node.position.longitude ? ( + + Yes + ) : ( - <> - + <> )} - {serverNode?.position && serverNode.position.latitude && serverNode.position.longitude && - node.position && node.position.latitude && node.position.latitude !== 0 && - node.position.longitude && node.position.longitude !== 0 && + {serverNode?.position && + serverNode.position.latitude && + serverNode.position.longitude && + node.position && + node.position.latitude && + node.position.latitude !== 0 && + node.position.longitude && + node.position.longitude !== 0 && getDistanceBetweenTwoPoints( [node.position.longitude, node.position.latitude], [ @@ -351,7 +382,12 @@ export const Nodes = () => {


- Download JSON + + Download JSON + ); }; diff --git a/frontend/src/pages/Telemetry.tsx b/frontend/src/pages/Telemetry.tsx index 3f26c3b..c28ae89 100644 --- a/frontend/src/pages/Telemetry.tsx +++ b/frontend/src/pages/Telemetry.tsx @@ -1,3 +1,5 @@ +import { Link } from "react-router-dom"; + import { HeardBy } from "../components/HeardBy"; import { useGetNodesQuery, useGetTelemetryQuery } from "../slices/apiSlice"; @@ -24,113 +26,119 @@ export const Telemetry = () => { - - +
+ Timestamp + Node Air Util TX Channel Util Battery Uptime Voltage Current Barometric Pressure Relative Humidity Temperature Gas Resistance @@ -142,7 +150,7 @@ export const Telemetry = () => { const inode = nodes[item.from]; return ( // eslint-disable-next-line react/no-array-index-key -
{"timestamp" in item ? ( new Date(item.timestamp * 1000).toISOString() @@ -152,7 +160,12 @@ export const Telemetry = () => { {inode ? ( - {inode.shortname} + + {inode.shortname} + ) : ( UNK )} diff --git a/frontend/src/pages/Traceroutes.tsx b/frontend/src/pages/Traceroutes.tsx index 07ff0d8..55c6052 100644 --- a/frontend/src/pages/Traceroutes.tsx +++ b/frontend/src/pages/Traceroutes.tsx @@ -1,3 +1,5 @@ +import { Link } from "react-router-dom"; + import { HeardBy } from "../components/HeardBy"; import { useGetNodesQuery, useGetTraceroutesQuery } from "../slices/apiSlice"; @@ -21,26 +23,41 @@ export const Traceroutes = () => { Traceroutes as

- +
- - - - -
+ Timestamp + From + To + Hops + Route Route Hops @@ -60,14 +77,24 @@ export const Traceroutes = () => { {fnode ? ( - {fnode.shortname} + + {fnode.shortname} + ) : ( UNK )} {tnode ? ( - {tnode.shortname} + + {tnode.shortname} + ) : ( UNK )} @@ -82,7 +109,12 @@ export const Traceroutes = () => { // eslint-disable-next-line react/no-array-index-key {hnode ? ( - {hnode.shortname} + + {hnode.shortname} + ) : ( UNK )} diff --git a/frontend/src/slices/appSlice.ts b/frontend/src/slices/appSlice.ts index 7a290b9..76cdaa7 100644 --- a/frontend/src/slices/appSlice.ts +++ b/frontend/src/slices/appSlice.ts @@ -1,25 +1,14 @@ +/* eslint-disable no-param-reassign */ import { createSlice } from "@reduxjs/toolkit"; +interface InitialState {} + +const initialState: InitialState = {}; + export const appSlice = createSlice({ name: "app", - initialState: { - value: 7, - }, - reducers: { - increment: (state) => { - // Redux Toolkit allows us to write "mutating" logic in reducers. It - // doesn't actually mutate the state because it uses the immer library, - // which detects changes to a "draft state" and produces a brand new - // immutable state based off those changes - state.value += 1; - }, - decrement: (state) => { - state.value -= 1; - }, - incrementByAmount: (state, action) => { - state.value += action.payload; - }, - }, + initialState, + reducers: {}, }); -export const { increment, decrement, incrementByAmount } = appSlice.actions; +export const {} = appSlice.actions;