New UI colors and changes
This commit is contained in:
+9
-19
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -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" />}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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)},
|
||||
{(node.currentPosition?.longitudeI / 1e7).toPrecision(6)}
|
||||
</div>
|
||||
<IconButton
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user