mirror of
https://github.com/meshtastic/meshtastic.git
synced 2025-02-21 03:25:51 -08:00
Hardware page component breakout
This commit is contained in:
parent
5ba2b9e14d
commit
b101307f2f
18
src/components/hardware/Badge.tsx
Normal file
18
src/components/hardware/Badge.tsx
Normal file
|
@ -0,0 +1,18 @@
|
|||
import React from 'react';
|
||||
|
||||
export interface BadgeProps {
|
||||
name: string;
|
||||
color: string;
|
||||
icon: React.ReactNode;
|
||||
}
|
||||
|
||||
export const Badge = ({ name, color, icon }: BadgeProps): JSX.Element => {
|
||||
return (
|
||||
<div
|
||||
className={`flex h-min cursor-pointer gap-1 rounded-md px-1 text-white shadow-md hover:opacity-80 ${color}`}
|
||||
>
|
||||
<div className="m-auto">{icon}</div>
|
||||
<span>{name}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
21
src/components/hardware/CardTab.tsx
Normal file
21
src/components/hardware/CardTab.tsx
Normal file
|
@ -0,0 +1,21 @@
|
|||
import React from 'react';
|
||||
|
||||
import { Tab } from '@headlessui/react';
|
||||
|
||||
export interface CardTabProps {
|
||||
title: string;
|
||||
}
|
||||
|
||||
export const CardTab = ({ title }: CardTabProps): JSX.Element => {
|
||||
return (
|
||||
<Tab
|
||||
className={({ selected }) =>
|
||||
`w-1/3 truncate rounded-md px-3 py-2 text-sm font-medium hover:bg-tertiary ${
|
||||
selected ? 'bg-secondary shadow-md' : ''
|
||||
}`
|
||||
}
|
||||
>
|
||||
{title}
|
||||
</Tab>
|
||||
);
|
||||
};
|
|
@ -4,11 +4,11 @@ import { IDevice, Stability } from '@site/src/data/device';
|
|||
|
||||
import { HardwareModal } from './HardwareModal';
|
||||
|
||||
export interface HardwareCard {
|
||||
export interface HardwareCardProps {
|
||||
device: IDevice;
|
||||
}
|
||||
|
||||
export const HardwareCard = ({ device }: HardwareCard): JSX.Element => {
|
||||
export const HardwareCard = ({ device }: HardwareCardProps): JSX.Element => {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
|
@ -21,12 +21,12 @@ export const HardwareCard = ({ device }: HardwareCard): JSX.Element => {
|
|||
>
|
||||
<div className="overflow-hidden rounded-lg">
|
||||
<div
|
||||
className={`flex aspect-[4/3] overflow-hidden bg-gradient-to-r ${device.misc.Gradient}`}
|
||||
className={`flex aspect-[4/3] overflow-hidden ${device.misc.Gradient}`}
|
||||
>
|
||||
<img
|
||||
src={device.misc.ImagePath}
|
||||
alt=""
|
||||
className="pointer-events-none m-auto object-cover p-2 group-hover:opacity-75"
|
||||
className="pointer-events-none m-auto max-h-full max-w-full object-cover p-2 group-hover:opacity-75"
|
||||
/>
|
||||
</div>
|
||||
<button type="button" className="absolute inset-0 focus:outline-none">
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
import React, { useState } from 'react';
|
||||
|
||||
import { FiBluetooth, FiChevronRight, FiWifi, FiX } from 'react-icons/fi';
|
||||
import {
|
||||
VictoryChart,
|
||||
VictoryLine,
|
||||
VictoryPolarAxis,
|
||||
VictoryTheme,
|
||||
} from 'victory';
|
||||
|
||||
import { Tab, Transition } from '@headlessui/react';
|
||||
import type { IDevice } from '@site/src/data/device';
|
||||
|
||||
import { Modal } from '../Modal';
|
||||
import { Badge } from './Badge';
|
||||
import { CardTab } from './CardTab';
|
||||
import { InfoTab } from './Tabs/InfoTab';
|
||||
import { PinoutTab } from './Tabs/PinoutTab';
|
||||
import { PowerTab } from './Tabs/PowerTab';
|
||||
import { VariantSelectButton } from './VariantSelectButton';
|
||||
|
||||
export interface HardwareModal {
|
||||
|
@ -33,7 +32,7 @@ export const HardwareModal = ({
|
|||
<div className="inline-block w-full max-w-md transform overflow-hidden rounded-2xl bg-base text-left align-middle transition-all md:max-w-2xl md:bg-primary lg:max-w-4xl xl:max-w-6xl">
|
||||
<div className="flex aspect-[3/2] flex-col md:aspect-[2/1] md:flex-row">
|
||||
<div
|
||||
className={`relative flex h-full rounded-t-2xl bg-gradient-to-r md:rounded-l-2xl md:rounded-tr-none ${
|
||||
className={`relative flex h-full rounded-t-2xl md:rounded-l-2xl md:rounded-tr-none ${
|
||||
device.misc.Gradient
|
||||
} ${hideDetails ? 'w-full' : ''}`}
|
||||
>
|
||||
|
@ -61,16 +60,14 @@ export const HardwareModal = ({
|
|||
{!hideDetails && (
|
||||
<div className="absolute -bottom-3 right-0 m-auto mr-2 ml-auto flex gap-2 md:bottom-2 md:mr-14 md:mt-2">
|
||||
{device.features.BLE && (
|
||||
<div className="flex h-min gap-1 rounded-md bg-blue-500 px-1 text-white shadow-md">
|
||||
<FiBluetooth className="m-auto" />
|
||||
<span>Bluetooth</span>
|
||||
</div>
|
||||
<Badge
|
||||
name="Bluetooth"
|
||||
color="bg-blue-500"
|
||||
icon={<FiBluetooth />}
|
||||
/>
|
||||
)}
|
||||
{device.features.WiFi && (
|
||||
<div className="m-auto flex h-min gap-1 rounded-md bg-orange-500 px-1 text-white shadow-md">
|
||||
<FiWifi className="m-auto" />
|
||||
<span>WiFi</span>
|
||||
</div>
|
||||
<Badge name="WiFi" color="bg-orange-500" icon={<FiWifi />} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
@ -83,7 +80,7 @@ export const HardwareModal = ({
|
|||
<FiX className="m-auto" />
|
||||
</div>
|
||||
<div
|
||||
className={`transition-[width] duration-100 ease-linear ${
|
||||
className={`transition-[all] duration-100 ease-linear ${
|
||||
hideDetails ? 'h-7 bg-base md:h-auto md:w-7' : 'w-full'
|
||||
}`}
|
||||
>
|
||||
|
@ -109,70 +106,14 @@ export const HardwareModal = ({
|
|||
className="flex-grow rounded-2xl bg-primary p-2"
|
||||
>
|
||||
<Tab.List className="flex gap-2">
|
||||
<Tab
|
||||
className={({ selected }) =>
|
||||
`w-1/3 truncate rounded-md px-3 py-2 text-sm font-medium hover:bg-tertiary ${
|
||||
selected ? 'bg-secondary shadow-md' : ''
|
||||
}`
|
||||
}
|
||||
>
|
||||
Info
|
||||
</Tab>
|
||||
<Tab
|
||||
className={({ selected }) =>
|
||||
`w-1/3 truncate rounded-md px-3 py-2 text-sm font-medium hover:bg-tertiary ${
|
||||
selected ? 'bg-secondary shadow-md' : ''
|
||||
}`
|
||||
}
|
||||
>
|
||||
Power
|
||||
</Tab>
|
||||
<Tab
|
||||
className={({ selected }) =>
|
||||
`w-1/3 truncate rounded-md px-3 py-2 text-sm font-medium hover:bg-tertiary ${
|
||||
selected ? 'bg-secondary shadow-md' : ''
|
||||
}`
|
||||
}
|
||||
>
|
||||
Pinout
|
||||
</Tab>
|
||||
<CardTab title="Info" />
|
||||
<CardTab title="Power" />
|
||||
<CardTab title="Pinout" />
|
||||
</Tab.List>
|
||||
<Tab.Panels as="div" className="">
|
||||
<Tab.Panel className="h-32">Content 1</Tab.Panel>
|
||||
<Tab.Panel className="h-96">
|
||||
<VictoryChart
|
||||
polar
|
||||
theme={VictoryTheme.material}
|
||||
domain={{ y: [0, 10] }}
|
||||
>
|
||||
<VictoryPolarAxis
|
||||
dependentAxis
|
||||
style={{ axis: { stroke: 'none' } }}
|
||||
tickFormat={() => ''}
|
||||
/>
|
||||
<VictoryPolarAxis
|
||||
tickValues={[
|
||||
0,
|
||||
Math.PI / 2,
|
||||
Math.PI,
|
||||
(3 * Math.PI) / 2,
|
||||
]}
|
||||
tickFormat={['2π', 'π/2', 'π', '3π/2']}
|
||||
labelPlacement="vertical"
|
||||
/>
|
||||
{[5, 4, 3, 2, 1].map((val, i) => {
|
||||
return (
|
||||
<VictoryLine
|
||||
key={i}
|
||||
samples={100}
|
||||
style={{ data: { stroke: colors[i] } }}
|
||||
y={(d) => val * (1 - Math.cos(d.x))}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</VictoryChart>
|
||||
</Tab.Panel>
|
||||
<Tab.Panel>Content 3</Tab.Panel>
|
||||
<InfoTab device={device} />
|
||||
<PowerTab device={device} />
|
||||
<PinoutTab device={device} />
|
||||
</Tab.Panels>
|
||||
</Tab.Group>
|
||||
</div>
|
||||
|
|
13
src/components/hardware/Tabs/InfoTab.tsx
Normal file
13
src/components/hardware/Tabs/InfoTab.tsx
Normal file
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
|
||||
import { Tab } from '@headlessui/react';
|
||||
|
||||
import type { IDevice } from '../../../data/device';
|
||||
|
||||
export interface InfoTabProps {
|
||||
device: IDevice;
|
||||
}
|
||||
|
||||
export const InfoTab = ({ device }: InfoTabProps): JSX.Element => {
|
||||
return <Tab.Panel className="h-32">Content 1</Tab.Panel>;
|
||||
};
|
13
src/components/hardware/Tabs/PinoutTab.tsx
Normal file
13
src/components/hardware/Tabs/PinoutTab.tsx
Normal file
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
|
||||
import { Tab } from '@headlessui/react';
|
||||
|
||||
import type { IDevice } from '../../../data/device';
|
||||
|
||||
export interface PinoutTabProps {
|
||||
device: IDevice;
|
||||
}
|
||||
|
||||
export const PinoutTab = ({ device }: PinoutTabProps): JSX.Element => {
|
||||
return <Tab.Panel className="h-32">Content 1</Tab.Panel>;
|
||||
};
|
13
src/components/hardware/Tabs/PowerTab.tsx
Normal file
13
src/components/hardware/Tabs/PowerTab.tsx
Normal file
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
|
||||
import { Tab } from '@headlessui/react';
|
||||
|
||||
import type { IDevice } from '../../../data/device';
|
||||
|
||||
export interface PowerTabProps {
|
||||
device: IDevice;
|
||||
}
|
||||
|
||||
export const PowerTab = ({ device }: PowerTabProps): JSX.Element => {
|
||||
return <Tab.Panel className="h-32">Content 1</Tab.Panel>;
|
||||
};
|
|
@ -46,7 +46,7 @@ export const VariantSelectButton = ({
|
|||
active ? 'bg-indigo-600' : ''
|
||||
}`
|
||||
}
|
||||
value={variant.name}
|
||||
value={variant}
|
||||
>
|
||||
{({ selected, active }) => (
|
||||
<>
|
||||
|
|
63
src/data/devices/hydra.ts
Normal file
63
src/data/devices/hydra.ts
Normal file
|
@ -0,0 +1,63 @@
|
|||
import { IDevice, Stability, UseCase } from '../device';
|
||||
|
||||
export const hydra: IDevice = {
|
||||
name: 'Hydra',
|
||||
misc: {
|
||||
Stability: Stability.Stable,
|
||||
SuggestedUse: [UseCase.Portable],
|
||||
ImagePath: '/img/hardware/Hydra-PCB.2.1.svg',
|
||||
Gradient: 'bg-gradient-to-r from-indigo-200 via-red-200 to-yellow-100',
|
||||
},
|
||||
features: {
|
||||
BLE: true,
|
||||
WiFi: true,
|
||||
Modules: [
|
||||
'cannedMessage',
|
||||
'externalNotification',
|
||||
'rangeTest',
|
||||
'rotaryEncoder',
|
||||
'storeAndForward',
|
||||
'telemetry',
|
||||
],
|
||||
},
|
||||
specifications: {
|
||||
BLEVersion: '4.2',
|
||||
BLEAntenna: 'Integrated',
|
||||
WiFiVersion: '2.4GHz 802.11 b/g/n WPA/WPA2/WPA2-Enterprise/SPS',
|
||||
WiFiAntenna: 'Integrated',
|
||||
Chipset: 'ESP32',
|
||||
Driver: 'CH9102',
|
||||
GNSS: 'NEO-6M',
|
||||
FlashSize: 4,
|
||||
Frequencies: [433, 868, 915, 923],
|
||||
LoRa: 'SX1262',
|
||||
PSRAM: 8,
|
||||
RAM: undefined,
|
||||
},
|
||||
variants: [
|
||||
{
|
||||
name: 'TBeam 0.7',
|
||||
misc: {
|
||||
Stability: Stability.Unstable,
|
||||
},
|
||||
specifications: {
|
||||
Driver: 'CP210X',
|
||||
GNSS: 'NEO-6M',
|
||||
Frequencies: [868, 915],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'TBeam 1.0',
|
||||
specifications: {
|
||||
Frequencies: [868, 915],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'TBeam 1.1',
|
||||
specifications: {
|
||||
Driver: 'CP210X',
|
||||
GNSS: 'NEO-6M',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
|
@ -6,7 +6,7 @@ export const rak19003: IDevice = {
|
|||
Stability: Stability.Stable,
|
||||
SuggestedUse: [UseCase.Portable],
|
||||
ImagePath: '/img/hardware/rak/RAK19003.png',
|
||||
Gradient: 'from-green-300 via-blue-500 to-purple-600',
|
||||
Gradient: 'bg-gradient-to-b from-orange-500 to-yellow-300',
|
||||
},
|
||||
features: {
|
||||
BLE: true,
|
||||
|
|
|
@ -6,7 +6,7 @@ export const tbeam: IDevice = {
|
|||
Stability: Stability.Stable,
|
||||
SuggestedUse: [UseCase.Portable],
|
||||
ImagePath: '/img/hardware/tbeam-v1.1.svg',
|
||||
Gradient: 'from-pink-500 via-red-500 to-yellow-500',
|
||||
Gradient: 'bg-gradient-to-r from-pink-500 via-red-500 to-yellow-500',
|
||||
},
|
||||
features: {
|
||||
BLE: true,
|
||||
|
|
|
@ -5,6 +5,7 @@ import { FiPlus } from 'react-icons/fi';
|
|||
import { HardwareCard } from '../../components/hardware/HardwareCard';
|
||||
import { PageLayout } from '../../components/PageLayout';
|
||||
import { heltec } from '../../data/devices/heltec';
|
||||
import { hydra } from '../../data/devices/hydra';
|
||||
import { rak19003 } from '../../data/devices/rak19003';
|
||||
import { tbeam } from '../../data/devices/tbeam';
|
||||
import { techo } from '../../data/devices/techo';
|
||||
|
@ -12,6 +13,7 @@ import { techo } from '../../data/devices/techo';
|
|||
const Hardware = (): JSX.Element => {
|
||||
const hardware = [
|
||||
tbeam,
|
||||
hydra,
|
||||
rak19003,
|
||||
heltec,
|
||||
techo,
|
||||
|
|
4910
static/img/hardware/Hydra-PCB.2.1.svg
Executable file
4910
static/img/hardware/Hydra-PCB.2.1.svg
Executable file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 798 KiB |
Loading…
Reference in a new issue