diff --git a/package.json b/package.json index 120f795c..29aaa51f 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "@emeraldpay/hashicon-react": "^0.5.2", "@floating-ui/react-dom": "^0.4.3", "@meshtastic/components": "^1.0.23", - "@meshtastic/meshtasticjs": "^0.6.43", + "@meshtastic/meshtasticjs": "^0.6.45", "@reduxjs/toolkit": "^1.7.2", "base64-js": "^1.5.1", "framer-motion": "^6.2.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e2505cb6..fa8652f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,7 +4,7 @@ specifiers: '@emeraldpay/hashicon-react': ^0.5.2 '@floating-ui/react-dom': ^0.4.3 '@meshtastic/components': ^1.0.23 - '@meshtastic/meshtasticjs': ^0.6.43 + '@meshtastic/meshtasticjs': ^0.6.45 '@reduxjs/toolkit': ^1.7.2 '@types/mapbox-gl': ^2.6.1 '@types/react': ^17.0.39 @@ -62,7 +62,7 @@ dependencies: '@emeraldpay/hashicon-react': 0.5.2 '@floating-ui/react-dom': 0.4.3_b8fdba992ce7d797017dc07106486496 '@meshtastic/components': 1.0.23_@types+react@17.0.39 - '@meshtastic/meshtasticjs': 0.6.43 + '@meshtastic/meshtasticjs': 0.6.45 '@reduxjs/toolkit': 1.7.2_react-redux@7.2.6+react@17.0.2 base64-js: 1.5.1 framer-motion: 6.2.6_react-dom@17.0.2+react@17.0.2 @@ -1587,8 +1587,8 @@ packages: - '@types/react' dev: false - /@meshtastic/meshtasticjs/0.6.43: - resolution: {integrity: sha512-INI9hj3AzjkXzJIp2yq65eV908wTCk6Ih5/5fMknKhwOgx14eC6d5qhlWxjC85kHB6gu8c/2KF3LUCFKHh+1fg==} + /@meshtastic/meshtasticjs/0.6.45: + resolution: {integrity: sha512-icAGMofpQ3hYqWhjYMLqMyhb0Xtk3GozEgOXScFTKVOaecDY0XIJmuvoBDfgD2lxNxDDPr0Dj77js+3JGxTcRg==} dependencies: '@protobuf-ts/runtime': 2.2.2 sub-events: 1.8.9 diff --git a/public/placeholders/Files Dark.svg b/public/placeholders/Files Dark.svg new file mode 100644 index 00000000..ffecedc3 --- /dev/null +++ b/public/placeholders/Files Dark.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/placeholders/Files.svg b/public/placeholders/Files.svg new file mode 100644 index 00000000..f306c952 --- /dev/null +++ b/public/placeholders/Files.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/placeholders/View Code Dark.svg b/public/placeholders/View Code Dark.svg new file mode 100644 index 00000000..0ead22d1 --- /dev/null +++ b/public/placeholders/View Code Dark.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/placeholders/View Code.svg b/public/placeholders/View Code.svg new file mode 100644 index 00000000..b46b0d34 --- /dev/null +++ b/public/placeholders/View Code.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/App.tsx b/src/App.tsx index 587ba910..693dac59 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,6 +5,7 @@ import { Connection } from '@components/Connection'; import { useRoute } from '@core/router'; import { useAppSelector } from '@hooks/useAppSelector'; +import { ContextMenu } from './components/generic/ContextMenu'; import { BottomNav } from './components/menu/BottomNav'; import { Extensions } from './pages/Extensions/Index'; import { Messages } from './pages/Messages'; @@ -17,17 +18,19 @@ export const App = (): JSX.Element => { return (
- -
-
- {route.name === 'messages' && } - {route.name === 'nodes' && } - {route.name === 'map' && } - {route.name === 'extensions' && } - {route.name === false && } + + +
+
+ {route.name === 'messages' && } + {route.name === 'nodes' && } + {route.name === 'map' && } + {route.name === 'extensions' && } + {route.name === false && } +
+
- -
+
); }; diff --git a/src/components/generic/ContextMenu.tsx b/src/components/generic/ContextMenu.tsx new file mode 100644 index 00000000..d3c11808 --- /dev/null +++ b/src/components/generic/ContextMenu.tsx @@ -0,0 +1,93 @@ +import React from 'react'; + +import { m } from 'framer-motion'; +import { FiActivity, FiAperture, FiTag } from 'react-icons/fi'; + +export interface ContextMenuProps { + children: React.ReactNode; +} + +export const ContextMenu = ({ children }: ContextMenuProps): JSX.Element => { + const [visible, setVisible] = React.useState(false); + const [position, setPosition] = React.useState({ x: 0, y: 0 }); + const [selectedValue, setSelectedValue] = React.useState(); + const doSomething = (selectedValue: string) => { + setSelectedValue(selectedValue); + }; + + const showContextMenu = (event: React.MouseEvent) => { + event.preventDefault(); + + setVisible(false); + const newPosition = { + x: event.pageX, + y: event.pageY, + }; + + setPosition(newPosition); + setVisible(true); + }; + + const hideContextMenu = (event: React.MouseEvent) => { + setVisible(false); + }; + + return ( +
+ {children} + {selectedValue &&

{selectedValue} is selected

} + + {visible && ( +
+
+ +
+ +
+
Menu item
+
+
+ +
+ +
+ +
+
Menu item 2
+
+
+ +
+ +
+ +
+
+ Menu item 3 with a very long name that should wrap +
+
+
+
+ )} +
+ ); +}; diff --git a/src/core/slices/meshtasticSlice.ts b/src/core/slices/meshtasticSlice.ts index a0a356d7..36fdf9b9 100644 --- a/src/core/slices/meshtasticSlice.ts +++ b/src/core/slices/meshtasticSlice.ts @@ -85,6 +85,8 @@ export const meshtasticSlice = createSlice({ initialState, reducers: { addLogEvent: (state, action: PayloadAction) => { + console.log(action.payload.packet); + state.logs.push(action.payload); }, setDeviceStatus: (state, action: PayloadAction) => { diff --git a/src/pages/Extensions/FileBrowser.tsx b/src/pages/Extensions/FileBrowser.tsx index bc7e9b9a..7c04f45b 100644 --- a/src/pages/Extensions/FileBrowser.tsx +++ b/src/pages/Extensions/FileBrowser.tsx @@ -1,5 +1,6 @@ import React from 'react'; +import { AnimatePresence, m } from 'framer-motion'; import useSWR from 'swr'; import fetcher from '@app/core/utils/fetcher'; @@ -27,6 +28,7 @@ export const FileBrowser = (): JSX.Element => { const connectionParams = useAppSelector( (state) => state.app.connectionParams, ); + const darkMode = useAppSelector((state) => state.app.darkMode); const { data } = useSWR( `${connectionParams.HTTP.tls ? 'https' : 'http'}://${ @@ -42,7 +44,22 @@ export const FileBrowser = (): JSX.Element => {
FileName
Actions
-
+
+ + {(!data || data?.data.files.length === 0) && ( +
+ +
+ )} +
{data?.data.files.map((file) => (
{ const logs = useAppSelector((state) => state.meshtastic.logs); + const darkMode = useAppSelector((state) => state.app.darkMode); type lookupType = { [key: number]: string }; @@ -54,6 +55,21 @@ export const Logs = (): JSX.Element => { className=" block h-full flex-col overflow-y-auto py-4 px-2 font-mono text-xs dark:text-gray-400" > + + {logs.length === 0 && ( +
+ +
+ )} +
{logs.map((log, index) => ( { [{Protobuf.LogRecord_Level[log.level]}]{/*
*/} + + + {log.message} ))}