New UI colors and changes

This commit is contained in:
Sacha Weatherstone
2022-01-15 22:11:55 +11:00
parent 5b10d4de59
commit 5f2503976d
13 changed files with 239 additions and 193 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "meshtastic-web",
"version": "1.0",
"version": "1.0.0",
"description": "Meshtastic web client",
"license": "GPL-3.0-only",
"scripts": {
@@ -13,8 +13,8 @@
},
"dependencies": {
"@floating-ui/react-dom": "^0.4.3",
"@headlessui/react": "^1.4.2",
"@meshtastic/components": "^1.0.15",
"@headlessui/react": "^1.4.3",
"@meshtastic/components": "^1.0.17",
"@meshtastic/meshtasticjs": "^0.6.38",
"@reduxjs/toolkit": "^1.7.1",
"base64-js": "^1.5.1",
@@ -26,7 +26,7 @@
"react-dom": "^17.0.2",
"react-error-boundary": "^3.1.4",
"react-file-icon": "^1.1.0",
"react-hook-form": "^7.23.0",
"react-hook-form": "^7.24.0",
"react-i18next": "^11.15.3",
"react-icons": "^4.3.1",
"react-json-pretty": "^2.2.0",
@@ -64,7 +64,7 @@
"gzipper": "^6.2.1",
"postcss": "^8.4.5",
"prettier": "^2.5.1",
"tailwindcss": "^3.0.13",
"tailwindcss": "^3.0.15",
"tar": "^6.1.11",
"typescript": "^4.5.4",
"vite": "^2.7.12",

100
pnpm-lock.yaml generated
View File

@@ -2,8 +2,8 @@ lockfileVersion: 5.3
specifiers:
'@floating-ui/react-dom': ^0.4.3
'@headlessui/react': ^1.4.2
'@meshtastic/components': ^1.0.15
'@headlessui/react': ^1.4.3
'@meshtastic/components': ^1.0.17
'@meshtastic/meshtasticjs': ^0.6.38
'@reduxjs/toolkit': ^1.7.1
'@types/mapbox-gl': ^2.6.0
@@ -38,7 +38,7 @@ specifiers:
react-dom: ^17.0.2
react-error-boundary: ^3.1.4
react-file-icon: ^1.1.0
react-hook-form: ^7.23.0
react-hook-form: ^7.24.0
react-i18next: ^11.15.3
react-icons: ^4.3.1
react-json-pretty: ^2.2.0
@@ -48,7 +48,7 @@ specifiers:
react-use-clipboard: ^1.0.7
rfc4648: ^1.5.1
swr: ^1.1.2
tailwindcss: ^3.0.13
tailwindcss: ^3.0.15
tar: ^6.1.11
timeago-react: ^3.0.4
type-route: ^0.6.0
@@ -61,8 +61,8 @@ specifiers:
dependencies:
'@floating-ui/react-dom': 0.4.3_b3482aaf5744fc7c2aeb7941b0e0a78f
'@headlessui/react': 1.4.2_react-dom@17.0.2+react@17.0.2
'@meshtastic/components': 1.0.15_@types+react@17.0.38
'@headlessui/react': 1.4.3_react-dom@17.0.2+react@17.0.2
'@meshtastic/components': 1.0.17_@types+react@17.0.38
'@meshtastic/meshtasticjs': 0.6.38
'@reduxjs/toolkit': 1.7.1_react-redux@7.2.6+react@17.0.2
base64-js: 1.5.1
@@ -74,7 +74,7 @@ dependencies:
react-dom: 17.0.2_react@17.0.2
react-error-boundary: 3.1.4_react@17.0.2
react-file-icon: 1.1.0_react-dom@17.0.2+react@17.0.2
react-hook-form: 7.23.0_react@17.0.2
react-hook-form: 7.24.0_react@17.0.2
react-i18next: 11.15.3_bc514be083f1f06b28df24d5713fc600
react-icons: 4.3.1_react@17.0.2
react-json-pretty: 2.2.0_react-dom@17.0.2+react@17.0.2
@@ -112,7 +112,7 @@ devDependencies:
gzipper: 6.2.1
postcss: 8.4.5
prettier: 2.5.1
tailwindcss: 3.0.13_ef48b3b8837f8a23677bffe8f9cd866d
tailwindcss: 3.0.15_ef48b3b8837f8a23677bffe8f9cd866d
tar: 6.1.11
typescript: 4.5.4
vite: 2.7.12
@@ -1443,8 +1443,8 @@ packages:
- '@types/react'
dev: false
/@headlessui/react/1.4.2_react-dom@17.0.2+react@17.0.2:
resolution: {integrity: sha512-N8tv7kLhg9qGKBkVdtg572BvKvWhmiudmeEpOCyNwzOsZHCXBtl8AazGikIfUS+vBoub20Fse3BjawXDVPPdug==}
/@headlessui/react/1.4.3_react-dom@17.0.2+react@17.0.2:
resolution: {integrity: sha512-n2IQkaaw0aAAlQS5MEXsM4uRK+w18CrM72EqnGRl/UBOQeQajad8oiKXR9Nk15jOzTFQjpxzrZMf1NxHidFBiw==}
engines: {node: '>=10'}
peerDependencies:
react: ^16 || ^17 || ^18
@@ -1524,8 +1524,8 @@ packages:
engines: {node: '>=6.0.0'}
dev: false
/@meshtastic/components/1.0.15_@types+react@17.0.38:
resolution: {integrity: sha512-+ZT2I6shgtDTKBm3qpillRvG89wDxDf4gpD/EDhvECAjSTIFYjo0m3kiDSytVjJw/sLnj3LJljQ3U4o75J3uqw==}
/@meshtastic/components/1.0.17_@types+react@17.0.38:
resolution: {integrity: sha512-e9ETFrzQUtpxVHc6NiiYMCkr7Ml4v7xlbILWK3LV48ALMDojBAFKLHdxuClpt0Rszo91ORACSSVpUkJNfWnp1A==}
dependencies:
inter-ui: 3.19.3
react: 17.0.2
@@ -1588,7 +1588,7 @@ packages:
reselect: 4.1.5
dev: false
/@rollup/plugin-babel/5.3.0_@babel+core@7.16.7+rollup@2.63.0:
/@rollup/plugin-babel/5.3.0_@babel+core@7.16.7+rollup@2.64.0:
resolution: {integrity: sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw==}
engines: {node: '>= 10.0.0'}
peerDependencies:
@@ -1601,36 +1601,36 @@ packages:
dependencies:
'@babel/core': 7.16.7
'@babel/helper-module-imports': 7.16.7
'@rollup/pluginutils': 3.1.0_rollup@2.63.0
rollup: 2.63.0
'@rollup/pluginutils': 3.1.0_rollup@2.64.0
rollup: 2.64.0
dev: true
/@rollup/plugin-node-resolve/11.2.1_rollup@2.63.0:
/@rollup/plugin-node-resolve/11.2.1_rollup@2.64.0:
resolution: {integrity: sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==}
engines: {node: '>= 10.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0
dependencies:
'@rollup/pluginutils': 3.1.0_rollup@2.63.0
'@rollup/pluginutils': 3.1.0_rollup@2.64.0
'@types/resolve': 1.17.1
builtin-modules: 3.2.0
deepmerge: 4.2.2
is-module: 1.0.0
resolve: 1.21.0
rollup: 2.63.0
rollup: 2.64.0
dev: true
/@rollup/plugin-replace/2.4.2_rollup@2.63.0:
/@rollup/plugin-replace/2.4.2_rollup@2.64.0:
resolution: {integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==}
peerDependencies:
rollup: ^1.20.0 || ^2.0.0
dependencies:
'@rollup/pluginutils': 3.1.0_rollup@2.63.0
'@rollup/pluginutils': 3.1.0_rollup@2.64.0
magic-string: 0.25.7
rollup: 2.63.0
rollup: 2.64.0
dev: true
/@rollup/pluginutils/3.1.0_rollup@2.63.0:
/@rollup/pluginutils/3.1.0_rollup@2.64.0:
resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
engines: {node: '>= 8.0.0'}
peerDependencies:
@@ -1639,7 +1639,7 @@ packages:
'@types/estree': 0.0.39
estree-walker: 1.0.1
picomatch: 2.3.1
rollup: 2.63.0
rollup: 2.64.0
dev: true
/@rollup/pluginutils/4.1.2:
@@ -2313,7 +2313,7 @@ packages:
hasBin: true
dependencies:
caniuse-lite: 1.0.30001299
electron-to-chromium: 1.4.45
electron-to-chromium: 1.4.46
escalade: 3.1.1
node-releases: 2.0.1
picocolors: 1.0.0
@@ -2559,7 +2559,7 @@ packages:
object-is: 1.1.5
object-keys: 1.1.1
object.assign: 4.1.2
regexp.prototype.flags: 1.3.2
regexp.prototype.flags: 1.4.1
side-channel: 1.0.4
which-boxed-primitive: 1.0.2
which-collection: 1.0.1
@@ -2678,8 +2678,8 @@ packages:
jake: 10.8.2
dev: true
/electron-to-chromium/1.4.45:
resolution: {integrity: sha512-czF9eYVuOmlY/vxyMQz2rGlNSjZpxNQYBe1gmQv7al171qOIhgyO9k7D5AKlgeTCSPKk+LHhj5ZyIdmEub9oNg==}
/electron-to-chromium/1.4.46:
resolution: {integrity: sha512-UtV0xUA/dibCKKP2JMxOpDtXR74zABevuUEH4K0tvduFSIoxRVcYmQsbB51kXsFTX8MmOyWMt8tuZAlmDOqkrQ==}
dev: true
/emoji-regex/8.0.0:
@@ -3350,8 +3350,8 @@ packages:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
/fast-glob/3.2.10:
resolution: {integrity: sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A==}
/fast-glob/3.2.11:
resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==}
engines: {node: '>=8.6.0'}
dependencies:
'@nodelib/fs.stat': 2.0.5
@@ -3576,7 +3576,7 @@ packages:
dependencies:
array-union: 2.1.0
dir-glob: 3.0.1
fast-glob: 3.2.10
fast-glob: 3.2.11
ignore: 5.2.0
merge2: 1.4.1
slash: 3.0.0
@@ -4707,8 +4707,8 @@ packages:
tinycolor2: 1.4.2
dev: false
/react-hook-form/7.23.0_react@17.0.2:
resolution: {integrity: sha512-bO1JCkPAjmpuKhfUpFhsjWn2RIPgWUpep8qpMAKCoc8NM8ytBA5nDx5p99wNhZWrblYQFvU+dVy9g1oYo/JKoQ==}
/react-hook-form/7.24.0_react@17.0.2:
resolution: {integrity: sha512-N2GT4wmdcgP5bw72q/a+vKUBqy14iNQz+4vaFBJLz9Bw+KNYKUjTzcV/kHfOYbcboMeHP2zgf4i4wTmAwrXssg==}
engines: {node: '>=12.22.0'}
peerDependencies:
react: ^16.8.0 || ^17
@@ -4916,8 +4916,8 @@ packages:
'@babel/runtime': 7.16.7
dev: true
/regexp.prototype.flags/1.3.2:
resolution: {integrity: sha512-uaro52GSI5be7+ssxjxxnLlleDBN3VHIWQHvBhfeeSXRQkuV/0Jo/hBU+omYH6NUkM+LYpTHnRRf2W/v+x7LzQ==}
/regexp.prototype.flags/1.4.1:
resolution: {integrity: sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
@@ -5014,22 +5014,22 @@ packages:
magic-string: 0.25.7
dev: true
/rollup-plugin-terser/7.0.2_rollup@2.63.0:
/rollup-plugin-terser/7.0.2_rollup@2.64.0:
resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==}
peerDependencies:
rollup: ^2.0.0
dependencies:
'@babel/code-frame': 7.16.7
jest-worker: 26.6.2
rollup: 2.63.0
rollup: 2.64.0
serialize-javascript: 4.0.0
terser: 5.10.0
transitivePeerDependencies:
- acorn
dev: true
/rollup/2.63.0:
resolution: {integrity: sha512-nps0idjmD+NXl6OREfyYXMn/dar3WGcyKn+KBzPdaLecub3x/LrId0wUcthcr8oZUAcZAR8NKcfGGFlNgGL1kQ==}
/rollup/2.64.0:
resolution: {integrity: sha512-+c+lbw1lexBKSMb1yxGDVfJ+vchJH3qLbmavR+awDinTDA2C5Ug9u7lkOzj62SCu0PKUExsW36tpgW7Fmpn3yQ==}
engines: {node: '>=10.0.0'}
hasBin: true
optionalDependencies:
@@ -5231,7 +5231,7 @@ packages:
get-intrinsic: 1.1.1
has-symbols: 1.0.2
internal-slot: 1.0.3
regexp.prototype.flags: 1.3.2
regexp.prototype.flags: 1.4.1
side-channel: 1.0.4
dev: true
@@ -5357,8 +5357,8 @@ packages:
strip-ansi: 6.0.1
dev: true
/tailwindcss/3.0.13_ef48b3b8837f8a23677bffe8f9cd866d:
resolution: {integrity: sha512-raRPGFwQSGXn/3h0ttHND9jyPYfqk/ur2NXtlQuK25+ZnrCjlH1s1j4/oPswHGMoZzGNykUVycZ/LcROanUE0A==}
/tailwindcss/3.0.15_ef48b3b8837f8a23677bffe8f9cd866d:
resolution: {integrity: sha512-bT2iy7FtjwgsXik4ZoJnHXR+SRCiGR1W95fVqpLZebr64m4ahwUwRbIAc5w5+2fzr1YF4Ct2eI7dojMRRl8sVQ==}
engines: {node: '>=12.13.0'}
hasBin: true
peerDependencies:
@@ -5374,7 +5374,7 @@ packages:
detective: 5.2.0
didyoumean: 1.2.2
dlv: 1.1.3
fast-glob: 3.2.10
fast-glob: 3.2.11
glob-parent: 6.0.2
is-glob: 4.0.3
normalize-path: 3.0.0
@@ -5690,9 +5690,9 @@ packages:
vite: ^2.0.0
dependencies:
debug: 4.3.3
fast-glob: 3.2.10
fast-glob: 3.2.11
pretty-bytes: 5.6.0
rollup: 2.63.0
rollup: 2.64.0
vite: 2.7.12
workbox-build: 6.4.2
workbox-window: 6.4.2
@@ -5721,7 +5721,7 @@ packages:
esbuild: 0.13.15
postcss: 8.4.5
resolve: 1.21.0
rollup: 2.63.0
rollup: 2.64.0
optionalDependencies:
fsevents: 2.3.2
dev: true
@@ -5826,9 +5826,9 @@ packages:
'@babel/core': 7.16.7
'@babel/preset-env': 7.16.8_@babel+core@7.16.7
'@babel/runtime': 7.16.7
'@rollup/plugin-babel': 5.3.0_@babel+core@7.16.7+rollup@2.63.0
'@rollup/plugin-node-resolve': 11.2.1_rollup@2.63.0
'@rollup/plugin-replace': 2.4.2_rollup@2.63.0
'@rollup/plugin-babel': 5.3.0_@babel+core@7.16.7+rollup@2.64.0
'@rollup/plugin-node-resolve': 11.2.1_rollup@2.64.0
'@rollup/plugin-replace': 2.4.2_rollup@2.64.0
'@surma/rollup-plugin-off-main-thread': 2.2.3
ajv: 8.8.2
common-tags: 1.8.2
@@ -5837,8 +5837,8 @@ packages:
glob: 7.2.0
lodash: 4.17.21
pretty-bytes: 5.6.0
rollup: 2.63.0
rollup-plugin-terser: 7.0.2_rollup@2.63.0
rollup: 2.64.0
rollup-plugin-terser: 7.0.2_rollup@2.64.0
source-map: 0.8.0-beta.0
source-map-url: 0.4.1
stringify-object: 3.3.0

View File

@@ -3,13 +3,8 @@ import React from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { FiBell } from 'react-icons/fi';
import { DeviceStatus } from '@app/components/menu/buttons/DeviceStatus';
import { Connection } from '@components/Connection';
import { MobileNavToggle } from '@components/menu/buttons/MobileNavToggle';
import { Notifications } from '@components/menu/buttons/Notifications';
import { ThemeToggle } from '@components/menu/buttons/ThemeToggle';
import { Logo } from '@components/menu/Logo';
import { MobileNav } from '@components/menu/MobileNav';
import { Navigation } from '@components/menu/Navigation';
import { useRoute } from '@core/router';
import { requestNotificationPermission } from '@core/utils/notifications';
@@ -23,6 +18,7 @@ import { Settings } from '@pages/settings/Index';
import { ErrorFallback } from './components/ErrorFallback';
import { MapboxProvider } from './components/MapBox/MapboxProvider';
import { BottomNav } from './components/menu/BottomNav';
import { addNotification, removeNotification } from './core/slices/appSlice';
export const App = (): JSX.Element => {
@@ -65,27 +61,20 @@ export const App = (): JSX.Element => {
return (
<div className={`h-screen w-screen ${darkMode ? 'dark' : ''}`}>
<Connection />
<div className="flex flex-col h-full bg-gray-200 dark:bg-primaryDark">
<div className="flex flex-col h-full bg-gray-200 dark:bg-secondaryDark">
<div className="flex flex-shrink-0 overflow-hidden bg-primary dark:bg-primary">
<div className="w-full overflow-hidden bg-white border-b border-gray-300 md:mt-6 md:mx-6 md:py-2 md:rounded-t-3xl dark:border-gray-600 md:shadow-md dark:bg-primaryDark">
<div className="flex items-center justify-between h-12 px-4 md:px-6">
<div className="hidden md:flex">
<div className="w-full overflow-hidden bg-white border-b border-gray-300 dark:border-gray-600 md:shadow-md dark:bg-secondaryDark">
<div className="flex items-center justify-between h-12 px-4">
<div className="flex">
<Logo />
</div>
<Navigation className="hidden md:flex" />
<MobileNavToggle />
<div className="flex items-center space-x-2">
<DeviceStatus />
<Notifications />
<ThemeToggle />
</div>
<Navigation className="flex" />
</div>
</div>
</div>
<MobileNav />
<div className="flex flex-grow w-full min-h-0 md:px-6 md:mb-6">
<div className="flex w-full bg-gray-100 md:shadow-xl md:overflow-hidden dark:bg-secondaryDark md:rounded-b-3xl">
<div className="flex flex-grow w-full min-h-0">
<div className="flex w-full bg-gray-100 md:shadow-xl md:overflow-hidden dark:bg-secondaryDark">
<ErrorBoundary FallbackComponent={ErrorFallback}>
{route.name === 'messages' && <Messages />}
{route.name === 'nodes' && (
@@ -99,6 +88,7 @@ export const App = (): JSX.Element => {
</ErrorBoundary>
</div>
</div>
<BottomNav />
</div>
</div>
);

View File

@@ -0,0 +1,97 @@
import React from 'react';
import {
FiBell,
FiBluetooth,
FiCpu,
FiGitBranch,
FiMoon,
FiSun,
FiWifi,
} from 'react-icons/fi';
import {
connType,
openConnectionModal,
setDarkModeEnabled,
} from '@app/core/slices/appSlice';
import { useAppDispatch } from '@hooks/useAppDispatch';
import { useAppSelector } from '@hooks/useAppSelector';
import { Types } from '@meshtastic/meshtasticjs';
// export interface BottomNavProps {
// }
export const BottomNav = (): JSX.Element => {
const dispatch = useAppDispatch();
const meshtasticState = useAppSelector((state) => state.meshtastic);
const appState = useAppSelector((state) => state.app);
// @ts-ignore define version string global
const version = window.__COMMIT_HASH__ as string;
return (
<div className="flex justify-between bg-white border-t border-gray-300 dark:bg-secondaryDark dark:border-gray-600">
<div
className={`flex p-1 cursor-pointer group w-min hover:bg-opacity-80 ${
[
Types.DeviceStatusEnum.DEVICE_CONNECTED,
Types.DeviceStatusEnum.DEVICE_CONFIGURED,
].includes(meshtasticState.deviceStatus)
? 'bg-primary'
: [
Types.DeviceStatusEnum.DEVICE_CONNECTING,
Types.DeviceStatusEnum.DEVICE_RECONNECTING,
Types.DeviceStatusEnum.DEVICE_CONFIGURING,
].includes(meshtasticState.deviceStatus)
? 'bg-yellow-400'
: 'bg-gray-400'
}`}
onClick={(): void => {
dispatch(dispatch(openConnectionModal()));
}}
>
{appState.connType === connType.BLE ? (
<FiBluetooth className="mr-1 p-0.5 group-active:scale-90" />
) : appState.connType === connType.SERIAL ? (
<FiCpu className="mr-1 p-0.5 group-active:scale-90" />
) : (
<FiWifi className="mr-1 p-0.5 group-active:scale-90" />
)}
<div className="text-xs font-medium truncate group-active:scale-90">
{meshtasticState.nodes.find(
(node) => node.number === meshtasticState.radio.hardware.myNodeNum,
)?.user?.longName ?? 'Disconnected'}
</div>
</div>
<div className="flex">
<a
href={`https://github.com/meshtastic/meshtastic-web/commit/${version}`}
target="_blank"
rel="noreferrer"
className="flex p-1 border-l border-gray-300 cursor-pointer select-none group dark:border-gray-600 dark:text-white hover:bg-gray-200 dark:hover:bg-primaryDark"
>
<FiGitBranch className="p-0.5 mr-1 group-active:scale-90" />
<p className="text-xs opacity-60">{version}</p>
</a>
<div className="flex p-1 border-l border-gray-300 cursor-pointer select-none group dark:border-gray-600 dark:text-white hover:bg-gray-200 dark:hover:bg-primaryDark">
<FiBell className="p-0.5 mr-1 group-active:scale-90" />
<p className="text-xs opacity-60">Example Notification</p>
</div>
<div
className="p-1 border-l border-gray-300 cursor-pointer group dark:border-gray-600 dark:text-white hover:bg-gray-200 dark:hover:bg-primaryDark"
onClick={(): void => {
dispatch(setDarkModeEnabled(!appState.darkMode));
}}
>
{appState.darkMode ? (
<FiSun className="p-0.5 group-active:scale-90" />
) : (
<FiMoon className="p-0.5 group-active:scale-90" />
)}
</div>
</div>
</div>
);
};

View File

@@ -1,36 +0,0 @@
import type React from 'react';
import { Drawer } from '@components/generic/Drawer';
import { closeMobileNav } from '@core/slices/appSlice';
import { useAppDispatch } from '@hooks/useAppDispatch';
import { useAppSelector } from '@hooks/useAppSelector';
import { Logo } from './Logo';
import { Navigation } from './Navigation';
export const MobileNav = (): JSX.Element => {
const dispatch = useAppDispatch();
const mobileNavOpen = useAppSelector((state) => state.app.mobileNavOpen);
return (
<Drawer
open={mobileNavOpen}
onClose={(): void => {
dispatch(closeMobileNav());
}}
className="z-50"
>
<div className="flex flex-col">
<div className="m-auto my-6">
<Logo />
</div>
<Navigation
onClick={(): void => {
dispatch(closeMobileNav());
}}
/>
</div>
</Drawer>
);
};

View File

@@ -1,9 +1,9 @@
import type React from 'react';
import { FiGrid, FiMessageSquare, FiPackage, FiSettings } from 'react-icons/fi';
import type { Link } from 'type-route';
import { routes, useRoute } from '@core/router';
import { Button } from '@meshtastic/components';
type DefaultDivProps = JSX.IntrinsicElements['div'];
@@ -15,51 +15,59 @@ export const Navigation = ({
...props
}: NavigationProps): JSX.Element => {
const route = useRoute();
return (
<div
className={`px-4 md:space-x-2 space-y-2 md:space-y-0 ${className}`}
{...props}
>
<div onClick={onClick}>
<Button
icon={<FiMessageSquare className="w-5 h-5" />}
active={route.name === 'messages'}
className="w-full md:w-auto"
{...routes.messages().link}
>
Messages
</Button>
</div>
<div onClick={onClick}>
<Button
icon={<FiGrid className="w-5 h-5" />}
className="w-full md:w-auto"
active={route.name === 'nodes'}
{...routes.nodes().link}
>
Nodes
</Button>
</div>
<div onClick={onClick}>
<Button
icon={<FiPackage className="w-5 h-5" />}
className="w-full md:w-auto"
active={route.name === 'plugins'}
{...routes.plugins().link}
>
Plugins
</Button>
</div>
<div onClick={onClick}>
<Button
icon={<FiSettings className="w-5 h-5" />}
className="w-full md:w-auto"
active={route.name === 'settings'}
{...routes.settings().link}
>
Settings
</Button>
</div>
<div className="flex h-full mt-2 border-t border-l border-r border-gray-300 rounded-t dark:text-white dark:border-gray-600">
<NavLink
name="Messages"
icon={
<FiMessageSquare className="w-5 h-5 my-auto group-active:scale-90" />
}
active={route.name === 'messages'}
link={routes.messages().link}
/>
<NavLink
name="Nodes"
icon={<FiGrid className="w-5 h-5 my-auto group-active:scale-90" />}
active={route.name === 'nodes'}
link={routes.nodes().link}
/>
<NavLink
name="Plugins"
icon={<FiPackage className="w-5 h-5 my-auto group-active:scale-90" />}
active={route.name === 'plugins'}
link={routes.plugins().link}
/>
<NavLink
name="Settings"
icon={<FiSettings className="w-5 h-5 my-auto group-active:scale-90" />}
active={route.name === 'settings'}
link={routes.settings().link}
/>
</div>
);
};
interface NavLinkProps {
name: string;
icon: JSX.Element;
active: boolean;
link: Link;
}
const NavLink = ({ name, icon, active, link }: NavLinkProps): JSX.Element => {
return (
<a
className={`flex h-full gap-1 p-2 cursor-pointer group hover:bg-gray-200 dark:hover:bg-primaryDark ${
active ? 'dark:bg-primaryDark bg-gray-200' : 'bg-transparent'
}`}
{...link}
>
{icon}
<div className="hidden my-auto md:flex">{name}</div>
</a>
);
};

View File

@@ -1,28 +0,0 @@
import type React from 'react';
import { FiMoon, FiSun } from 'react-icons/fi';
import { setDarkModeEnabled } from '@core/slices/appSlice';
import { useAppDispatch } from '@hooks/useAppDispatch';
import { useAppSelector } from '@hooks/useAppSelector';
import { IconButton } from '@meshtastic/components';
export const ThemeToggle = (): JSX.Element => {
const dispatch = useAppDispatch();
const darkMode = useAppSelector((state) => state.app.darkMode);
return (
<IconButton
icon={
darkMode ? (
<FiSun className="w-5 h-5" />
) : (
<FiMoon className="w-5 h-5" />
)
}
onClick={(): void => {
dispatch(setDarkModeEnabled(!darkMode));
}}
/>
);
};

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { FiXCircle } from 'react-icons/fi';
import { FiMenu, FiXCircle } from 'react-icons/fi';
import { Drawer } from '@components/generic/Drawer';
import type { SidebarItemProps } from '@components/generic/SidebarItem';
@@ -37,10 +37,11 @@ export const PageLayout = ({
}}
>
<Tab.List className="flex flex-col border-b border-gray-300 divide-y divide-gray-300 dark:divide-gray-600 dark:border-gray-600">
<div className="flex items-center justify-between m-6 mr-6">
<div className="text-4xl font-extrabold leading-none tracking-tight">
<div className="flex items-center justify-between m-4">
<div className="text-2xl font-extrabold leading-none tracking-tight">
{title}
</div>
<IconButton icon={<FiMenu />} />
<div className="md:hidden">
<IconButton
icon={<FiXCircle className="w-5 h-5" />}

View File

@@ -14,6 +14,8 @@ import { IconButton } from '@meshtastic/components';
import { NodeCard } from './NodeCard';
import { Sidebar } from './Sidebar';
// const getMarkerRadius = ():number => {}
export const Nodes = (): JSX.Element => {
const myNodeInfo = useAppSelector((state) => state.meshtastic.radio.hardware);
@@ -99,7 +101,11 @@ export const Nodes = (): JSX.Element => {
setSelectedNode(node);
setSidebarOpen(true);
}}
className="z-50 bg-blue-500 border-2 border-blue-500 rounded-full bg-opacity-30"
className={`z-50 border-2 rounded-full bg-opacity-30 ${
node.number === selectedNode?.number
? 'bg-green-500 border-green-500'
: 'bg-blue-500 border-blue-500'
}`}
>
<div className="m-4 ">
<FiMapPin className="w-5 h-5" />

View File

@@ -76,9 +76,9 @@ export const Sidebar = ({ node, closeSidebar }: SidebarProps): JSX.Element => {
<Tab.Panel className="p-2">Content 1</Tab.Panel>
<Tab.Panel className="p-2">
{node.currentPosition && (
<div className="flex justify-between h-10 px-1 bg-transparent border border-gray-300 rounded-md select-none dark:border-gray-600">
<div className="my-auto">
{(node.currentPosition.latitudeI / 1e7).toPrecision(6)},
<div className="flex justify-between h-10 px-1 text-gray-500 bg-transparent bg-gray-200 border border-gray-300 rounded-md select-none dark:border-gray-600 dark:bg-secondaryDark dark:text-gray-400 ">
<div className="px-1 my-auto">
{(node.currentPosition.latitudeI / 1e7).toPrecision(6)},&nbsp;
{(node.currentPosition?.longitudeI / 1e7).toPrecision(6)}
</div>
<IconButton

View File

@@ -74,7 +74,7 @@ export const Files = ({ navOpen, setNavOpen }: RangeTestProps): JSX.Element => {
{data.data.files.map((file: IFile) => (
<div
key={file.name}
className="flex justify-between mx-4 bg-gray-300 rounded-md dark:bg-gray-600 "
className="flex justify-between mx-4 bg-gray-300 rounded-md dark:bg-secondaryDark "
>
<div className="flex p-2 max-h-12">
<div className="flex w-12">

View File

@@ -10,8 +10,10 @@ module.exports = {
extend: {
colors: {
primary: '#67ea94',
primaryDark: '#1E293B',
secondaryDark: '#0F172A',
// primaryDark: '#1E293B',
primaryDark: '#25262C',
// secondaryDark: '#0F172A',
secondaryDark: '#1C1D23',
},
boxShadow: {
border: '0 0 0 1px #67ea94',

View File

@@ -1,3 +1,4 @@
import { execSync } from 'child_process';
import path from 'path';
import { defineConfig } from 'vite';
import importToCDN from 'vite-plugin-cdn-import';
@@ -7,6 +8,11 @@ import react from '@vitejs/plugin-react';
// https://vitejs.dev/config/
export default defineConfig({
define: {
__COMMIT_HASH__: JSON.stringify(
execSync('git rev-parse --short HEAD').toString().trim(),
),
},
plugins: [
react(),
importToCDN({