diff --git a/web/src/components/ConnectionStatus.tsx b/web/src/components/ConnectionStatus.tsx index 6012f64..a474298 100644 --- a/web/src/components/ConnectionStatus.tsx +++ b/web/src/components/ConnectionStatus.tsx @@ -48,7 +48,7 @@ export const ConnectionStatus: React.FC = ({ const { icon, text, colorClass } = getStatusInfo(); return ( -
+
{icon} {text} diff --git a/web/src/components/Nav.tsx b/web/src/components/Nav.tsx index 40de034..d1d7806 100644 --- a/web/src/components/Nav.tsx +++ b/web/src/components/Nav.tsx @@ -75,8 +75,6 @@ export const Nav: React.FC = ({ connectionStatus }) => { - -
diff --git a/web/src/components/PacketList.tsx b/web/src/components/PacketList.tsx index 4327930..11a7a44 100644 --- a/web/src/components/PacketList.tsx +++ b/web/src/components/PacketList.tsx @@ -2,45 +2,48 @@ import React, { useState, useEffect, useCallback } from "react"; import { useAppSelector, useAppDispatch } from "../hooks"; import { PacketRenderer } from "./packets/PacketRenderer"; import { StreamControl } from "./StreamControl"; -import { Trash2, RefreshCw, Archive } from "lucide-react"; +import { Trash2, RefreshCw, Archive, Radio } from "lucide-react"; import { clearPackets, toggleStreamPause } from "../store/slices/packetSlice"; import { Packet } from "../lib/types"; +import { Separator } from "./Separator"; // Number of packets to show per page const PACKETS_PER_PAGE = 10; export const PacketList: React.FC = () => { - const { packets, bufferedPackets, loading, error, streamPaused } = useAppSelector( - (state) => state.packets - ); + const { packets, bufferedPackets, loading, error, streamPaused } = + useAppSelector((state) => state.packets); const dispatch = useAppDispatch(); const [currentPage, setCurrentPage] = useState(1); - + // Generate a reproducible hash code for a string const hashString = useCallback((str: string): string => { let hash = 0; for (let i = 0; i < str.length; i++) { const char = str.charCodeAt(i); - hash = ((hash << 5) - hash) + char; + hash = (hash << 5) - hash + char; hash = hash & hash; // Convert to 32bit integer } // Make sure hash is always positive and convert to string return Math.abs(hash).toString(36); }, []); - + // Create a packet key using data.id and from address // This should match the key generation logic in the reducer - const createPacketKey = useCallback((packet: Packet): string => { - if (packet.data.id !== undefined && packet.data.from !== undefined) { - // Use Meshtastic node ID format (! followed by lowercase hex) and packet ID - const nodeId = `!${packet.data.from.toString(16).toLowerCase()}`; - return `${nodeId}_${packet.data.id}`; - } else { - // Fallback to hash-based key if no ID or from (should be rare) - return `hash_${hashString(JSON.stringify(packet))}`; - } - }, [hashString]); - + const createPacketKey = useCallback( + (packet: Packet): string => { + if (packet.data.id !== undefined && packet.data.from !== undefined) { + // Use Meshtastic node ID format (! followed by lowercase hex) and packet ID + const nodeId = `!${packet.data.from.toString(16).toLowerCase()}`; + return `${nodeId}_${packet.data.id}`; + } else { + // Fallback to hash-based key if no ID or from (should be rare) + return `hash_${hashString(JSON.stringify(packet))}`; + } + }, + [hashString] + ); + // We don't need to track packet keys in state anymore since we use data.id // and it's deterministic - removing this effect to prevent the infinite loop issue @@ -97,14 +100,10 @@ export const PacketList: React.FC = () => { return (
-
-

- Packets{" "} - - ({packets.length} total) - -

- +
+
+ {packets.length} packets received, since 6:00am +
{/* Show buffered count when paused */} {streamPaused && bufferedPackets.length > 0 && ( @@ -123,13 +122,14 @@ export const PacketList: React.FC = () => { {/* Clear button */}
+
    {currentPackets.map((packet, index) => ( @@ -156,7 +156,9 @@ export const PacketList: React.FC = () => { {totalPages > 1 && (
    ); -}; \ No newline at end of file +}; diff --git a/web/src/components/PageWrapper.tsx b/web/src/components/PageWrapper.tsx index 941076e..4fb2fe3 100644 --- a/web/src/components/PageWrapper.tsx +++ b/web/src/components/PageWrapper.tsx @@ -2,24 +2,15 @@ import React, { ReactNode } from "react"; interface PageWrapperProps { children: ReactNode; - title?: string; } /** * A consistent page wrapper component for all leaf routes */ -export const PageWrapper: React.FC = ({ - children, - title, -}) => { +export const PageWrapper: React.FC = ({ children }) => { return ( -
    - {title && ( -

    {title}

    - )} -
    - {children} -
    +
    + {children}
    ); }; diff --git a/web/src/components/Separator.tsx b/web/src/components/Separator.tsx index 3a06954..0303a9a 100644 --- a/web/src/components/Separator.tsx +++ b/web/src/components/Separator.tsx @@ -1,3 +1,4 @@ +import { cn } from "@/lib/cn"; import React from "react"; interface SeparatorProps { @@ -7,7 +8,10 @@ interface SeparatorProps { export const Separator: React.FC = ({ className = "" }) => { return (
    ); }; diff --git a/web/src/components/StreamControl.tsx b/web/src/components/StreamControl.tsx index 76531a5..2e72975 100644 --- a/web/src/components/StreamControl.tsx +++ b/web/src/components/StreamControl.tsx @@ -13,7 +13,7 @@ export const StreamControl: React.FC = ({ return ( ); -}; \ No newline at end of file +}; diff --git a/web/src/components/packets/PacketCard.tsx b/web/src/components/packets/PacketCard.tsx index 2f28d60..2a34309 100644 --- a/web/src/components/packets/PacketCard.tsx +++ b/web/src/components/packets/PacketCard.tsx @@ -19,7 +19,7 @@ export const PacketCard: React.FC = ({ const { data } = packet; return ( -
    +
    {icon}
    diff --git a/web/src/routes/__root.tsx b/web/src/routes/__root.tsx index 68bd453..1a0eab9 100644 --- a/web/src/routes/__root.tsx +++ b/web/src/routes/__root.tsx @@ -28,14 +28,14 @@ export default function Root() { }, []); return ( -
    +
    {/* Sidebar Navigation */}
    ); -} \ No newline at end of file +} diff --git a/web/src/routes/home.tsx b/web/src/routes/home.tsx index 28ed040..8c34d14 100644 --- a/web/src/routes/home.tsx +++ b/web/src/routes/home.tsx @@ -3,7 +3,7 @@ import { SITE_TITLE } from "../lib/config"; export function IndexPage() { return ( - +

    This application provides a real-time view of Meshtastic network @@ -42,4 +42,4 @@ export function IndexPage() {

    ); -} \ No newline at end of file +} diff --git a/web/src/styles/index.css b/web/src/styles/index.css index 63cdc7e..30aef0d 100644 --- a/web/src/styles/index.css +++ b/web/src/styles/index.css @@ -38,4 +38,12 @@ @apply rounded-md; @apply shadow-md; } + .effect-outset { + @apply shadow-inner; + @apply [box-shadow:inset_0_1px_0_0_rgba(255,255,255,0.15),inset_0_-1px_0_0_rgba(0,0,0,0.3)]; + } + .effect-inset { + @apply shadow-inner; + @apply [box-shadow:inset_0_1px_2px_0_rgba(0,0,0,0.3),inset_0_-1px_1px_0_rgba(255,255,255,0.15)]; + } } \ No newline at end of file