Merge branch 'master' into march-discord

This commit is contained in:
Sacha Weatherstone 2022-04-08 11:30:17 +10:00 committed by GitHub
commit 9ba2407919
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
60 changed files with 6510 additions and 403 deletions

View file

@ -1,6 +1,8 @@
<!-- markdownlint-disable MD033 -->
<!-- markdownlint-disable MD041 -->
[![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/Meshtastic)](https://cla-assistant.io/meshtastic/Meshtastic)
<div align="center">
<img src="https://raw.githubusercontent.com/meshtastic/meshtastic-design/4463325bedef20be5655c91c80d1cd32a625f3ff/logo/svg/Mesh_Logo_Dynamic.svg" width="256">
<h1>Meshtastic</h1>

View file

@ -1,5 +1,4 @@
:::important
<span>
The name of ths option changed between Meshtastic 1.2 and 1.3. This
documentaton already reflects the 1.3 syntax. Please substitute '{props.name}'

View file

@ -8,7 +8,7 @@ sidebar_label: Building Android App
If you would like to develop this application we'd love your help! These build instructions are brief and should be improved, please send a PR if you can.
- Use Android Studio 4.1.2 to build/debug (other versions might work but no promises)
- Use Android Studio to build/debug
- Use `git submodule update --init --recursive` to pull in the various submodules we depend on
- There are a few config files which you'll need to copy from templates included in the project. Run the following commands to do so:

View file

@ -26,3 +26,44 @@ Meshtastic uses the [PlatformIO](https://platformio.org) development environment
1. To select the device you you wish to build for, first open your [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) (`Ctrl + Shift + P`) and enter: `platformio: Switch Project Environment` and select your target.
1. To build the firmware, simply run `PlatformIO: Build` from your command palette.
1. Finally flashing the firmware to your device is as easy as running `PlatformIO: Upload`
## Adding your own Hardware
The build system is modular. Adding a new board variant for an already supported architecture is straigtforward.
### Building for your own DIY hardware or mod that you don't want to distribute
1. go to the `variants` folder in the Meshtastic-device sourcecode and make a new directory for your hardware, let's call it `m5stack_core` and copy an existing configuration you wanna modify
```shell
cd variants; mkdir m5stack_core
cp ../heltec_v1/* m5stack_core
cd m5stack_core
```
2. modify the `platformio.ini` *in this subdirectory* from the canonical define of the hardware variant (`HELTEC_V1` in this case) to `PRIVATE_HW` and make the `-I` on the `build_flags` point to the newly created dir.
```shell
[env:m5stack-core]
extends = esp32_base
board = m5stack-core-esp32
monitor_filters = esp32_exception_decoder
build_flags =
${esp32_base.build_flags} -D PRIVATE_HW -I variants/m5stack_core
lib_deps =
${esp32_base.lib_deps}
```
3. edit the `variant.h` file *in this subdirectory* to reflect the defines and configurations for your board. The example is very well commented.
3. build, run and debug until you are satisfied with the result.
### Adding a new off-the-shelf or DIY hardware that you want to distribute (e.g. add a new canon board)
1. do all of the above until your hardware runs fine
2. [Send in a proposal to add a new board](https://github.com/meshtastic/Meshtastic-device/issues/new?assignees=&labels=enhancement%2Ctriage&template=New+Board.yml&title=%5BBoard%5D%3A+)
3. if approved, go to (https://github.com/meshtastic/Meshtastic-protobufs) and send a Pull Request for the mesh.proto file, adding your board to the HardwareModel enum.
4. change your define in `platformio.ini` from `PRIVATE_HW` to `YOUR_BOARD`. Adjust any macro guards in the code you need to support your board.
5. add your board identifier to `configuration.h` on the Meshtastic-device repo and send in that Pull Request too.
6. wait for the Pulls to be merged back into Master.
7. profit :-)

View file

@ -0,0 +1,49 @@
---
id: markdown-features
title: Style Guide - Markdown Features
sidebar_label: Markdown Features
---
import { Dark, Light } from '/src/components/ColorMode';
## Overview
We have developed several [React](https://reactjs.org/) components for assisting with writing documentation.
## Features
### Light/Dark Mode Switch
#### Usage:
```jsx
import { Dark, Light } from '/src/components/ColorMode';
<Dark>
<p>Dark</p>
</Dark>
<Light>
<p>Light</p>
</Light>
```
#### Demo:
<Dark>
<div className="not-prose rounded-lg bg-primary shadow-md">
<p className="p-2 text-lg font-medium">This is only shown in dark mode.</p>
<img
src="https://picsum.photos/id/101/600/200"
className="w-full rounded-lg shadow-md"
/>
</div>
</Dark>
<Light>
<div className="not-prose rounded-lg border bg-primary shadow-md">
<p className="p-2 text-lg font-medium">This is only shown in light mode.</p>
<img
src="https://picsum.photos/id/1028/600/200"
className="w-full rounded-lg shadow-md"
/>
</div>
</Light>

View file

@ -29,7 +29,6 @@ For a description and more information on what exactly all of these mean, please
| phone_timeout_secs | `integer` (seconds) | `0` |
| screen_on_secs | `integer` (seconds) | `0` |
| sds_secs | `integer` (seconds) | `0` |
| send_owner_interval | `integer` (sent every x network pings) | `4` |
| wait_bluetooth_secs | `integer` (seconds) | `0` |
:::note
@ -505,43 +504,6 @@ Configuring this setting is not yet available for the selected platform. If this
</TabItem>
</Tabs>
### send_owner_interval
This sets how often to send the database of node owner information with other nodes in the mesh (per mesh network ping).
#### Configure send_owner_interval
<Tabs
groupId="settings"
defaultValue="cli"
values={[
{label: 'CLI', value: 'cli'},
{label: 'Android', value: 'android'},
{label: 'iOS', value: 'iOS'},
{label: 'Web', value: 'web'},
]}>
<TabItem value="cli">
```shell title="Set send_owner_interval to default (every 4 network pings)"
meshtastic --set send_owner_interval 0
```
```shell title="Set send_owner_interval to every 10 network pings"
meshtastic --set send_owner_interval 10
```
</TabItem>
<TabItem value="android">
Configuring this setting is not yet available for the selected platform. If this is incorrect please update the documentation for this page.
</TabItem>
<TabItem value="iOS">
Configuring this setting is not yet available for the selected platform. If this is incorrect please update the documentation for this page.
</TabItem>
<TabItem value="web">
Configuring this setting is not yet available for the selected platform. If this is incorrect please update the documentation for this page.
</TabItem>
</Tabs>
For instance the default interval of 4 will send the node owner information for every 4 mesh network pings. This information is also transmitted after the node first boots up.
### wait_bluetooth_secs

View file

@ -70,7 +70,6 @@ Toggling `is_router` changes your device settings in the following ways.
| Setting | `is_router` Default | Normal Default |
| :-----------------------: | :-----------------: | :------------: |
| `send_owner_interval` | 2 | 4 |
| `position_broadcast_secs` | 12 hours | 15 minutes |
| `wait_bluetooth_secs` | 1 | 60 |
| `mesh_sds_timeout_secs` | NODE_DELAY_FOREVER | 2 hours |

View file

@ -16,28 +16,19 @@ Open the App and you should see a screen like this. Notice the cloud with a slas
You will need a device with Meshtastic installed to go any further. See the [getting started](/docs/getting-started) section for information on how to do this.
Open the Settings tab (last tab), and it should look similar to the screen below. It shows any Meshtastic devices that are found over Bluetooth.
[![Search for devices](/img/android/android-settings-none-c.png)](/img/android/android-settings-none-c.png)
:::note
Android requires location permission granted and location must be turned on to find new devices via Bluetooth. You can turn it off again afterwards.
:::
To find devices via Bluetooth click the button on the bottom right corner of the Settings tab (last tab).
[![Device available to select](/img/android/android-settings-deselected-c.png)](/img/android/android-settings-deselected.png)
If the button is disabled, there are no devices available. To refresh the button state, click `None (disable)`. Make sure the device is turned on and not connected to any other app or client. Try to reset, or forget the device on Android Bluetooth settings.
1. Select the Device by name, "Meshtastic_c830" in the example below. (You will see any active devices within range, so make sure to get the right one.)
2. You will need to "pair" the device by entering a PIN shown on the device screen. This can alternatively be done in the phone Bluetooth settings. If the Device has no screen, but it's connected via USB, it may be displayed on a serial terminal (921600 Baud). For a development device, the PlatformIO terminal would come in handy. Some nodes have buttons allowing you to change the page displayed on the nodes screen. If you double click this button, it will set the pairing code to `123456`.
3. Edit the "Your name", e.g. to be "Mike Bird". This is the name that other people will see, so make it unique within your group.
4. The initials e.g. "MB" should also be unique and will be used to identify you in the message history and on the device screens.
[![Device available to select](/img/android/android-settings-connect-sm.png)](/img/android/android-settings-connect.png)
[![Changing device name](/img/android/android-settings-mike-sm.png)](/img/android/android-settings-mike.png)
1. Select the Device by name, "Meshtastic_bebc" in the example above. (You will see any active devices within range, so make sure to get the right one.)
2. You will need to "pair" the device by entering a PIN shown on the device screen. This can alternatively be done in the phone Bluetooth settings. Some devices have buttons, where a double click sets the pairing PIN to `123456`.
3. This should start the communication with the Device. The cloud icon, on the status bar, will have a tick.
5. This should start the communication with the Device. The cloud icon, on the status bar, will have a tick.
![Connected](/img/android/android-cloud-tick.png)
If there is no Device shown, just the `None (disable)` as below, then the device may be off, or in a sleep mode. Try to reset, or press a button to wake it.
[![No devices available](/img/android/android-settings-none-c.png)](/img/android/android-settings-none-c.png)
[![Device connected](/img/android/android-settings-mike-c.png)](/img/android/android-settings-mike-c.png)
The cloud icon at the top right corner indicates if you are connected to a device. This currently has three states:
@ -49,17 +40,23 @@ The cloud icon at the top right corner indicates if you are connected to a devic
## Common tasks
Once you are connected to a device, the App will work, and you can test it by "sending" a message. However, you will need to join or create a new mesh network so you have someone to communicate with. If you have been sent a QR code or link for Meshtastic, then skip ahead to [Join a Channel](#join-a-channel), otherwise you will need to Setup a Channel.
### Change your name
Edit the "Your name", e.g. to be "Mike Bird". This is the name that other people will see, so make it unique within your group. The initials e.g. "MB" should also be unique and will be used to identify you in the message history and on the device screens.
[![Changing device name](/img/android/android-settings-mike-sm.png)](/img/android/android-settings-mike.png)
### Setup a channel
To use Meshtastic, you need to setup a Channel and share the details with your group. The group is private and only those who have the details can join the group and see the messages. You will need to do this once initially, and then only when you want to change or make a new mesh network group. For a new device you will see there is a default setting, shown as `#LongSlow-1, Very long range (but slow)`. It is OK to use this initially.
If you have been sent a QR code or link for Meshtastic, then skip ahead to [Join a Channel](#join-a-channel). Devices have a default channel preconfigured, shown as `#LongSlow-V (Long range / Slow)`. It is OK to use this initially.
You can also create a new Channel and share the details with your group. The group is private and only those who have the details can join the group and see the messages. You will need to do this once initially, and then only when you want to change or make a new mesh network group.
The Channel tab allows you to do this. This screen is initially locked so that you don't change it accidentally. Press the lock symbol, and you will be able to edit. First, select the Channel options, as shown here, and chose the most appropriate option:
[![Changing channel settings](/img/android/android-change-channel-sm.png)](/img/android/android-change-channel.png)
Here we selected `Very long range (but slow)`, and then made a Channel Name using the keyboard. This identifies your group, here "Owl Team".
Here we selected `Long Range / Fast`, and then made a Channel Name using the keyboard. This identifies your group, here "Owl Team".
[![Changing channel name](/img/android/android-channel-owl-sm.png)](/img/android/android-channel-owl.png)
@ -71,14 +68,14 @@ The app will generate a new QR code on the screen, and this encodes the channel
### Join a channel
If another user shares a QR code, you will be able to scan it with your camera. If the channel is shared as a file or link via the Share button, you can click on the file or link and follow similar steps.
If another user shares a QR code, you will be able to scan it directly with your camera using the Scan button.
You should see a message with the option "open with Meshtastic".
If the channel is shared as a file or link via the Share button, you can click on the file or link and you should see a message with the option to "Open with Meshtastic".
[![Open with Meshtastic](/img/android/android-open-with-c.png)](/img/android/android-open-with.png)
<details>
<summary>Troubleshooting: Can't "open with Meshtastic".</summary>
<summary>Troubleshooting shared links: Can't "open with Meshtastic".</summary>
<div>
<div>
If you don't see "Meshtastic" as an option to open the file or link with:
@ -119,7 +116,7 @@ Various data-rates are selectable when configuring a channel and are inversely p
| Medium Range / Fast | 1227.18 bps |
| Medium Range / Slow | 763.29 bps |
| Long Range / Fast | 196.74 bps |
| long Range / Slow | 136.71 bps (default) |
| Long Range / Slow | 136.71 bps |
### Send a message
@ -166,21 +163,21 @@ Pressing the three vertical dots in the top right corner shows the configuration
#### Broadcast position period
This allows you to change the frequency with which your location is broadcast across the mesh. By default, this is set to 900 seconds (15 minutes). The minimum time this can be set for the default channel is 375 seconds, the reasons for which have been [discussed on the forum](https://meshtastic.discourse.group/t/lost-messages-while-testing/2455/19).
This allows you to disable or change the frequency with which your location is broadcast across the mesh. By default, this is set to 900 seconds (15 minutes). The minimum time this can be set for the default channel is 375 seconds, the reasons for which have been [discussed on the forum](https://meshtastic.discourse.group/t/lost-messages-while-testing/2455/19).
#### Device sleep period
#### Device sleep period (now disabled by default & no longer recommended)
ESP32 devices can enter sleep mode to save battery life. During sleep Bluetooth is turned off. This setting allows the length of the sleep mode to be changed from the default 300 seconds (5 minutes). After this time period, they awake to check the phone for any queued messages and then go back to sleep, alternating between sleep and awake states. Receiving a message over LoRa (the LoRa receiver never switches off) or pressing a program button (if there is one on the device) also awakes the device.
### Debug page
### Debug Panel
[![Debug page](/img/android/android-debug-sm.png)](/img/android/android-debug.png)
The debug page allows you to see all packets sent between the application and the device. This can be useful for debugging purposes.
The debug panel allows you to see all packets sent between the application and the device. This can be useful for debugging purposes.
### Save messages as CSV
### Export rangetest.csv
This allows you to save your messages to a .csv (comma separated value) file on your phone.
This allows you to save all your position data with GPS coordinates into a .csv (comma separated value) file on your phone. This feature is similar but independent from the device range test module, and results may differ.
### Theme

View file

@ -55,7 +55,7 @@ From lower to higher power consumption.
- At cold boot: The initial state (after setup() has run) is DARK
- While in DARK: if we receive EVENT_BOOT, transition to ON (and show the bootscreen). This event will be sent if we detect we woke due to reset (as opposed to deep sleep)
- While in LS: Once every position_broadcast_secs (default 15 mins) - the unit will wake into DARK mode and broadcast a "networkPing" (our position) and stay alive for wait_bluetooth_secs (default 60 seconds). This allows other nodes to have a record of our last known position if we go away and allows a paired phone to hear from us and download messages.
- While in LS: Every send*owner_interval (defaults to 4, i.e. one hour), when we wake to send our position we \_also* broadcast our owner. This lets new nodes on the network find out about us or correct duplicate node number assignments.
- While in LS: Every one hour, when we wake to send our position we \_also* broadcast our owner. This lets new nodes on the network find out about us or correct duplicate node number assignments.
- While in LS/NB/DARK: If the user presses a button (EVENT_PRESS) we go to full ON mode for screen_on_secs (default 30 seconds). Multiple presses keeps resetting this timeout
- While in LS/NB/DARK: If we receive new text messages (EVENT_RECEIVED_TEXT_MSG), we go to full ON mode for screen_on_secs (same as if user pressed a button)
- While in LS: while we receive packets on the radio (EVENT_RECEIVED_PACKET) we will wake and handle them and stay awake in NB mode for min_wake_secs (default 10 seconds)

View file

@ -1,18 +1,18 @@
// @ts-check
require("dotenv").config();
require('dotenv').config();
/** @type {import('@docusaurus/types').Config} */
const config = {
title: "Meshtastic",
tagline: "Open Source hiking, pilot, skiing and secure GPS mesh communicator",
url: "https://meshtastic.org",
baseUrl: "/",
onBrokenLinks: "throw",
onBrokenMarkdownLinks: "warn",
favicon: "design/web/favicon.ico",
organizationName: "meshtastic",
projectName: "meshtastic",
title: 'Meshtastic',
tagline: 'Open Source hiking, pilot, skiing and secure GPS mesh communicator',
url: 'https://meshtastic.org',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'design/web/favicon.ico',
organizationName: 'meshtastic',
projectName: 'meshtastic',
ssrTemplate: `<!DOCTYPE html>
<html <%~ it.htmlAttributes %>>
<head>
@ -57,12 +57,12 @@ const config = {
respectPrefersColorScheme: true,
},
navbar: {
title: "Meshtastic",
title: 'Meshtastic',
hideOnScroll: true,
logo: {
alt: "Meshtastic Logo",
src: "design/logo/svg/Mesh_Logo_Black.svg",
srcDark: "design/logo/svg/Mesh_Logo_White.svg",
alt: 'Meshtastic Logo',
src: 'design/logo/svg/Mesh_Logo_Black.svg',
srcDark: 'design/logo/svg/Mesh_Logo_White.svg',
},
items: [
@ -74,9 +74,9 @@ const config = {
},
*/
{
label: "About Meshtastic",
to: "docs/about",
activeBasePath: "docs/about",
label: 'About Meshtastic',
to: 'docs/about',
activeBasePath: 'docs/about',
},
/*
{
@ -86,20 +86,20 @@ const config = {
},
*/
{
label: "Documentation",
label: 'Documentation',
items: [
{
label: "Getting Started",
to: "docs/getting-started",
label: 'Getting Started',
to: 'docs/getting-started',
},
// FIXME create configuration & settings landing page and adjust path below
{
label: "Configuration & Settings",
to: "docs/settings",
label: 'Configuration & Settings',
to: 'docs/settings',
},
{
label: "Hardware Details",
to: "docs/hardware",
label: 'Hardware Details',
to: 'docs/hardware',
},
/*
{
@ -108,43 +108,43 @@ const config = {
},
*/
{
label: "Meshtastic Software",
to: "docs/software",
label: 'Meshtastic Software',
to: 'docs/software',
},
],
},
{
label: "Contribute",
label: 'Contribute',
items: [
{
label: "Developers",
to: "docs/developers",
label: 'Developers',
to: 'docs/developers',
},
{
label: "Maintaining Documentation",
to: "docs/developers/maintaining-documentation/overview",
label: 'Maintaining Documentation',
to: 'docs/developers/maintaining-documentation/overview',
},
{
label: "Legal",
to: "docs/legal",
label: 'Legal',
to: 'docs/legal',
},
],
},
{
label: "Downloads",
to: "downloads",
activeBasePath: "downloads",
label: 'Downloads',
to: 'downloads',
activeBasePath: 'downloads',
},
{
href: "https://meshtastic.discourse.group",
label: "Forum",
position: "left",
href: 'https://meshtastic.discourse.group',
label: 'Forum',
position: 'left',
},
{
href: "https://github.com/meshtastic/meshtastic",
position: "right",
className: "header-github-link",
"aria-label": "GitHub repository",
href: 'https://github.com/meshtastic/meshtastic',
position: 'right',
className: 'header-github-link',
'aria-label': 'GitHub repository',
},
],
},
@ -152,21 +152,21 @@ const config = {
copyright: `<a href="https://vercel.com/?utm_source=meshtastic&utm_campaign=oss" style="color: var(--ifm-footer-color)">Powered by ▲ Vercel</a> | Meshtastic® is a registered trademark of Geeksville Industries LLC`,
},
algolia: {
appId: "IG2GQB8L3V",
apiKey: "2e4348812173ec7ea6f7879c7032bb21",
indexName: "meshtastic",
appId: 'IG2GQB8L3V',
apiKey: '2e4348812173ec7ea6f7879c7032bb21',
indexName: 'meshtastic',
contextualSearch: false,
searchPagePath: "search",
searchPagePath: 'search',
},
},
plugins: [
() => {
return {
name: "docusaurus-tailwindcss",
name: 'docusaurus-tailwindcss',
configurePostCss(postcssOptions) {
// Appends TailwindCSS and AutoPrefixer.
postcssOptions.plugins.push(require("tailwindcss"));
postcssOptions.plugins.push(require("autoprefixer"));
postcssOptions.plugins.push(require('tailwindcss'));
postcssOptions.plugins.push(require('autoprefixer'));
return postcssOptions;
},
};
@ -174,15 +174,15 @@ const config = {
],
presets: [
[
"@docusaurus/preset-classic",
'@docusaurus/preset-classic',
/** @type {import('@docusaurus/preset-classic').Options} */
{
docs: {
sidebarPath: require.resolve("./sidebars.js"),
editUrl: "https://github.com/meshtastic/meshtastic/edit/master/",
sidebarPath: require.resolve('./sidebars.js'),
editUrl: 'https://github.com/meshtastic/meshtastic/edit/master/',
},
theme: {
customCss: require.resolve("./src/css/custom.css"),
customCss: require.resolve('./src/css/custom.css'),
},
},
],

View file

@ -16,6 +16,7 @@
"@algolia/client-search": "^4.13.0",
"@docusaurus/core": "^2.0.0-beta.18",
"@docusaurus/preset-classic": "^2.0.0-beta.18",
"@headlessui/react": "^1.5.0",
"@mdx-js/react": "^1.6.22",
"autoprefixer": "^10.4.4",
"dotenv": "^16.0.0",
@ -27,7 +28,8 @@
"react-spring": "^9.4.4",
"swr": "^1.2.2",
"tailwindcss": "^3.0.23",
"url-search-params-polyfill": "^8.1.1"
"url-search-params-polyfill": "^8.1.1",
"victory": "^36.3.1"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^2.0.0-beta.18",

View file

@ -5,6 +5,7 @@ specifiers:
'@docusaurus/core': ^2.0.0-beta.18
'@docusaurus/module-type-aliases': ^2.0.0-beta.18
'@docusaurus/preset-classic': ^2.0.0-beta.18
'@headlessui/react': ^1.5.0
'@mdx-js/react': ^1.6.22
'@meshtastic/eslint-config': ^1.0.7
'@tailwindcss/typography': ^0.5.2
@ -26,11 +27,13 @@ specifiers:
tailwindcss: ^3.0.23
typescript: ^4.6.3
url-search-params-polyfill: ^8.1.1
victory: ^36.3.1
dependencies:
'@algolia/client-search': 4.13.0
'@docusaurus/core': 2.0.0-beta.18_28e7016540b0a32b5f8d7be755522ab7
'@docusaurus/preset-classic': 2.0.0-beta.18_cd2ecee38e568e94b4890eebc445da58
'@headlessui/react': 1.5.0_react-dom@17.0.2+react@17.0.2
'@mdx-js/react': 1.6.22_react@17.0.2
autoprefixer: 10.4.4_postcss@8.4.12
dotenv: 16.0.0
@ -43,6 +46,7 @@ dependencies:
swr: 1.2.2_react@17.0.2
tailwindcss: 3.0.23_autoprefixer@10.4.4
url-search-params-polyfill: 8.1.1
victory: 36.3.1_react@17.0.2
devDependencies:
'@docusaurus/module-type-aliases': 2.0.0-beta.18_react-dom@17.0.2+react@17.0.2
@ -2203,6 +2207,17 @@ packages:
dependencies:
'@hapi/hoek': 9.2.1
/@headlessui/react/1.5.0_react-dom@17.0.2+react@17.0.2:
resolution: {integrity: sha512-aaRnYxBb3MU2FNJf3Ut9RMTUqqU3as0aI1lQhgo2n9Fa67wRu14iOGqx93xB+uMNVfNwZ5B3y/Ndm7qZGuFeMQ==}
engines: {node: '>=10'}
peerDependencies:
react: ^16 || ^17 || ^18
react-dom: ^16 || ^17 || ^18
dependencies:
react: 17.0.2
react-dom: 17.0.2_react@17.0.2
dev: false
/@humanwhocodes/config-array/0.9.5:
resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==}
engines: {node: '>=10.10.0'}
@ -4147,6 +4162,76 @@ packages:
/csstype/3.0.11:
resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==}
/d3-array/1.2.4:
resolution: {integrity: sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==}
dev: false
/d3-array/2.3.3:
resolution: {integrity: sha512-syv3wp0U5aB6toP2zb2OdBkhTy1MWDsCAaYk6OXJZv+G4u7bSWEmYgxLoFyc88RQUhZYGCebW9a9UD1gFi5+MQ==}
dev: false
/d3-collection/1.0.7:
resolution: {integrity: sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==}
dev: false
/d3-color/1.4.1:
resolution: {integrity: sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==}
dev: false
/d3-ease/1.0.7:
resolution: {integrity: sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==}
dev: false
/d3-format/1.4.5:
resolution: {integrity: sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==}
dev: false
/d3-interpolate/1.4.0:
resolution: {integrity: sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==}
dependencies:
d3-color: 1.4.1
dev: false
/d3-path/1.0.9:
resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==}
dev: false
/d3-scale/1.0.7:
resolution: {integrity: sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==}
dependencies:
d3-array: 1.2.4
d3-collection: 1.0.7
d3-color: 1.4.1
d3-format: 1.4.5
d3-interpolate: 1.4.0
d3-time: 1.1.0
d3-time-format: 2.3.0
dev: false
/d3-shape/1.3.7:
resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==}
dependencies:
d3-path: 1.0.9
dev: false
/d3-time-format/2.3.0:
resolution: {integrity: sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==}
dependencies:
d3-time: 1.1.0
dev: false
/d3-time/1.1.0:
resolution: {integrity: sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==}
dev: false
/d3-timer/1.0.10:
resolution: {integrity: sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==}
dev: false
/d3-voronoi/1.1.4:
resolution: {integrity: sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==}
dev: false
/debug/2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
dependencies:
@ -4240,6 +4325,16 @@ packages:
slash: 3.0.0
dev: false
/delaunator/4.0.1:
resolution: {integrity: sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag==}
dev: false
/delaunay-find/0.0.6:
resolution: {integrity: sha512-1+almjfrnR7ZamBk0q3Nhg6lqSe6Le4vL0WJDSMx4IDbQwTpUTXPjxC00lqLBT8MYsJpPCbI16sIkw9cPsbi7Q==}
dependencies:
delaunator: 4.0.1
dev: false
/depd/1.1.2:
resolution: {integrity: sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=}
engines: {node: '>= 0.6'}
@ -6018,6 +6113,10 @@ packages:
resolution: {integrity: sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=}
dev: true
/json-stringify-safe/5.0.1:
resolution: {integrity: sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=}
dev: false
/json5/1.0.1:
resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==}
hasBin: true
@ -7565,6 +7664,10 @@ packages:
resolution: {integrity: sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==}
dev: false
/react-fast-compare/2.0.4:
resolution: {integrity: sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==}
dev: false
/react-fast-compare/3.2.0:
resolution: {integrity: sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==}
@ -8992,6 +9095,372 @@ packages:
vfile-message: 2.0.4
dev: false
/victory-area/36.3.0_react@17.0.2:
resolution: {integrity: sha512-vf/vR+6k4VyeGOuRvc651fN3ItsU6NoGkHrtafCDmJ/KH9bcwgfQS9uZn0aXHC9Vr9rarbFFTrBC6/gLhBYSRA==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
d3-shape: 1.3.7
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-axis/36.3.0_react@17.0.2:
resolution: {integrity: sha512-k4h27pN2RHd1TYLia4SbaFn8NHddf7Mzfmqt4WUCLYmkN+R3xQ3METD+X6kwfZmV6FffclJVoD1Errlar/mGdQ==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-bar/36.3.0_react@17.0.2:
resolution: {integrity: sha512-8qitdaC2LYzxuQfbmsZLQ8VQksumbofD1ks0PimYM2exnBdo9nKi5GB0zuLVeuxvq36qlXUpPyH1VRUyUnCMPg==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
d3-shape: 1.3.7
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-box-plot/36.3.0_react@17.0.2:
resolution: {integrity: sha512-FtRMRMoGxIqOKMx7bzU0h63BPeRh4tiMvR1xZ+n32SJOFFnTC9YwsCLM6o03lBx5af6PegV05JLZs6dVgKEMcA==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
d3-array: 1.2.4
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-brush-container/36.3.0_react@17.0.2:
resolution: {integrity: sha512-iaal/Dn5o113TFZ2i4GIApZq6lsfSx9MwD+1cQ8yEC67/Krzn127AfDXfPYKUiFhD+NvmCTg8OGsryt4MEHbsw==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
react-fast-compare: 2.0.4
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-brush-line/36.3.0_react@17.0.2:
resolution: {integrity: sha512-idOU6G1xcS780QR7GEEdBqd+48SQPxzo8pxC3eqdN0IUhdIcEZF/untJhehQiQrt8MFvMQLnpW2k1JaqnV2Peg==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
react-fast-compare: 2.0.4
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-candlestick/36.3.0_react@17.0.2:
resolution: {integrity: sha512-I2LnJDi/wmYhNyLE3GqJwsxJi/rx0ixY3G5tW3Wp+zmzC3qXfJ8ucU+3qNfL3pj5z5Jda1KYYo0Ei6Rq2k4jwg==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-canvas/36.3.0_react@17.0.2:
resolution: {integrity: sha512-FQfjjZ7YzBPnVvxg1WMFDeXOcLHRXAD7t6qxS0sDcwGerJ8dn51Iel/Kd+jKiXT25W34pUqMh+cUsGIwkpTsZQ==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-chart/36.3.0_react@17.0.2:
resolution: {integrity: sha512-8BM/xUavO6ineRzhycehHCvf3NT5Z+8YepdvVOVX6PGJUx9rvmZCAVDlB6fDh7kuDdq5mtDFzos+B+BglC1rcA==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
react-fast-compare: 2.0.4
victory-axis: 36.3.0_react@17.0.2
victory-core: 36.3.0_react@17.0.2
victory-polar-axis: 36.3.0_react@17.0.2
victory-shared-events: 36.3.0_react@17.0.2
dev: false
/victory-core/36.3.0_react@17.0.2:
resolution: {integrity: sha512-X75h6FvLCO+9u/PbCkHat7CmcOeJrkTLz0uUhLqryofJN81nfZ7VamRDfw5KxDWYlCB5hmxX+dfjzteaqndgeA==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
d3-ease: 1.0.7
d3-interpolate: 1.4.0
d3-scale: 1.0.7
d3-shape: 1.3.7
d3-timer: 1.0.10
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
react-fast-compare: 2.0.4
dev: false
/victory-create-container/36.3.1_react@17.0.2:
resolution: {integrity: sha512-ved4WQH7UxhQZAHZsRK/B/bqIvQZi6EeHR7CkCgvanjYY3mkCM/avv9TNC5RzrNp/DeRC2xdFoBGVuUaLPLnTw==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
react: 17.0.2
victory-brush-container: 36.3.0_react@17.0.2
victory-core: 36.3.0_react@17.0.2
victory-cursor-container: 36.3.0_react@17.0.2
victory-selection-container: 36.3.0_react@17.0.2
victory-voronoi-container: 36.3.1_react@17.0.2
victory-zoom-container: 36.3.0_react@17.0.2
dev: false
/victory-cursor-container/36.3.0_react@17.0.2:
resolution: {integrity: sha512-iR+8R1kEul22tifSxr8lnyR0kJ9Wb4VGCVyLgH3VGiJkmbaTRLt0fvKxP+sFbrVIngxTemiVuFBi+nwi48lpAA==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-errorbar/36.3.0_react@17.0.2:
resolution: {integrity: sha512-Pa/p/36KH45xBivuJsmHZRiWjVJWAqMzRKZrBrY4sPmItq5KMgmDYJLzMgl4F+ZFCIUt6OQP38MnOq47EgOkFg==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-group/36.3.0_react@17.0.2:
resolution: {integrity: sha512-JsO/CMxQrGOv+GK55ssTWtcASVyC2Y9kJ0a6xWyGKAWufGDehvdmwg2HxAcx9QeIu9vQ0qQOYc3Yk2/DwW0bJQ==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
react-fast-compare: 2.0.4
victory-core: 36.3.0_react@17.0.2
victory-shared-events: 36.3.0_react@17.0.2
dev: false
/victory-histogram/36.3.0_react@17.0.2:
resolution: {integrity: sha512-C1IlANqjiUMOzvpaDQZKLgMVf9wEhYBVm9SpGAHmMSo45fGH89Knp+PgKMFKom2BXjuBPAyZjETdulTKDPOHsw==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
d3-array: 2.3.3
d3-scale: 1.0.7
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
react-fast-compare: 2.0.4
victory-bar: 36.3.0_react@17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-legend/36.3.0_react@17.0.2:
resolution: {integrity: sha512-5gaUBXQcJfA4BQpatCG1X/evAgrzBfMIHhbEkwH4jCtt9aVU+b2qMYRs7nw+Rnzz5Cicb6cwajHgem9mv3E04w==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-line/36.3.0_react@17.0.2:
resolution: {integrity: sha512-qLDHBcmFRMytKACgDt3z6ktuqTNKHvVPifoSrAnORfFlXxMJlGB8+XZAGeAP6DeC5jDOb+sc6DFKzSOIvFLnqA==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
d3-shape: 1.3.7
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-pie/36.3.0_react@17.0.2:
resolution: {integrity: sha512-ZApiB4OW2l6vHSxRZpaqklQ9gnOshqqZBCHgcyr2kbx+oLJMeKi+mJbh/YS1btFCPwL7bSSO4EYdBuaGyAX9VA==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
d3-shape: 1.3.7
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-polar-axis/36.3.0_react@17.0.2:
resolution: {integrity: sha512-xbxHDMJi3CG1dB8ATiURNg0NVVECk0z82soAwVSA5jPmGRmW4t8ByKBfSsw/ommeDclJ95X8+jtR1Jxd+mjsfw==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-scatter/36.3.0_react@17.0.2:
resolution: {integrity: sha512-PfgM/y7tV/e1Y3ew5R2wvM1O11+EXoToQ2KR0/WTzybwD6R5OghgbcM1xS2NUCtOeubYDkkXjBogZc0rDyyfjA==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-selection-container/36.3.0_react@17.0.2:
resolution: {integrity: sha512-RdFkmxoy2HkbZ9ebuj5Mlx+/OTtPjoUO+FYXItc/Le+HWcGNvkhzmyfZJ+JZAi7atwevCEQawsdUHslIf9mZig==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-shared-events/36.3.0_react@17.0.2:
resolution: {integrity: sha512-XnTzwlRy7uUgBm8NW1tLn4wx3M4lkFO/jA3DHFMYgCVzq+Fu7Tu+BmMPZ8m5DxZFwxKP4HVlYuYKwoQu7yerWA==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
json-stringify-safe: 5.0.1
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
react-fast-compare: 2.0.4
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-stack/36.3.0_react@17.0.2:
resolution: {integrity: sha512-QtW+UReATWUojUyv2II+i0d+RonLRcxFIhCFPO4Eo6tHS7ZqvBQWii0N3FRlbl65h2jW4By+xjoNxyHoSsbJJQ==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
react-fast-compare: 2.0.4
victory-core: 36.3.0_react@17.0.2
victory-shared-events: 36.3.0_react@17.0.2
dev: false
/victory-tooltip/36.3.0_react@17.0.2:
resolution: {integrity: sha512-GM8hOmbcKZRQCtWDi9bJrqvjUEryqwXcw8onz5sFGvPPONLu7nYKCO0s6/m3wCHqAWqotPpu6FTtxXSChYJ6kA==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-voronoi-container/36.3.1_react@17.0.2:
resolution: {integrity: sha512-bFznyx0dLRb84nrGhOslN/e/3mfEGCmlPbvEFv8SGBVZxvAQv2go4byhZx4qvFbcKf2Wyx8svyxCsfS9g/OsEw==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
delaunay-find: 0.0.6
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
react-fast-compare: 2.0.4
victory-core: 36.3.0_react@17.0.2
victory-tooltip: 36.3.0_react@17.0.2
dev: false
/victory-voronoi/36.3.0_react@17.0.2:
resolution: {integrity: sha512-P+DMO+mLtpqsH1rfnLBBKanObnk55X44km+eIiqr3NuFJBVOT5XCaiv2p6gbU1adv5ciAxxpN6KAo8TgZwupgg==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
d3-voronoi: 1.1.4
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory-zoom-container/36.3.0_react@17.0.2:
resolution: {integrity: sha512-FG+nh5pi4xCP7EBI+rtc0q3U6RrkOW+ophOgpGCpNGswvvuREl+DtdS/dPjYk+Ktt45f1qmVrT26ovJ4IiMKEA==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
lodash: 4.17.21
prop-types: 15.8.1
react: 17.0.2
victory-core: 36.3.0_react@17.0.2
dev: false
/victory/36.3.1_react@17.0.2:
resolution: {integrity: sha512-zqmld8hwkV9ysYRUIwfIR1/smjhLEr+m8XZ5xLPK7Io3BLUEcdeJd7bK/Edb4Scv91DodkF9d5DVmvyzEph89g==}
peerDependencies:
react: ^16.6.0 || ^17.0.0
dependencies:
react: 17.0.2
victory-area: 36.3.0_react@17.0.2
victory-axis: 36.3.0_react@17.0.2
victory-bar: 36.3.0_react@17.0.2
victory-box-plot: 36.3.0_react@17.0.2
victory-brush-container: 36.3.0_react@17.0.2
victory-brush-line: 36.3.0_react@17.0.2
victory-candlestick: 36.3.0_react@17.0.2
victory-canvas: 36.3.0_react@17.0.2
victory-chart: 36.3.0_react@17.0.2
victory-core: 36.3.0_react@17.0.2
victory-create-container: 36.3.1_react@17.0.2
victory-cursor-container: 36.3.0_react@17.0.2
victory-errorbar: 36.3.0_react@17.0.2
victory-group: 36.3.0_react@17.0.2
victory-histogram: 36.3.0_react@17.0.2
victory-legend: 36.3.0_react@17.0.2
victory-line: 36.3.0_react@17.0.2
victory-pie: 36.3.0_react@17.0.2
victory-polar-axis: 36.3.0_react@17.0.2
victory-scatter: 36.3.0_react@17.0.2
victory-selection-container: 36.3.0_react@17.0.2
victory-shared-events: 36.3.0_react@17.0.2
victory-stack: 36.3.0_react@17.0.2
victory-tooltip: 36.3.0_react@17.0.2
victory-voronoi: 36.3.0_react@17.0.2
victory-voronoi-container: 36.3.1_react@17.0.2
victory-zoom-container: 36.3.0_react@17.0.2
dev: false
/wait-on/6.0.1:
resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==}
engines: {node: '>=10.0.0'}

@ -1 +1 @@
Subproject commit 99ce57802da9e8a3106d29b94e14e4a090cde3b3
Subproject commit 7c1b6cb6ad143b29c1031e307ed7d1dbe1280e92

View file

@ -1,318 +1,319 @@
module.exports = {
About: {
"About Meshtastic": [
"about/overview",
'About Meshtastic': [
'about/overview',
{
Concepts: [
"about/concepts/overview",
"about/concepts/channels",
"about/concepts/clients",
"about/concepts/external-devices",
"about/concepts/internet",
"about/concepts/mesh",
'about/concepts/overview',
'about/concepts/channels',
'about/concepts/clients',
'about/concepts/external-devices',
'about/concepts/internet',
'about/concepts/mesh',
],
},
"about/expectations",
'about/expectations',
{
FAQs: [
"faq/faq",
"faq/antenna",
"faq/bluetooth",
"faq/channel",
'faq/faq',
'faq/antenna',
'faq/bluetooth',
'faq/channel',
{
Clients: [
"faq/client-android",
"faq/client-python-cli",
"faq/client-ios",
"faq/client-web",
'faq/client-android',
'faq/client-python-cli',
'faq/client-ios',
'faq/client-web',
],
},
{
Devices: [
"faq/device",
"faq/device-tbeam",
"faq/device-wisblock",
'faq/device',
'faq/device-tbeam',
'faq/device-wisblock',
]
},
{
"Flashing Firmware": ["faq/m-flasher"],
'Flashing Firmware': ['faq/m-flasher'],
},
"faq/mesh",
"faq/mqtt",
"faq/modules",
"faq/wifi",
'faq/mesh',
'faq/mqtt',
'faq/modules',
'faq/wifi',
],
},
],
},
Software: {
Software: [
"software/overview",
'software/overview',
{
"Meshtastic device": [
"software/device/device-firmware",
"software/device/device-channels",
"software/device/device-remote-admin",
"software/device/remote-hardware-service",
"software/device/device-power",
"software/device/critical-error-codes",
"software/device/ham",
'Meshtastic device': [
'software/device/device-firmware',
'software/device/device-channels',
'software/device/device-remote-admin',
'software/device/remote-hardware-service',
'software/device/device-power',
'software/device/critical-error-codes',
'software/device/ham',
],
},
{
"Meshtastic Android": [
"software/android/android-installation",
"software/android/android-usage",
'Meshtastic Android': [
'software/android/android-installation',
'software/android/android-usage',
],
},
{
"Meshtastic Apple": [
"software/apple/ios-development",
"software/apple/ios",
"software/apple/ipados",
"software/apple/macos",
'Meshtastic Apple': [
'software/apple/ios-development',
'software/apple/ios',
'software/apple/ipados',
'software/apple/macos',
],
},
{
"Meshtastic.js": [
"software/js/getting-started",
"software/js/connecting",
"software/js/events",
"software/js/http-api",
'Meshtastic.js': [
'software/js/getting-started',
'software/js/connecting',
'software/js/events',
'software/js/http-api',
{
type: "link",
label: "API Docs",
href: "https://js.meshtastic.org",
type: 'link',
label: 'API Docs',
href: 'https://js.meshtastic.org',
},
],
},
{
"Meshtastic-python": [
"software/python/python-installation",
"software/python/python-standalone",
"software/python/python-cli",
"software/python/python-uses",
"software/python/python-stream",
'Meshtastic-python': [
'software/python/python-installation',
'software/python/python-standalone',
'software/python/python-cli',
'software/python/python-uses',
'software/python/python-stream',
{
type: "link",
label: "API Docs",
href: "https://python.meshtastic.org/",
type: 'link',
label: 'API Docs',
href: 'https://python.meshtastic.org/',
},
],
},
{
Modules: [
"software/modules/modules",
"software/modules/range-test-module",
"software/modules/ext-notif-module",
"software/modules/canned-message-module",
"software/modules/serial-module",
"software/modules/store-forward-module",
"software/modules/telemetry-module",
'software/modules/modules',
'software/modules/range-test-module',
'software/modules/ext-notif-module',
'software/modules/canned-message-module',
'software/modules/serial-module',
'software/modules/store-forward-module',
'software/modules/telemetry-module',
],
},
{
"Web interface": [
"software/web/web-app-software",
"software/web/web-partitions-software",
"software/web/web-development-software",
'Web interface': [
'software/web/web-app-software',
'software/web/web-partitions-software',
'software/web/web-development-software',
],
},
{
"Community projects": [
"software/community/community-overview",
"software/community/community-atak",
"software/community/community-pygui",
"software/community/community-go",
'Community projects': [
'software/community/community-overview',
'software/community/community-atak',
'software/community/community-pygui',
'software/community/community-go',
],
},
{
Other: [
"software/other/sw-design",
"software/other/remote-hardware-service",
"software/other/rak815",
"software/other/power",
"software/other/pinetab",
"software/other/nrf52-TODO",
"software/other/mqtt",
"software/other/install-OSX",
"software/other/esp32-arduino-build",
"software/other/ant",
"software/other/docker",
'software/other/sw-design',
'software/other/remote-hardware-service',
'software/other/rak815',
'software/other/power',
'software/other/pinetab',
'software/other/nrf52-TODO',
'software/other/mqtt',
'software/other/install-OSX',
'software/other/esp32-arduino-build',
'software/other/ant',
'software/other/docker',
],
},
],
"Additional Documentation": [
{ type: "ref", id: "getting-started/overview" },
{ type: "ref", id: "settings/overview" },
{ type: "ref", id: "hardware/overview" },
{ type: "ref", id: "developers/overview" },
{ type: "ref", id: "developers/maintaining-documentation/overview" },
{ type: "ref", id: "legal/overview" },
'Additional Documentation': [
{ type: 'ref', id: 'getting-started/overview' },
{ type: 'ref', id: 'settings/overview' },
{ type: 'ref', id: 'hardware/overview' },
{ type: 'ref', id: 'developers/overview' },
{ type: 'ref', id: 'developers/maintaining-documentation/overview' },
{ type: 'ref', id: 'legal/overview' },
],
},
Configuration: {
"Getting Started": [
"getting-started/overview",
'Getting Started': [
'getting-started/overview',
{
"Flashing firmware": [
"getting-started/flashing-firmware",
"getting-started/meshtastic-flasher",
'Flashing firmware': [
'getting-started/flashing-firmware',
'getting-started/meshtastic-flasher',
{
"Manual Method": [
"getting-started/flashing-esp32",
"getting-started/flashing-nrf52",
'Manual Method': [
'getting-started/flashing-esp32',
'getting-started/flashing-nrf52',
],
},
],
},
{
"Connect to Device": ["getting-started/clients"],
'Connect to Device': ['getting-started/clients'],
},
"getting-started/first-steps",
'getting-started/first-steps',
],
"Device Settings": [
"settings/overview",
"settings/channel",
"settings/gps",
"settings/ham",
"settings/mqtt",
"settings/power",
"settings/router",
"settings/wifi",
'Device Settings': [
'settings/overview',
'settings/channel',
'settings/gps',
'settings/ham',
'settings/mqtt',
'settings/power',
'settings/router',
'settings/wifi',
{
Modules: [
"settings/canned-message-module",
"settings/input-broker-module",
"settings/external-notification-module",
"settings/range-test-module",
"settings/serial-module",
"settings/store-and-forward-module",
"settings/telemetry-module",
'settings/canned-message-module',
'settings/input-broker-module',
'settings/external-notification-module',
'settings/range-test-module',
'settings/serial-module',
'settings/store-and-forward-module',
'settings/telemetry-module',
],
Advanced: ["settings/channel-advanced", "settings/misc"],
Advanced: ['settings/channel-advanced', 'settings/misc'],
},
],
"Additional Documentation": [
{ type: "ref", id: "hardware/overview" },
{ type: "ref", id: "software/overview" },
{ type: "ref", id: "developers/overview" },
{ type: "ref", id: "developers/maintaining-documentation/overview" },
{ type: "ref", id: "legal/overview" },
'Additional Documentation': [
{ type: 'ref', id: 'hardware/overview' },
{ type: 'ref', id: 'software/overview' },
{ type: 'ref', id: 'developers/overview' },
{ type: 'ref', id: 'developers/maintaining-documentation/overview' },
{ type: 'ref', id: 'legal/overview' },
],
},
Hardware: {
Hardware: [
"hardware/overview",
'hardware/overview',
{
type: "link",
label: "Hardware List",
href: "/hardware",
type: 'link',
label: 'Hardware List',
href: '/hardware',
},
{
"Supported Hardware": [
"hardware/supported/tbeam",
"hardware/supported/lora",
"hardware/supported/heltec",
"hardware/supported/techo",
"hardware/supported/wisBlock",
"hardware/supported/linux",
'Supported Hardware': [
'hardware/supported/tbeam',
'hardware/supported/lora',
'hardware/supported/heltec',
'hardware/supported/techo',
'hardware/supported/wisBlock',
'hardware/supported/linux',
],
},
"hardware/buttons",
"hardware/battery",
"hardware/gpsmodule",
'hardware/buttons',
'hardware/battery',
'hardware/gpsmodule',
{
Antennas: [
"hardware/antenna/antenna",
"hardware/antenna/aerials",
"hardware/antenna/non-aerial",
"hardware/antenna/antenna-testing",
"hardware/antenna/resources",
'hardware/antenna/antenna',
'hardware/antenna/aerials',
'hardware/antenna/non-aerial',
'hardware/antenna/antenna-testing',
'hardware/antenna/resources',
],
},
],
"Additional Documentation": [
{ type: "ref", id: "getting-started/overview" },
{ type: "ref", id: "settings/overview" },
{ type: "ref", id: "software/overview" },
{ type: "ref", id: "developers/overview" },
{ type: "ref", id: "developers/maintaining-documentation/overview" },
{ type: "ref", id: "legal/overview" },
'Additional Documentation': [
{ type: 'ref', id: 'getting-started/overview' },
{ type: 'ref', id: 'settings/overview' },
{ type: 'ref', id: 'software/overview' },
{ type: 'ref', id: 'developers/overview' },
{ type: 'ref', id: 'developers/maintaining-documentation/overview' },
{ type: 'ref', id: 'legal/overview' },
],
},
Contribute: {
Developers: [
"developers/overview",
'developers/overview',
{
Protobufs: ["developers/protobufs/api"],
Protobufs: ['developers/protobufs/api'],
},
"developers/api",
"developers/publish",
'developers/api',
'developers/publish',
{
Firmware: [
"developers/firmware/build",
"developers/firmware/stacktrace-decode",
"developers/firmware/device-api",
"developers/firmware/radio-settings",
"developers/firmware/mesh-alg",
"developers/firmware/encryption",
"developers/firmware/portnum",
"developers/firmware/module-api",
"developers/firmware/http-api",
"developers/firmware/documents",
'developers/firmware/build',
'developers/firmware/stacktrace-decode',
'developers/firmware/device-api',
'developers/firmware/radio-settings',
'developers/firmware/mesh-alg',
'developers/firmware/encryption',
'developers/firmware/portnum',
'developers/firmware/module-api',
'developers/firmware/http-api',
'developers/firmware/documents',
],
},
{
"Android App": [
"developers/android/build-app",
"developers/android/mapbox",
'Android App': [
'developers/android/build-app',
'developers/android/mapbox',
],
"Maintaining Documentation": [
"developers/maintaining-documentation/overview",
'Maintaining Documentation': [
'developers/maintaining-documentation/overview',
{
Dependencies: [
"developers/maintaining-documentation/docusaurus",
"developers/maintaining-documentation/github",
"developers/maintaining-documentation/vercel",
'developers/maintaining-documentation/docusaurus',
'developers/maintaining-documentation/github',
'developers/maintaining-documentation/vercel',
],
},
{
Examples: [
"developers/maintaining-documentation/serve-docs-locally",
'developers/maintaining-documentation/serve-docs-locally',
],
},
{
"Style Guides": [
"developers/maintaining-documentation/style-guides/style-guide-settings",
'Style Guides': [
'developers/maintaining-documentation/style-guides/markdown-features',
'developers/maintaining-documentation/style-guides/style-guide-settings',
],
},
],
},
],
"Additional Documentation": [
{ type: "ref", id: "getting-started/overview" },
{ type: "ref", id: "settings/overview" },
{ type: "ref", id: "hardware/overview" },
{ type: "ref", id: "software/overview" },
{ type: "ref", id: "legal/overview" },
{ type: "ref", id: "developers/overview" },
'Additional Documentation': [
{ type: 'ref', id: 'getting-started/overview' },
{ type: 'ref', id: 'settings/overview' },
{ type: 'ref', id: 'hardware/overview' },
{ type: 'ref', id: 'software/overview' },
{ type: 'ref', id: 'legal/overview' },
{ type: 'ref', id: 'developers/overview' },
],
},
Legal: {
Legal: [
"legal/overview",
"legal/licensing",
"legal/trademark",
"legal/privacy",
'legal/overview',
'legal/licensing',
'legal/trademark',
'legal/privacy',
],
"Additional Documentation": [
{ type: "ref", id: "getting-started/overview" },
{ type: "ref", id: "settings/overview" },
{ type: "ref", id: "hardware/overview" },
{ type: "ref", id: "software/overview" },
{ type: "ref", id: "developers/overview" },
'Additional Documentation': [
{ type: 'ref', id: 'getting-started/overview' },
{ type: 'ref', id: 'settings/overview' },
{ type: 'ref', id: 'hardware/overview' },
{ type: 'ref', id: 'software/overview' },
{ type: 'ref', id: 'developers/overview' },
],
},
};

View file

@ -0,0 +1,13 @@
import React from 'react';
export interface ColorModeProps {
children: React.ReactNode;
}
export const Dark = ({ children }: ColorModeProps): JSX.Element => {
return <div className="hideLight">{children}</div>;
};
export const Light = ({ children }: ColorModeProps): JSX.Element => {
return <div className="hideDark">{children}</div>;
};

54
src/components/Modal.tsx Normal file
View file

@ -0,0 +1,54 @@
import React, { Fragment } from 'react';
import { Dialog, Transition } from '@headlessui/react';
export interface ModalProps {
open: boolean;
onClose: () => void;
children: React.ReactNode;
}
export const Modal = ({ open, onClose, children }: ModalProps): JSX.Element => {
return (
<Transition appear show={open} as={Fragment}>
<Dialog
as="div"
className="fixed inset-0 z-10 overflow-y-auto"
onClose={onClose}
>
<div className="min-h-screen px-4 text-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-100"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className="fixed inset-0 backdrop-blur-md" />
</Transition.Child>
{/* This element is to trick the browser into centering the modal contents. */}
<span
className="inline-block h-screen align-middle"
aria-hidden="true"
>
&#8203;
</span>
<Transition.Child
as={Fragment}
enter="ease-out duration-100"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
{children}
</Transition.Child>
</div>
</Dialog>
</Transition>
);
};

View file

@ -0,0 +1,25 @@
import React from 'react';
import Layout from '@theme/Layout';
export interface PageLayoutProps {
title: string;
description: string;
children: React.ReactNode;
}
export const PageLayout = ({
title,
description,
children,
}: PageLayoutProps): JSX.Element => {
return (
<Layout title={title} description={description}>
{children}
</Layout>
);
};
export interface ColorModeProps {
children: React.ReactNode;
}

View 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>
);
};

View 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>
);
};

View file

@ -0,0 +1,67 @@
import React, { useState } from 'react';
import { IDevice, Stability } from '@site/src/data/device';
import { HardwareModal } from './HardwareModal';
export interface HardwareCardProps {
device: IDevice;
}
export const HardwareCard = ({ device }: HardwareCardProps): JSX.Element => {
const [open, setOpen] = useState(false);
return (
<>
<li
className="group relative"
onClick={() => {
setOpen(true);
}}
>
<div className="overflow-hidden rounded-lg">
<div
className={`flex aspect-[4/3] overflow-hidden ${device.misc.Gradient}`}
>
<img
src={device.misc.ImagePath}
alt=""
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">
<span className="sr-only">View details for {device.name}</span>
</button>
</div>
<div className="flex">
<div>
<p className="pointer-events-none mt-2 block truncate text-sm font-medium text-primaryInv">
{device.name}
</p>
<p className="pointer-events-none flex gap-1 text-sm font-medium text-mute">
<div
className={`my-auto h-3 w-3 rounded-full ${
device.misc.Stability === Stability.Broken
? 'bg-red-500'
: device.misc.Stability === Stability.Unstable
? 'bg-orange-500'
: device.misc.Stability === Stability.Semi
? 'bg-cyan-500'
: 'bg-green-500'
}`}
/>
<div className="my-auto">{Stability[device.misc.Stability]}</div>
</p>
</div>
</div>
</li>
<HardwareModal
open={open}
close={() => {
setOpen(false);
}}
device={device}
/>
</>
);
};

View file

@ -0,0 +1,127 @@
import React, { useState } from 'react';
import { FiBluetooth, FiChevronRight, FiWifi, FiX } from 'react-icons/fi';
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 {
device: IDevice;
open: boolean;
close: () => void;
}
export const HardwareModal = ({
device,
open,
close,
}: HardwareModal): JSX.Element => {
const colors = ['#428517', '#77D200', '#D6D305', '#EC8E19', '#C92B05'];
const [hideDetails, setHideDetails] = useState(false);
return (
<Modal open={open} onClose={close}>
<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 md:rounded-l-2xl md:rounded-tr-none ${
device.misc.Gradient
} ${hideDetails ? 'w-full' : ''}`}
>
<img
src={device.misc.ImagePath}
alt=""
className="pointer-events-none m-auto object-cover p-2 group-hover:opacity-75"
/>
<div className="absolute -bottom-4 flex w-full md:bottom-auto md:-right-4 md:h-full md:w-auto ">
<div
onClick={() => {
setHideDetails(!hideDetails);
}}
className="m-auto flex cursor-pointer rounded-full bg-secondary p-2 shadow-md hover:bg-tertiary"
>
<FiChevronRight
className={`m-auto ${
hideDetails
? 'rotate-90 md:rotate-180'
: '-rotate-90 md:rotate-0'
}`}
/>
</div>
</div>
{!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 && (
<Badge
name="Bluetooth"
color="bg-blue-500"
icon={<FiBluetooth />}
/>
)}
{device.features.WiFi && (
<Badge name="WiFi" color="bg-orange-500" icon={<FiWifi />} />
)}
</div>
)}
</div>
<div
className="absolute right-0 mr-2 flex cursor-pointer rounded-b-full bg-secondary p-3 shadow-md hover:bg-tertiary md:mt-2 md:rounded-full"
onClick={close}
>
<FiX className="m-auto" />
</div>
<div
className={`transition-[all] duration-100 ease-linear ${
hideDetails ? 'h-7 bg-base md:h-auto md:w-7' : 'w-full'
}`}
>
<Transition
appear
as={'div'}
className="flex h-full flex-col"
show={!hideDetails}
enter="ease-out duration-100 delay-100"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-100 delay-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<>
<div className="flex shadow-md md:pb-2">
<VariantSelectButton options={device.variants} />
</div>
<div className="flex h-full bg-base p-2 md:p-4">
<Tab.Group
as="div"
className="flex-grow rounded-2xl bg-primary p-2"
>
<Tab.List className="flex gap-2">
<CardTab title="Info" />
<CardTab title="Power" />
<CardTab title="Pinout" />
</Tab.List>
<Tab.Panels as="div" className="">
<InfoTab device={device} />
<PowerTab device={device} />
<PinoutTab device={device} />
</Tab.Panels>
</Tab.Group>
</div>
</>
</Transition>
</div>
</div>
</div>
</Modal>
);
};

View 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>;
};

View 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>;
};

View 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>;
};

View file

@ -0,0 +1,81 @@
import React, { Fragment, useState } from 'react';
import { FiCheck } from 'react-icons/fi';
import { HiSelector } from 'react-icons/hi';
import { Listbox, Transition } from '@headlessui/react';
import type { Variant } from '@site/src/data/device.js';
export interface VariantSelectButtonProps {
options: Variant[];
}
export const VariantSelectButton = ({
options,
}: VariantSelectButtonProps): JSX.Element => {
const [selected, setSelected] = useState(options[options.length - 1]);
return (
<Listbox value={selected} onChange={setSelected}>
{({ open }) => (
<>
<div className="relative">
<Listbox.Button className="relative -mt-5 ml-2 flex w-fit gap-1 rounded-lg bg-secondary p-2 py-2 pl-3 pr-10 text-lg font-medium leading-6 shadow-md hover:bg-tertiary md:mt-2">
<span className="block truncate">{selected.name}</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<HiSelector
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</span>
</Listbox.Button>
<Transition
show={open}
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-primary py-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
{options.map((variant, index) => (
<Listbox.Option
key={index}
className={({ active }) =>
`relative cursor-default select-none py-2 pl-3 pr-9 ${
active ? 'bg-indigo-600' : ''
}`
}
value={variant}
>
{({ selected, active }) => (
<>
<span
className={`block truncate ${
selected ? 'font-semibold' : 'font-normal'
}`}
>
{variant.name}
</span>
{selected ? (
<span
className={`absolute inset-y-0 right-0 flex items-center pr-4 ${
active ? '' : 'text-indigo-600'
}`}
>
<FiCheck className="h-5 w-5" aria-hidden="true" />
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</>
)}
</Listbox>
);
};

View file

@ -12,6 +12,27 @@
--ifm-color-primary-lighter: rgb(102, 212, 189);
--ifm-color-primary-lightest: rgb(146, 224, 208);
--ifm-code-font-size: 95%;
--ifm-z-index-fixed: 1;
--accent: #67ea94;
--base: #f3f4f6;
--primary: #ffffff;
--secondary: #e5e7eb;
--tertiary: #d1d5db;
--mute: #6b7280;
--primaryInv: #242526;
--secondaryInv: #18191a;
--tertiaryInv: #4C4E50;
}
[data-theme="dark"] {
--base: #38393B;
--primary: #242526;
--secondary: #18191a;
--tertiary: #4C4E50;
--mute: #9ca3af;
--primaryInv: #ffffff;
--secondaryInv: #e5e7eb;
--tertiaryInv: #d1d5db;
}
.docusaurus-highlight-code-line {
@ -112,10 +133,24 @@ a + .navbar__link > svg {
@layer base {
.markdown {
@apply prose prose-lg dark:prose-invert;
@apply prose prose-lg;
}
.col,
.row {
@apply w-full h-full m-0 p-0 flex-grow;
.markdown img {
@apply rounded-lg mx-auto;
}
[data-theme="dark"] .markdown {
@apply prose-invert;
}
[data-theme="dark"] .hideDark {
@apply hidden
}
[data-theme="dark"] .hideLight {
@apply block
}
.hideLight {
@apply hidden
}
.hideDark {
@apply block
}
}

View file

@ -26,6 +26,8 @@ export type GNSSModule = 'NEO-6M' | 'NEO-8M';
export type LORAModule = 'SX1276' | 'SX1262';
export type Variant = DeepPartial<Omit<IDevice, 'variants'>> & { name: string };
export enum Stability {
Stable,
Semi,
@ -47,6 +49,7 @@ export interface IDevice {
SuggestedUse: UseCase[];
Stability: Stability;
ImagePath: string;
Gradient: string;
};
features: {
BLE: boolean;
@ -67,5 +70,5 @@ export interface IDevice {
PSRAM: number;
RAM?: number;
};
variants: (DeepPartial<Omit<IDevice, 'variants'>> & { name: string })[];
variants: Variant[];
}

View file

@ -0,0 +1,63 @@
import { IDevice, Stability, UseCase } from '../device';
export const heltec: IDevice = {
name: 'Heltec',
misc: {
Stability: Stability.Unstable,
SuggestedUse: [UseCase.Portable],
ImagePath: '/img/hardware/heltec-v2.png',
Gradient: 'from-pink-300 via-purple-300 to-indigo-400',
},
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',
},
},
],
};

63
src/data/devices/hydra.ts Normal file
View 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',
},
},
],
};

View file

@ -6,6 +6,7 @@ export const rak19003: IDevice = {
Stability: Stability.Stable,
SuggestedUse: [UseCase.Portable],
ImagePath: '/img/hardware/rak/RAK19003.png',
Gradient: 'bg-gradient-to-b from-orange-500 to-yellow-300',
},
features: {
BLE: true,

View file

@ -5,7 +5,8 @@ export const tbeam: IDevice = {
misc: {
Stability: Stability.Stable,
SuggestedUse: [UseCase.Portable],
ImagePath: '/img/hardware/t-beam-meshtastic.png',
ImagePath: '/img/hardware/tbeam-v1.1.svg',
Gradient: 'bg-gradient-to-r from-pink-500 via-red-500 to-yellow-500',
},
features: {
BLE: true,

63
src/data/devices/techo.ts Normal file
View file

@ -0,0 +1,63 @@
import { IDevice, Stability, UseCase } from '../device';
export const techo: IDevice = {
name: 'T-Echo',
misc: {
Stability: Stability.Semi,
SuggestedUse: [UseCase.Portable],
ImagePath: '/img/hardware/t-echo-lilygo.jpg',
Gradient: 'from-gray-700 via-gray-900 to-black',
},
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',
},
},
],
};

View file

@ -1,20 +1,22 @@
import React from 'react';
import { IDevice } from '../../data/device';
import { tbeam } from '../../data/devices/tbeam';
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 Layout from '@theme/Layout';
import { tbeam } from '../../data/devices/tbeam';
import { techo } from '../../data/devices/techo';
const Hardware = (): JSX.Element => {
const [selectedDevice, setSelectedDevice] = React.useState<IDevice>();
const hardware = [
tbeam,
hydra,
rak19003,
rak19003,
rak19003,
rak19003,
rak19003,
rak19003,
rak19003,
heltec,
techo,
rak19003,
rak19003,
rak19003,
@ -23,65 +25,59 @@ const Hardware = (): JSX.Element => {
];
return (
<Layout title="Hardware" description="Supported hardware">
<div className="m-auto flex w-full flex-grow gap-2">
<div className="flex w-2/3 flex-wrap gap-2 overflow-y-auto p-4">
{hardware.map((device) => (
<div
className={`flex cursor-pointer select-none flex-col divide-y rounded-xl border-2 bg-primaryDark shadow-md transition duration-300 ease-in-out hover:scale-95 ${
selectedDevice?.name === device.name
? 'border-accent'
: 'border-secondaryDark'
}`}
onClick={() => {
setSelectedDevice(device);
}}
>
<div className="flex flex-grow">
<img
draggable="false"
className="m-0 w-48 p-4"
src={device.misc.ImagePath}
/>
{/* <img
draggable="false"
className="mt-auto p-4 m-0 w-48"
src="/img/hardware/rak/RAK19003.png"
/> */}
</div>
<div className="p-2">
<div className="text-lg font-medium">{device.name}</div>
<div className="flex">
<div className="m-auto w-min rounded-full bg-secondaryDark px-2 py-0.5 text-sm">
{device.specifications.Chipset}
</div>
{device.features.WiFi && (
<div className="m-auto w-min rounded-full bg-secondaryDark px-2 py-0.5 text-sm">
WiFi
</div>
)}
{device.features.BLE && (
<div className="m-auto w-min rounded-full bg-secondaryDark px-2 py-0.5 text-sm">
BLE
</div>
)}
</div>
</div>
</div>
))}
</div>
{selectedDevice && (
<div className="my-4 w-1/3 flex-grow flex-grow rounded-l-xl bg-primaryDark">
Selected Device {selectedDevice.name}
<h3>Variants:</h3>
{selectedDevice.variants.map((varitant) => (
<div className="">{varitant.name}</div>
))}
<PageLayout title="Hardware" description="Supported hardware">
<div className="border-b border-tertiary p-4">
<div className="sm:flex sm:items-baseline">
<h3 className="text-lg font-medium leading-6 text-gray-900">
Issues
</h3>
<div className="mt-4 sm:mt-0 sm:ml-10">
<nav className="-mb-px flex space-x-8">
<a
href="#"
className="border-indigo-500 text-indigo-600"
aria-current={'page'}
>
Devices
</a>
<a
href="#"
className="hover:border-gray-300', 'whitespace-nowrap border-b-2 border-transparent
px-1 pb-4 text-sm font-medium text-gray-500 hover:text-gray-700"
>
Antennas
</a>
</nav>
</div>
)}
</div>
</div>
</Layout>
<div className="mx-auto max-w-7xl py-8 px-4 sm:px-6 lg:px-8">
<ul
role="list"
className="grid grid-cols-2 gap-x-2 gap-y-4 sm:grid-cols-3 sm:gap-x-6 lg:grid-cols-4 xl:grid-cols-5 xl:gap-x-4"
>
{hardware.map((device, index) => (
<HardwareCard key={index} device={device} />
))}
<li className="group relative">
<a
href="https://github.com/meshtastic/Meshtastic-device/issues/new?assignees=&labels=enhancement%2Ctriage&template=New+Board.yml&title=%5BBoard%5D%3A+"
className="flex aspect-[4/3] rounded-lg border-2 border-dashed border-mute group-hover:border-tertiaryInv"
target="_blank"
rel="noreferrer"
>
<FiPlus className="m-auto h-12 w-12 text-mute group-hover:text-tertiaryInv" />
</a>
<p className="pointer-events-none mt-2 block truncate text-sm font-medium text-primaryInv">
New Board
</p>
<p className="pointer-events-none block text-sm font-medium text-mute">
Want to support a board?
</p>
</li>
</ul>
</div>
</PageLayout>
);
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 798 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 173 KiB

View file

@ -1,15 +1,20 @@
module.exports = {
content: ["./src/**/*.{js,jsx,ts,tsx}"],
content: ['./src/**/*.{js,jsx,ts,tsx}'],
darkMode: 'class',
theme: {
extend: {
colors: {
accent: "#67ea94",
primary: "#f2f2f2",
secondary: "#ffffff",
primaryDark: "#242526",
secondaryDark: "#18191a",
accent: 'var(--accent)',
base: 'var(--base)',
primary: 'var(--primary)',
secondary: 'var(--secondary)',
tertiary: 'var(--tertiary)',
mute: 'var(--mute)',
primaryInv: 'var(--primaryInv)',
secondaryInv: 'var(--secondaryInv)',
tertiaryInv: 'var(--tertiaryInv)',
},
},
},
plugins: [require("@tailwindcss/typography")],
plugins: [require('@tailwindcss/typography')],
};