Merge branch 'master' into add_search_nodes
This commit is contained in:
@@ -20,7 +20,7 @@ export const getChannelName = (channel: Protobuf.Channel.Channel) =>
|
||||
? "Primary"
|
||||
: `Ch ${channel.index}`;
|
||||
|
||||
export const ChannelsPage = (): JSX.Element => {
|
||||
const ChannelsPage = () => {
|
||||
const { channels, setDialogOpen } = useDevice();
|
||||
const [activeChannel, setActiveChannel] = useState<Types.ChannelNumber>(
|
||||
Types.ChannelNumber.Primary,
|
||||
@@ -69,3 +69,4 @@ export const ChannelsPage = (): JSX.Element => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default ChannelsPage;
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ModuleConfig } from "@pages/Config/ModuleConfig.tsx";
|
||||
import { BoxesIcon, SaveIcon, SettingsIcon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
export const ConfigPage = (): JSX.Element => {
|
||||
const ConfigPage = (): JSX.Element => {
|
||||
const { workingConfig, workingModuleConfig, connection } = useDevice();
|
||||
const [activeConfigSection, setActiveConfigSection] = useState<
|
||||
"device" | "module"
|
||||
@@ -72,3 +72,5 @@ export const ConfigPage = (): JSX.Element => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConfigPage;
|
||||
|
||||
@@ -15,8 +15,9 @@ import {
|
||||
import { useMemo } from "react";
|
||||
|
||||
export const Dashboard = () => {
|
||||
const { setConnectDialogOpen } = useAppStore();
|
||||
const { setConnectDialogOpen, setSelectedDevice } = useAppStore();
|
||||
const { getDevices } = useDeviceStore();
|
||||
const { darkMode } = useAppStore();
|
||||
|
||||
const devices = useMemo(() => getDevices(), [getDevices]);
|
||||
|
||||
@@ -38,7 +39,13 @@ export const Dashboard = () => {
|
||||
{devices.map((device) => {
|
||||
return (
|
||||
<li key={device.id}>
|
||||
<div className="px-4 py-4 sm:px-6">
|
||||
<button
|
||||
type="button"
|
||||
className={`w-full px-4 py-4 sm:px-6 ${darkMode ? "hover:bg-slate-800 focus:bg-slate-400 active:bg-slate-600" : "hover:bg-slate-50 focus:bg-slate-50 active:bg-slate-100"}`}
|
||||
onClick={() => {
|
||||
setSelectedDevice(device.id);
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="truncate text-sm font-medium text-accent">
|
||||
{device.nodes.get(device.hardware.myNodeNum)?.user
|
||||
@@ -75,7 +82,7 @@ export const Dashboard = () => {
|
||||
{device.nodes.size === 0 ? 0 : device.nodes.size - 1}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
||||
+40
-12
@@ -1,3 +1,5 @@
|
||||
import { NodeDetail } from "@app/components/PageComponents/Map/NodeDetail";
|
||||
import { Avatar } from "@app/components/UI/Avatar";
|
||||
import { Subtle } from "@app/components/UI/Typography/Subtle.tsx";
|
||||
import { cn } from "@app/core/utils/cn.ts";
|
||||
import { PageLayout } from "@components/PageLayout.tsx";
|
||||
@@ -6,7 +8,7 @@ import { SidebarSection } from "@components/UI/Sidebar/SidebarSection.tsx";
|
||||
import { SidebarButton } from "@components/UI/Sidebar/sidebarButton.tsx";
|
||||
import { useAppStore } from "@core/stores/appStore.ts";
|
||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||
import { Hashicon } from "@emeraldpay/hashicon-react";
|
||||
import type { Protobuf } from "@meshtastic/js";
|
||||
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
||||
import { bbox, lineString } from "@turf/turf";
|
||||
import {
|
||||
@@ -15,18 +17,20 @@ import {
|
||||
ZoomInIcon,
|
||||
ZoomOutIcon,
|
||||
} from "lucide-react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { Marker, useMap } from "react-map-gl";
|
||||
import { type JSX, useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { AttributionControl, Marker, Popup, useMap } from "react-map-gl";
|
||||
import MapGl from "react-map-gl/maplibre";
|
||||
|
||||
export const MapPage = (): JSX.Element => {
|
||||
const MapPage = (): JSX.Element => {
|
||||
const { nodes, waypoints } = useDevice();
|
||||
const { rasterSources, darkMode } = useAppStore();
|
||||
const { default: map } = useMap();
|
||||
|
||||
const [zoom, setZoom] = useState(0);
|
||||
const [selectedNode, setSelectedNode] =
|
||||
useState<Protobuf.Mesh.NodeInfo | null>(null);
|
||||
|
||||
const allNodes = Array.from(nodes.values());
|
||||
const allNodes = useMemo(() => Array.from(nodes.values()), [nodes]);
|
||||
|
||||
const getBBox = useCallback(() => {
|
||||
if (!map) {
|
||||
@@ -126,13 +130,12 @@ export const MapPage = (): JSX.Element => {
|
||||
// }}
|
||||
|
||||
// @ts-ignore
|
||||
|
||||
attributionControl={false}
|
||||
renderWorldCopies={false}
|
||||
maxPitch={0}
|
||||
style={{
|
||||
filter: darkMode
|
||||
? "brightness(0.6) invert(1) contrast(3) hue-rotate(200deg) saturate(0.3) brightness(0.7)"
|
||||
: "",
|
||||
filter: darkMode ? "brightness(0.8)" : "",
|
||||
}}
|
||||
dragRotate={false}
|
||||
touchZoomRotate={false}
|
||||
@@ -142,6 +145,12 @@ export const MapPage = (): JSX.Element => {
|
||||
longitude: 0,
|
||||
}}
|
||||
>
|
||||
<AttributionControl
|
||||
style={{
|
||||
background: darkMode ? "#ffffff" : "",
|
||||
color: darkMode ? "black" : "",
|
||||
}}
|
||||
/>
|
||||
{waypoints.map((wp) => (
|
||||
<Marker
|
||||
key={wp.id}
|
||||
@@ -160,15 +169,16 @@ export const MapPage = (): JSX.Element => {
|
||||
</Source>
|
||||
))} */}
|
||||
{allNodes.map((node) => {
|
||||
if (node.position?.latitudeI) {
|
||||
if (node.position?.latitudeI && node.num !== selectedNode?.num) {
|
||||
return (
|
||||
<Marker
|
||||
key={node.num}
|
||||
longitude={(node.position.longitudeI ?? 0) / 1e7}
|
||||
latitude={(node.position.latitudeI ?? 0) / 1e7}
|
||||
style={{ filter: darkMode ? "invert(1)" : "" }}
|
||||
// style={{ filter: darkMode ? "invert(1)" : "" }}
|
||||
anchor="bottom"
|
||||
onClick={() => {
|
||||
setSelectedNode(node);
|
||||
map?.easeTo({
|
||||
zoom: 12,
|
||||
center: [
|
||||
@@ -178,8 +188,13 @@ export const MapPage = (): JSX.Element => {
|
||||
});
|
||||
}}
|
||||
>
|
||||
<div className="flex cursor-pointer gap-2 rounded-md border bg-backgroundPrimary p-1.5">
|
||||
<Hashicon value={node.num.toString()} size={22} />
|
||||
<div className="flex cursor-pointer gap-2 rounded-md bg-transparent p-1.5">
|
||||
<Avatar
|
||||
text={
|
||||
node.user?.shortName.toString() ?? node.num.toString()
|
||||
}
|
||||
size="sm"
|
||||
/>
|
||||
<Subtle className={cn(zoom < 12 && "hidden")}>
|
||||
{node.user?.longName ||
|
||||
`!${numberToHexUnpadded(node.num)}`}
|
||||
@@ -189,8 +204,21 @@ export const MapPage = (): JSX.Element => {
|
||||
);
|
||||
}
|
||||
})}
|
||||
{selectedNode?.position && (
|
||||
<Popup
|
||||
longitude={(selectedNode.position.longitudeI ?? 0) / 1e7}
|
||||
latitude={(selectedNode.position.latitudeI ?? 0) / 1e7}
|
||||
anchor="left"
|
||||
closeOnClick={false}
|
||||
onClose={() => setSelectedNode(null)}
|
||||
>
|
||||
<NodeDetail node={selectedNode} />
|
||||
</Popup>
|
||||
)}
|
||||
</MapGl>
|
||||
</PageLayout>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MapPage;
|
||||
|
||||
+27
-16
@@ -1,18 +1,18 @@
|
||||
import { ChannelChat } from "@components/PageComponents/Messages/ChannelChat.tsx";
|
||||
import { PageLayout } from "@components/PageLayout.tsx";
|
||||
import { Sidebar } from "@components/Sidebar.tsx";
|
||||
import { Avatar } from "@components/UI/Avatar.tsx";
|
||||
import { SidebarSection } from "@components/UI/Sidebar/SidebarSection.tsx";
|
||||
import { SidebarButton } from "@components/UI/Sidebar/sidebarButton.tsx";
|
||||
import { useToast } from "@core/hooks/useToast.ts";
|
||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||
import { Hashicon } from "@emeraldpay/hashicon-react";
|
||||
import { Device, useDevice, useDeviceStore } from "@core/stores/deviceStore.ts";
|
||||
import { Protobuf, Types } from "@meshtastic/js";
|
||||
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
||||
import { getChannelName } from "@pages/Channels.tsx";
|
||||
import { HashIcon, LockIcon, LockOpenIcon, WaypointsIcon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
export const MessagesPage = (): JSX.Element => {
|
||||
const MessagesPage = () => {
|
||||
const { channels, nodes, hardware, messages, traceroutes, connection } =
|
||||
useDevice();
|
||||
const [chatType, setChatType] =
|
||||
@@ -68,18 +68,27 @@ export const MessagesPage = (): JSX.Element => {
|
||||
className="w-full p-2 border border-gray-300 rounded bg-white text-black"
|
||||
/>
|
||||
</div>
|
||||
{filteredNodes.map((node) => (
|
||||
<SidebarButton
|
||||
key={node.num}
|
||||
label={node.user?.longName ?? `!${numberToHexUnpadded(node.num)}`}
|
||||
active={activeChat === node.num}
|
||||
onClick={() => {
|
||||
setChatType("direct");
|
||||
setActiveChat(node.num);
|
||||
}}
|
||||
element={<Hashicon size={20} value={node.num.toString()} />}
|
||||
/>
|
||||
))}
|
||||
<div className="flex flex-col gap-4">
|
||||
{filteredNodes.map((node) => (
|
||||
<SidebarButton
|
||||
key={node.num}
|
||||
label={
|
||||
node.user?.longName ?? `!${numberToHexUnpadded(node.num)}`
|
||||
}
|
||||
active={activeChat === node.num}
|
||||
onClick={() => {
|
||||
setChatType("direct");
|
||||
setActiveChat(node.num);
|
||||
}}
|
||||
element={
|
||||
<Avatar
|
||||
text={node.user?.shortName ?? node.num.toString()}
|
||||
size="sm"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</SidebarSection>
|
||||
</Sidebar>
|
||||
<div className="flex flex-col flex-grow">
|
||||
@@ -88,7 +97,7 @@ export const MessagesPage = (): JSX.Element => {
|
||||
chatType === "broadcast" && currentChannel
|
||||
? getChannelName(currentChannel)
|
||||
: chatType === "direct" && nodes.get(activeChat)
|
||||
? nodes.get(activeChat)?.user?.longName ?? nodeHex
|
||||
? (nodes.get(activeChat)?.user?.longName ?? nodeHex)
|
||||
: "Loading..."
|
||||
}`}
|
||||
actions={
|
||||
@@ -158,3 +167,5 @@ export const MessagesPage = (): JSX.Element => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MessagesPage;
|
||||
|
||||
+9
-4
@@ -6,12 +6,11 @@ import { Mono } from "@components/generic/Mono.tsx";
|
||||
import { Table } from "@components/generic/Table/index.tsx";
|
||||
import { TimeAgo } from "@components/generic/Table/tmp/TimeAgo.tsx";
|
||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||
import { Hashicon } from "@emeraldpay/hashicon-react";
|
||||
import { Protobuf } from "@meshtastic/js";
|
||||
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
||||
import { LockIcon, LockOpenIcon, TrashIcon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { Fragment } from "react";
|
||||
import { Fragment, type JSX } from "react";
|
||||
import { base16 } from "rfc4648";
|
||||
|
||||
export interface DeleteNoteDialogProps {
|
||||
@@ -19,7 +18,7 @@ export interface DeleteNoteDialogProps {
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}
|
||||
|
||||
export const NodesPage = (): JSX.Element => {
|
||||
const NodesPage = (): JSX.Element => {
|
||||
const { nodes, hardware, setDialogOpen } = useDevice();
|
||||
const { setNodeNumToBeRemoved } = useAppStore();
|
||||
const [searchTerm, setSearchTerm] = useState<string>("");
|
||||
@@ -57,7 +56,11 @@ export const NodesPage = (): JSX.Element => {
|
||||
{ title: "Remove", type: "normal", sortable: false },
|
||||
]}
|
||||
rows={filteredNodes.map((node) => [
|
||||
<Hashicon key="icon" size={24} value={node.num.toString()} />,
|
||||
<span
|
||||
key={node.num}
|
||||
className="h-3 w-3 rounded-full bg-accent"
|
||||
/>,
|
||||
|
||||
<h1 key="header">
|
||||
{node.user?.longName ??
|
||||
(node.user?.macaddr
|
||||
@@ -124,3 +127,5 @@ export const NodesPage = (): JSX.Element => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NodesPage;
|
||||
|
||||
Reference in New Issue
Block a user