Browse Source

Add disclosure to widgets

pull/39/head
Sacha Weatherstone 4 years ago
parent
commit
41ad0c00c0
No known key found for this signature in database GPG Key ID: 7AB2D7E206124B31
  1. 2
      src/components/Card.tsx
  2. 39
      src/components/Dropdown.tsx
  3. 29
      src/components/Widgets/BatteryWidget.tsx
  4. 78
      src/components/Widgets/ConfiguringWidget.tsx
  5. 36
      src/components/Widgets/NodeInfoWidget.tsx
  6. 17
      src/components/Widgets/PeersWidget.tsx
  7. 18
      src/components/Widgets/PositionWidget.tsx

2
src/components/Card.tsx

@ -7,7 +7,7 @@ export const Card = ({
}: JSX.IntrinsicElements["div"]): JSX.Element => { }: JSX.IntrinsicElements["div"]): JSX.Element => {
return ( return (
<div <div
className={`flex overflow-hidden rounded-2xl bg-white text-sm text-black shadow-md ${ className={`flex overflow-hidden rounded-md bg-white text-sm text-black shadow-md ${
className ?? "" className ?? ""
}`} }`}
{...rest} {...rest}

39
src/components/Dropdown.tsx

@ -0,0 +1,39 @@
import type React from "react";
import { Disclosure } from "@headlessui/react";
import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/24/outline";
export interface DropdownProps {
title: string;
icon: JSX.Element;
children: React.ReactNode;
}
export const Dropdown = ({
title,
icon,
children,
}: DropdownProps): JSX.Element => {
return (
<Disclosure defaultOpen>
{({ open }) => (
<>
<Disclosure.Button className="flex h-8 justify-between bg-slate-100 px-2 hover:bg-slate-200">
<div className="my-auto flex gap-2 text-slate-700">
<div className="my-auto">{icon}</div>
<span className="text-lg font-medium">{title}</span>
</div>
<div className="my-auto text-slate-600">
{open ? (
<ChevronUpIcon className="h-5" />
) : (
<ChevronDownIcon className="h-5" />
)}
</div>
</Disclosure.Button>
<Disclosure.Panel>{children}</Disclosure.Panel>
</>
)}
</Disclosure>
);
};

29
src/components/Widgets/BatteryWidget.tsx

@ -1,8 +1,10 @@
import type React from "react"; import type React from "react";
import { BoltIcon } from "@heroicons/react/24/outline"; import { Battery100Icon, BoltIcon } from "@heroicons/react/24/outline";
import { Card } from "../Card.js"; import { Card } from "../Card.js";
import { Dropdown } from "../Dropdown.js";
import { Mono } from "../Mono.js";
export interface BatteryWidgetProps { export interface BatteryWidgetProps {
batteryLevel: number; batteryLevel: number;
@ -14,17 +16,22 @@ export const BatteryWidget = ({
voltage, voltage,
}: BatteryWidgetProps): JSX.Element => { }: BatteryWidgetProps): JSX.Element => {
return ( return (
<Card> <Card className="flex-col">
<div className="flex w-20 bg-slate-700 p-3"> <Dropdown title="Position" icon={<BoltIcon className="h-4" />}>
<BoltIcon className="m-auto h-12 text-white" /> <div className="flex">
</div> <div className="flex w-20 bg-slate-700 p-3">
<div className="w-full"> <Battery100Icon className="m-auto h-12 text-white" />
<div className="flex h-8 bg-slate-100"> </div>
<span className="m-auto text-lg font-medium">Power</span> <span className="m-auto text-lg">
{batteryLevel}
<Mono>%</Mono>
</span>
<span className="m-auto text-lg">
{voltage}
<Mono>v</Mono>
</span>
</div> </div>
<span>{batteryLevel}</span> </Dropdown>
<span>{voltage}</span>
</div>
</Card> </Card>
); );
}; };

78
src/components/Widgets/ConfiguringWidget.tsx

@ -1,9 +1,11 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useDevice } from "@core/providers/useDevice.js"; import { useDevice } from "@core/providers/useDevice.js";
import { AdjustmentsHorizontalIcon } from "@heroicons/react/24/outline";
import { Button } from "../Button.js"; import { Button } from "../Button.js";
import { Card } from "../Card.js"; import { Card } from "../Card.js";
import { Dropdown } from "../Dropdown.js";
export const ConfiguringWidget = (): JSX.Element => { export const ConfiguringWidget = (): JSX.Element => {
const { const {
@ -36,43 +38,45 @@ export const ConfiguringWidget = (): JSX.Element => {
return ( return (
<Card className="flex-col"> <Card className="flex-col">
<div className="flex h-8 bg-slate-100"> <Dropdown
<span className="m-auto text-lg font-medium">Power</span> title="Config Status"
</div> icon={<AdjustmentsHorizontalIcon className="h-4" />}
<div className="flex flex-col gap-2 p-3"> >
<ol className="flex flex-col gap-3 overflow-hidden"> <div className="flex flex-col gap-2 p-3">
<StatusIndicator <ol className="flex flex-col gap-3 overflow-hidden">
title="Device Info" <StatusIndicator
current={hardware.myNodeNum ? 1 : 0} title="Device Info"
total={0} current={hardware.myNodeNum ? 1 : 0}
/> total={0}
<StatusIndicator title="Peers" current={nodes.length} total={0} /> />
<StatusIndicator <StatusIndicator title="Peers" current={nodes.length} total={0} />
title="Device Config" <StatusIndicator
current={Object.keys(config).length - 1} title="Device Config"
total={6} current={Object.keys(config).length - 1}
/> total={6}
<StatusIndicator />
title="Module Config" <StatusIndicator
current={Object.keys(moduleConfig).length - 1} title="Module Config"
total={6} current={Object.keys(moduleConfig).length - 1}
/> total={6}
<StatusIndicator />
title="Channels" <StatusIndicator
current={channels.length} title="Channels"
total={hardware.maxChannels ?? 0} current={channels.length}
/> total={hardware.maxChannels ?? 0}
</ol> />
<Button </ol>
variant="secondary" <Button
size="sm" variant="secondary"
onClick={() => { size="sm"
void connection?.configure(); onClick={() => {
}} void connection?.configure();
> }}
Retry >
</Button> Retry
</div> </Button>
</div>
</Dropdown>
</Card> </Card>
); );
}; };

36
src/components/Widgets/NodeInfoWidget.tsx

@ -1,8 +1,10 @@
import type React from "react"; import type React from "react";
import { InformationCircleIcon } from "@heroicons/react/24/outline";
import type { Protobuf } from "@meshtastic/meshtasticjs"; import type { Protobuf } from "@meshtastic/meshtasticjs";
import { Card } from "../Card.js"; import { Card } from "../Card.js";
import { Dropdown } from "../Dropdown.js";
export interface NodeInfoWidgetProps { export interface NodeInfoWidgetProps {
hardware: Protobuf.MyNodeInfo; hardware: Protobuf.MyNodeInfo;
@ -13,26 +15,28 @@ export const NodeInfoWidget = ({
}: NodeInfoWidgetProps): JSX.Element => { }: NodeInfoWidgetProps): JSX.Element => {
return ( return (
<Card className="flex-col"> <Card className="flex-col">
<div className="flex h-8 bg-slate-100"> <Dropdown
<span className="m-auto text-lg font-medium">Information</span> title="Information"
</div> icon={<InformationCircleIcon className="h-4" />}
<div className="flex flex-col gap-2 p-3"> >
<dl className="mt-2 border-b border-gray-200"> <div className="flex flex-col gap-2 p-3">
<dl className="mt-2 border-b border-gray-200">
<div className="flex justify-between py-1 text-sm font-medium">
<dt className="text-gray-500">Firmware version</dt>
<dd className="cursor-pointer whitespace-nowrap text-gray-900 hover:text-orange-400 hover:underline">
{hardware.firmwareVersion}
</dd>
</div>
</dl>
<div className="flex justify-between py-1 text-sm font-medium"> <div className="flex justify-between py-1 text-sm font-medium">
<dt className="text-gray-500">Firmware version</dt> <dt className="text-gray-500">Bitrate</dt>
<dd className="cursor-pointer whitespace-nowrap text-gray-900 hover:text-orange-400 hover:underline"> <dd className="whitespace-nowrap text-gray-900">
{hardware.firmwareVersion} {hardware.bitrate.toFixed(2)}
<span className="font-mono text-sm text-slate-500 ">bps</span>
</dd> </dd>
</div> </div>
</dl>
<div className="flex justify-between py-1 text-sm font-medium">
<dt className="text-gray-500">Bitrate</dt>
<dd className="whitespace-nowrap text-gray-900">
{hardware.bitrate.toFixed(2)}
<span className="font-mono text-sm text-slate-500 ">bps</span>
</dd>
</div> </div>
</div> </Dropdown>
</Card> </Card>
); );
}; };

17
src/components/Widgets/PeersWidget.tsx

@ -3,10 +3,14 @@ import type React from "react";
import { base16 } from "rfc4648"; import { base16 } from "rfc4648";
import { Hashicon } from "@emeraldpay/hashicon-react"; import { Hashicon } from "@emeraldpay/hashicon-react";
import { EllipsisHorizontalCircleIcon } from "@heroicons/react/24/outline"; import {
EllipsisHorizontalCircleIcon,
UserGroupIcon,
} from "@heroicons/react/24/outline";
import type { Protobuf } from "@meshtastic/meshtasticjs"; import type { Protobuf } from "@meshtastic/meshtasticjs";
import { Card } from "../Card.js"; import { Card } from "../Card.js";
import { Dropdown } from "../Dropdown.js";
import { IconButton } from "../IconButton.js"; import { IconButton } from "../IconButton.js";
import { Mono } from "../Mono.js"; import { Mono } from "../Mono.js";
@ -16,12 +20,9 @@ export interface PeersWidgetProps {
export const PeersWidget = ({ peers }: PeersWidgetProps): JSX.Element => { export const PeersWidget = ({ peers }: PeersWidgetProps): JSX.Element => {
return ( return (
<Card> <Card className="flex-col">
<div className="flex w-full flex-col gap-1"> <Dropdown title="Peers" icon={<UserGroupIcon className="h-4" />}>
<div className="flex h-8 bg-slate-100"> <div className="p-3">
<span className="m-auto text-lg font-medium">Peers</span>
</div>
<div className="p-4">
{peers.map((peer) => ( {peers.map((peer) => (
<div <div
className="flex gap-2 rounded-md p-2 hover:bg-slate-100" className="flex gap-2 rounded-md p-2 hover:bg-slate-100"
@ -49,7 +50,7 @@ export const PeersWidget = ({ peers }: PeersWidgetProps): JSX.Element => {
</div> </div>
))} ))}
</div> </div>
</div> </Dropdown>
</Card> </Card>
); );
}; };

18
src/components/Widgets/PositionWidget.tsx

@ -3,6 +3,7 @@ import type React from "react";
import { MapPinIcon } from "@heroicons/react/24/outline"; import { MapPinIcon } from "@heroicons/react/24/outline";
import { Card } from "../Card.js"; import { Card } from "../Card.js";
import { Dropdown } from "../Dropdown.js";
export interface PositionWidgetProps { export interface PositionWidgetProps {
grid: string; grid: string;
@ -10,16 +11,15 @@ export interface PositionWidgetProps {
export const PositionWidget = ({ grid }: PositionWidgetProps): JSX.Element => { export const PositionWidget = ({ grid }: PositionWidgetProps): JSX.Element => {
return ( return (
<Card> <Card className="flex-col">
<div className="flex w-20 bg-teal-600 p-3"> <Dropdown title="Position" icon={<MapPinIcon className="h-4" />}>
<MapPinIcon className="m-auto h-12 text-white" /> <div className="flex">
</div> <div className="flex w-20 bg-teal-600 p-3">
<div className="flex w-full flex-col"> <MapPinIcon className="m-auto h-12 text-white" />
<div className="flex h-8 bg-slate-100"> </div>
<span className="m-auto text-lg font-medium">Position</span> <span className="m-auto text-lg">{grid}</span>
</div> </div>
<span className="m-auto text-lg">{grid}</span> </Dropdown>
</div>
</Card> </Card>
); );
}; };

Loading…
Cancel
Save