Add Trunk and lint non mdx files

This commit is contained in:
Sacha Weatherstone 2023-01-19 22:41:44 +10:00
parent f924461192
commit d94b0e9a42
No known key found for this signature in database
GPG key ID: 7AB2D7E206124B31
88 changed files with 1919 additions and 1539 deletions

View file

@ -1,4 +1,9 @@
{
"plugins": ["@docusaurus"],
"extends": ["plugin:@docusaurus/recommended"]
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:@docusaurus/recommended"],
"parser": "@typescript-eslint/parser",
"plugins": ["@docusaurus", "@typescript-eslint"],
"root": true
}

View file

@ -6,9 +6,9 @@ module.exports = {
overrides: {
removeViewBox: false, // https://github.com/svg/svgo/issues/1128
sortAttrs: true,
removeOffCanvasPaths: true,
},
},
},
],
removeOffCanvasPaths: true
}
}
}
]
};

View file

@ -12,7 +12,6 @@ lint:
- actionlint@1.6.22
- gitleaks@8.15.2
- git-diff-check
- oxipng@8.0.0
- shellcheck@0.9.0
- prettier@2.8.2
- shfmt@3.5.0

View file

@ -1,5 +1,3 @@
{
"recommendations": [
"trunk.io"
]
"recommendations": ["trunk.io"]
}

View file

@ -1,4 +1,7 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "trunk.io"
"editor.defaultFormatter": "trunk.io",
"files.associations": {
"*.mdx": "markdown"
}
}

View file

@ -11,7 +11,7 @@ Website and documentation source for the Meshtastic project.
## Stats
![Alt](https://repobeats.axiom.co/api/embed/9ef7282debe009789c697432a86499ac2b058a86.svg 'Repobeats analytics image')
![Alt](https://repobeats.axiom.co/api/embed/9ef7282debe009789c697432a86499ac2b058a86.svg "Repobeats analytics image")
## Development & Building

View file

@ -1,6 +1,5 @@
position: 1 # float position is supported
label: 'Style Guides'
label: "Style Guides"
collapsible: true # make the category collapsible
link:
slug: /development/docs/style-guide

View file

@ -1,144 +1,145 @@
// @ts-check
require('dotenv').config();
require("dotenv").config();
/** @type {import('@docusaurus/types').Config} */
const config = {
title: 'Meshtastic',
title: "Meshtastic",
tagline:
'An open source, off-grid, decentralized, mesh network built to run on affordable, low-power devices',
url: 'https://meshtastic.org',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'design/web/favicon.ico',
organizationName: 'meshtastic',
projectName: 'meshtastic',
"An open source, off-grid, decentralized, mesh network built to run on affordable, low-power devices",
url: "https://meshtastic.org",
baseUrl: "/",
onBrokenLinks: "throw",
onBrokenMarkdownLinks: "warn",
favicon: "design/web/favicon.ico",
organizationName: "meshtastic",
projectName: "meshtastic",
themeConfig: /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ {
announcementBar: {
id: '2_0',
id: "2_0",
content:
'🎉 Meshtastic 2.0 Has Now Launched! Check it Out <a href="/2.0">Here</a> 🎉',
'🎉 Meshtastic 2.0 Has Now Launched! Check it Out <a href="/2.0">Here</a> 🎉'
},
docs: {
sidebar: {
autoCollapseCategories: true,
},
autoCollapseCategories: 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: [
{
label: 'Docs',
to: 'docs/introduction',
label: "Docs",
to: "docs/introduction"
},
{
label: 'Downloads',
to: 'downloads',
label: "Downloads",
to: "downloads"
},
{
label: 'About',
position: 'right',
label: "About",
position: "right",
items: [
{
label: 'Introduction',
to: 'docs/introduction',
label: "Introduction",
to: "docs/introduction"
},
{
label: 'Getting Started',
to: 'docs/getting-started',
label: "Getting Started",
to: "docs/getting-started"
},
{
label: 'Contributing',
to: 'docs/contributing',
label: "Contributing",
to: "docs/contributing"
},
{
label: 'Legal',
to: 'docs/legal',
label: "Legal",
to: "docs/legal"
},
{
label: 'FAQs',
to: 'docs/faq',
},
],
label: "FAQs",
to: "docs/faq"
}
]
},
{
href: 'https://github.com/meshtastic',
position: 'right',
className: 'header-github-link',
'aria-label': 'GitHub repository',
},
],
href: "https://github.com/meshtastic",
position: "right",
className: "header-github-link",
"aria-label": "GitHub repository"
}
]
},
footer: {
copyright: `<a href="https://vercel.com/?utm_source=meshtastic&utm_campaign=oss">Powered by ▲ Vercel</a> | Meshtastic® is a registered trademark of Meshtastic LLC. | <a href="/docs/legal">Legal Information</a>.`,
copyright: `<a href="https://vercel.com/?utm_source=meshtastic&utm_campaign=oss">Powered by ▲ Vercel</a> | Meshtastic® is a registered trademark of Meshtastic LLC. | <a href="/docs/legal">Legal Information</a>.`
},
algolia: {
appId: 'IG2GQB8L3V',
apiKey: '2e4348812173ec7ea6f7879c7032bb21',
indexName: 'meshtastic',
appId: "IG2GQB8L3V",
// trunk-ignore(gitleaks/generic-api-key)
apiKey: "2e4348812173ec7ea6f7879c7032bb21",
indexName: "meshtastic",
contextualSearch: false,
searchPagePath: 'search',
searchPagePath: "search"
},
colorMode: {
respectPrefersColorScheme: true,
respectPrefersColorScheme: true
},
mermaid: {
theme: {light: 'base', dark: 'base'},
theme: { light: "base", dark: "base" },
options: {
themeVariables: {
primaryColor: '#67EA94',
primaryTextColor: 'var(--tw-prose-headings)',
primaryBorderColor: '#4D4D4D',
lineColor: '#EAD667',
secondaryColor: '#EA67BD',
tertiaryColor: '#677CEA'
},
},
primaryColor: "#67EA94",
primaryTextColor: "var(--tw-prose-headings)",
primaryBorderColor: "#4D4D4D",
lineColor: "#EAD667",
secondaryColor: "#EA67BD",
tertiaryColor: "#677CEA"
}
}
}
},
plugins: [
() => {
return {
name: 'docusaurus-tailwindcss',
name: "docusaurus-tailwindcss",
configurePostCss(postcssOptions) {
postcssOptions.plugins.push(require('tailwindcss'));
postcssOptions.plugins.push(require('autoprefixer'));
postcssOptions.plugins.push(require("tailwindcss"));
postcssOptions.plugins.push(require("autoprefixer"));
return postcssOptions;
},
}
};
},
}
],
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/",
breadcrumbs: false,
showLastUpdateAuthor: true,
showLastUpdateAuthor: true
},
theme: {
customCss: require.resolve('./src/css/custom.css'),
},
},
],
customCss: require.resolve("./src/css/custom.css")
}
}
]
],
customFields: {
API_URL: process.env.API_URL,
API_URL: process.env.API_URL
},
markdown: {
mermaid: true,
mermaid: true
},
themes: ['@docusaurus/theme-mermaid'],
themes: ["@docusaurus/theme-mermaid"]
};
module.exports = config;

View file

@ -8,9 +8,7 @@
"start": "docusaurus start",
"build": "docusaurus build",
"serve": "docusaurus serve",
"clear": "docusaurus clear",
"format": "prettier --write 'docs/**/*{.md,.mdx}' 'src/**/*.{ts,tsx}'",
"lint": "eslint src/**/*.{ts,tsx}"
"clear": "docusaurus clear"
},
"dependencies": {
"@algolia/client-search": "^4.14.3",
@ -22,9 +20,12 @@
"@heroicons/react": "^2.0.13",
"@mdx-js/react": "^1.6.22",
"@meshtastic/meshtasticjs": "2.0.13-0",
"@typescript-eslint/eslint-plugin": "^5.48.2",
"@typescript-eslint/parser": "^5.48.2",
"autoprefixer": "^10.4.13",
"base64-js": "^1.5.1",
"dotenv": "^16.0.3",
"eslint": "^8.32.0",
"framer-motion": "^6.5.1",
"postcss": "^8.4.21",
"react": "^17.0.2",
@ -37,6 +38,7 @@
"use-breakpoint": "^3.0.6"
},
"devDependencies": {
"@docusaurus/eslint-plugin": "^2.2.0",
"@docusaurus/module-type-aliases": "2.2.0",
"@tailwindcss/typography": "^0.5.9",
"@tsconfig/docusaurus": "^1.0.6",

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
import React from 'react';
import React from "react";
export const BatteryCalculator = (): JSX.Element => {
return (
@ -6,7 +6,7 @@ export const BatteryCalculator = (): JSX.Element => {
<div className="card__header">
<h3>Battery Calculator</h3>
</div>
<div className="card__body" style={{ display: 'flex', gap: '2rem' }}>
<div className="card__body" style={{ display: "flex", gap: "2rem" }}>
<div>
<input placeholder="Search" />
<input placeholder="Search" />

View file

@ -1,12 +1,12 @@
import React from 'react';
import React from "react";
import { HTMLMotionProps, motion } from 'framer-motion';
import { HTMLMotionProps, motion } from "framer-motion";
export const Button = ({ children, ...props }: HTMLMotionProps<'div'>) => {
export const Button = ({ children, ...props }: HTMLMotionProps<"div">) => {
return (
<motion.div
{...props}
whileHover={{ scale: 1.1, backgroundColor: 'var(--tertiary)' }}
whileHover={{ scale: 1.1, backgroundColor: "var(--tertiary)" }}
whileTap={{ scale: 1.0 }}
className="m-auto flex cursor-pointer rounded-full bg-secondary p-3 shadow-md"
>

View file

@ -1,4 +1,4 @@
import React from 'react';
import React from "react";
export interface ColorModeProps {
children: React.ReactNode;

View file

@ -1,8 +1,8 @@
import React from 'react';
import React from "react";
import { AnimatePresence, motion } from 'framer-motion';
import { AnimatePresence, motion } from "framer-motion";
import { Dialog } from '@headlessui/react';
import { Dialog } from "@headlessui/react";
export interface ModalProps {
open: boolean;

View file

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

View file

@ -1,4 +1,4 @@
import React from 'react';
import React from "react";
export interface BadgeProps {
name: string;

View file

@ -1,6 +1,6 @@
import React from 'react';
import React from "react";
import { Tab } from '@headlessui/react';
import { Tab } from "@headlessui/react";
export interface CardTabProps {
title: string;
@ -11,7 +11,7 @@ export const CardTab = ({ title }: CardTabProps): JSX.Element => {
<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' : ''
selected ? "bg-secondary shadow-md" : ""
}`
}
>

View file

@ -1,6 +1,6 @@
import React from 'react';
import React from "react";
import { IDevice, Stability } from '@site/src/data/device';
import { IDevice, Stability } from "@site/src/data/device";
export interface HardwareCardProps {
device: IDevice;
@ -9,7 +9,7 @@ export interface HardwareCardProps {
export const HardwareCard = ({
device,
setDevice,
setDevice
}: HardwareCardProps): JSX.Element => {
return (
<li
@ -41,12 +41,12 @@ export const HardwareCard = ({
<div
className={`my-auto h-3 w-3 rounded-full ${
device.misc.Stability === Stability.Broken
? 'bg-red-500'
? "bg-red-500"
: device.misc.Stability === Stability.Unstable
? 'bg-orange-500'
? "bg-orange-500"
: device.misc.Stability === Stability.Semi
? 'bg-cyan-500'
: 'bg-green-500'
? "bg-cyan-500"
: "bg-green-500"
}`}
/>
<div className="my-auto">{Stability[device.misc.Stability]}</div>

View file

@ -1,21 +1,21 @@
import React, { useState } from 'react';
import React, { useState } from "react";
import { AnimatePresence, motion } from 'framer-motion';
import { FiBluetooth, FiChevronRight, FiWifi, FiX } from 'react-icons/fi';
import { useBreakpoint } from 'use-breakpoint';
import { AnimatePresence, motion } from "framer-motion";
import { FiBluetooth, FiChevronRight, FiWifi, FiX } from "react-icons/fi";
import { useBreakpoint } from "use-breakpoint";
import { Tab } from '@headlessui/react';
import type { IDevice } from '@site/src/data/device';
import { Tab } from "@headlessui/react";
import type { IDevice } from "@site/src/data/device";
import { Button } from '../../components/Button';
import { BREAKPOINTS } from '../../utils/breakpoints';
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';
import { Button } from "../../components/Button";
import { BREAKPOINTS } from "../../utils/breakpoints";
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;
@ -26,10 +26,10 @@ export interface HardwareModal {
export const HardwareModal = ({
device,
open,
close,
close
}: HardwareModal): JSX.Element => {
const [hideDetails, setHideDetails] = useState(false);
const { breakpoint } = useBreakpoint(BREAKPOINTS, 'md');
const { breakpoint } = useBreakpoint(BREAKPOINTS, "md");
return (
<Modal open={open} onClose={close}>
@ -42,22 +42,22 @@ export const HardwareModal = ({
<motion.div
layout
animate={
breakpoint === 'sm'
breakpoint === "sm"
? hideDetails
? 'hiddenSm'
: 'visibleSm'
? "hiddenSm"
: "visibleSm"
: hideDetails
? 'hidden'
: 'visible'
? "hidden"
: "visible"
}
variants={{
hidden: { width: '100%', height: '100%' },
hiddenSm: { height: '100%', width: '100%' },
visible: { width: '20%', height: '100%' },
visibleSm: { height: '33%', width: '100%' },
hidden: { width: "100%", height: "100%" },
hiddenSm: { height: "100%", width: "100%" },
visible: { width: "20%", height: "100%" },
visibleSm: { height: "33%", width: "100%" }
}}
transition={{
type: 'just',
type: "just"
}}
className="flex flex-col md:h-full md:flex-row"
>
@ -74,19 +74,19 @@ export const HardwareModal = ({
<div className="absolute -bottom-5 z-20 flex w-full md:bottom-auto md:-right-5 md:h-full md:w-auto">
<Button
animate={
breakpoint === 'sm'
breakpoint === "sm"
? hideDetails
? 'hiddenSm'
: 'visibleSm'
? "hiddenSm"
: "visibleSm"
: hideDetails
? 'hidden'
: 'visible'
? "hidden"
: "visible"
}
variants={{
hidden: { rotate: 180 },
hiddenSm: { rotate: -90 },
visible: { rotate: 0 },
visibleSm: { rotate: 90 },
visibleSm: { rotate: 90 }
}}
onClick={() => {
setHideDetails(!hideDetails);
@ -103,7 +103,7 @@ export const HardwareModal = ({
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className={`absolute -bottom-5 z-20 flex md:mt-0 md:hidden md:pb-2 ${
hideDetails ? 'opacity-0' : 'opacity-100'
hideDetails ? "opacity-0" : "opacity-100"
}`}
>
<VariantSelectButton options={device.variants} />
@ -137,7 +137,7 @@ export const HardwareModal = ({
</motion.div>
<div
className={`h-7 bg-base opacity-0 md:h-auto md:w-7 ${
hideDetails ? 'flex' : 'hidden'
hideDetails ? "flex" : "hidden"
}`}
/>
</motion.div>
@ -148,7 +148,7 @@ export const HardwareModal = ({
</div>
<div
className={`mt-1 flex flex-grow rounded-2xl bg-base p-2 shadow-inner transition-opacity duration-100 ease-linear md:mt-0 md:rounded-l-none md:rounded-r-2xl md:p-4 ${
hideDetails ? 'opacity-0' : 'opacity-100'
hideDetails ? "opacity-0" : "opacity-100"
}`}
>
<Tab.Group

View file

@ -1,8 +1,8 @@
import React from 'react';
import React from "react";
import { Tab } from '@headlessui/react';
import { Tab } from "@headlessui/react";
import type { IDevice } from '../../../data/device';
import type { IDevice } from "../../../data/device";
export interface InfoTabProps {
device: IDevice;

View file

@ -1,8 +1,8 @@
import React from 'react';
import React from "react";
import { Tab } from '@headlessui/react';
import { Tab } from "@headlessui/react";
import type { IDevice } from '../../../data/device';
import type { IDevice } from "../../../data/device";
export interface PinoutTabProps {
device: IDevice;
@ -14,13 +14,13 @@ export const PinoutTab = ({ device }: PinoutTabProps): JSX.Element => {
<div className="m-auto flex gap-4 rounded-lg bg-slate-700 px-2 py-1 shadow-md">
{[
device.pinout.slice(0, device.misc.pinoutSplit),
device.pinout.slice(device.misc.pinoutSplit, device.pinout.length),
device.pinout.slice(device.misc.pinoutSplit, device.pinout.length)
].map((group, index) => (
<div key={index}>
{group.map((pin, pinIndex) => (
<div
className={`flex gap-1 ${
index === 0 ? 'flex-row' : 'flex-row-reverse'
index === 0 ? "flex-row" : "flex-row-reverse"
}`}
key={pinIndex}
>

View file

@ -1,13 +1,13 @@
import React from 'react';
import React from "react";
import { Tab } from '@headlessui/react';
import { Tab } from "@headlessui/react";
import type { IDevice } from '../../../data/device';
import type { IDevice } from "../../../data/device";
export interface PowerTabProps {
device: IDevice;
}
export const PowerTab = ({ device }: PowerTabProps): JSX.Element => {
export const PowerTab = ({}: PowerTabProps): JSX.Element => {
return <Tab.Panel className="h-32">Content 1</Tab.Panel>;
};

View file

@ -1,18 +1,18 @@
import React, { Fragment, useState } from 'react';
import React, { Fragment, useState } from "react";
import { motion } from 'framer-motion';
import { FiCheck } from 'react-icons/fi';
import { HiSelector } from 'react-icons/hi';
import { motion } from "framer-motion";
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';
import { Listbox, Transition } from "@headlessui/react";
import type { Variant } from "@site/src/data/device.js";
export interface VariantSelectButtonProps {
options: Variant[];
}
export const VariantSelectButton = ({
options,
options
}: VariantSelectButtonProps): JSX.Element => {
const [selected, setSelected] = useState(options[options.length - 1]);
@ -23,7 +23,7 @@ export const VariantSelectButton = ({
<div className="relative select-none">
<Listbox.Button as={Fragment}>
<motion.button
whileHover={{ backgroundColor: 'var(--tertiary)' }}
whileHover={{ backgroundColor: "var(--tertiary)" }}
whileTap={{ scale: 0.99 }}
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 md:mt-2"
>
@ -50,7 +50,7 @@ export const VariantSelectButton = ({
key={index}
className={({ active }) =>
`relative cursor-default select-none py-2 pl-3 pr-9 ${
active ? 'bg-secondary' : ''
active ? "bg-secondary" : ""
}`
}
value={variant}
@ -59,7 +59,7 @@ export const VariantSelectButton = ({
<>
<span
className={`block truncate ${
selected ? 'font-semibold' : 'font-normal'
selected ? "font-semibold" : "font-normal"
}`}
>
{variant.name}
@ -68,7 +68,7 @@ export const VariantSelectButton = ({
{selected ? (
<span
className={`absolute inset-y-0 right-0 flex items-center pr-4 ${
active ? '' : 'text-primaryInv'
active ? "" : "text-primaryInv"
}`}
>
<FiCheck className="h-5 w-5" aria-hidden="true" />

View file

@ -1,6 +1,6 @@
import React from 'react';
import React from "react";
import { FiExternalLink } from 'react-icons/fi';
import { FiExternalLink } from "react-icons/fi";
export interface SocialCardProps {
children: React.ReactNode;
@ -11,7 +11,7 @@ export interface SocialCardProps {
export const SocialCard = ({
children,
color,
link,
link
}: SocialCardProps): JSX.Element => {
return (
<div

View file

@ -22,14 +22,14 @@
--mute: #6b7280;
--primaryInv: #242526;
--secondaryInv: #18191a;
--tertiaryInv: #4C4E50;
--tertiaryInv: #4c4e50;
}
[data-theme="dark"] {
--base: #38393B;
--base: #38393b;
--primary: #242526;
--secondary: #18191a;
--tertiary: #4C4E50;
--tertiary: #4c4e50;
--mute: #9ca3af;
--primaryInv: #ffffff;
--secondaryInv: #e5e7eb;
@ -143,53 +143,59 @@ a + .navbar__link > svg {
@apply prose-invert;
}
[data-theme="dark"] .hideDark {
@apply hidden
@apply hidden;
}
[data-theme="dark"] .hideLight {
@apply block
@apply block;
}
.hideLight {
@apply hidden
@apply hidden;
}
.hideDark {
@apply block
@apply block;
}
}
.markdown :where(li):not(:where([class~=not-prose] *)){
.markdown :where(li):not(:where([class~="not-prose"] *)) {
margin-bottom: 0;
margin-top: 0;
}
.markdown :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose] *)){
.markdown
:where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"] *)) {
margin-bottom: 0;
margin-top: 0;
}
h1, h2, h3, h4, h5, h6 {
font-weight: var(--ifm-heading-font-weight)
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: var(--ifm-heading-font-weight);
}
h1 {
font-size: var(--ifm-h1-font-size)
font-size: var(--ifm-h1-font-size);
}
h2 {
font-size: var(--ifm-h2-font-size)
font-size: var(--ifm-h2-font-size);
}
h3 {
font-size: var(--ifm-h3-font-size)
font-size: var(--ifm-h3-font-size);
}
h4 {
font-size: var(--ifm-h4-font-size)
font-size: var(--ifm-h4-font-size);
}
h5 {
font-size: var(--ifm-h5-font-size)
font-size: var(--ifm-h5-font-size);
}
h6 {
font-size: var(--ifm-h6-font-size)
font-size: var(--ifm-h6-font-size);
}

View file

@ -7,12 +7,12 @@ export type DeepPartial<T> = T extends object
export enum UseCase {
Solar,
Router,
Portable,
Portable
}
enum PinUsage {
LoRa,
GNSS,
GNSS
}
export interface Pin {
@ -25,38 +25,38 @@ export interface Pin {
usage?: PinUsage;
}
export type DeviceName = 'tbeam' | 'techo';
export type DeviceName = "tbeam" | "techo";
export type BLEVersion = '4.2' | '5.0';
export type BLEVersion = "4.2" | "5.0";
export type AntennaType = 'Integrated';
export type AntennaType = "Integrated";
export type Chipset = 'ESP32' | 'NRF52';
export type Chipset = "ESP32" | "NRF52";
export type Frequency = 433 | 868 | 915 | 923;
export type SerialAdapter = 'CP210X' | 'CH9102';
export type SerialAdapter = "CP210X" | "CH9102";
export type GNSSModule = 'NEO-6M' | 'NEO-8M';
export type GNSSModule = "NEO-6M" | "NEO-8M";
export type LORAModule = 'SX1276' | 'SX1262';
export type LORAModule = "SX1276" | "SX1262";
export type Variant = DeepPartial<Omit<IDevice, 'variants'>> & { name: string };
export type Variant = DeepPartial<Omit<IDevice, "variants">> & { name: string };
export enum Stability {
Stable,
Semi,
Unstable,
Broken,
Broken
}
export type Module =
| 'cannedMessage'
| 'externalNotification'
| 'rangeTest'
| 'rotaryEncoder'
| 'storeAndForward'
| 'telemetry';
| "cannedMessage"
| "externalNotification"
| "rangeTest"
| "rotaryEncoder"
| "storeAndForward"
| "telemetry";
export interface IDevice {
name: string;

View file

@ -1,66 +1,66 @@
import { IDevice, Stability, UseCase } from '../device';
import { IDevice, Stability, UseCase } from "../device";
export const heltec: IDevice = {
name: 'Heltec',
name: "Heltec",
misc: {
Stability: Stability.Unstable,
SuggestedUse: [UseCase.Portable],
Gradient: 'bg-gradient-to-r from-pink-300 via-purple-300 to-indigo-400',
Gradient: "bg-gradient-to-r from-pink-300 via-purple-300 to-indigo-400"
},
images: {
Front: '/img/hardware/heltec-v2.png',
Back: '',
Front: "/img/hardware/heltec-v2.png",
Back: ""
},
features: {
BLE: true,
WiFi: true,
Modules: [
'cannedMessage',
'externalNotification',
'rangeTest',
'rotaryEncoder',
'storeAndForward',
'telemetry',
],
"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',
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',
LoRa: "SX1262",
PSRAM: 8,
RAM: undefined,
RAM: undefined
},
variants: [
{
name: 'TBeam 0.7',
name: "TBeam 0.7",
misc: {
Stability: Stability.Unstable,
Stability: Stability.Unstable
},
specifications: {
Driver: 'CP210X',
GNSS: 'NEO-6M',
Frequencies: [868, 915],
},
Driver: "CP210X",
GNSS: "NEO-6M",
Frequencies: [868, 915]
}
},
{
name: 'TBeam 1.0',
name: "TBeam 1.0",
specifications: {
Frequencies: [868, 915],
},
Frequencies: [868, 915]
}
},
{
name: 'TBeam 1.1',
name: "TBeam 1.1",
specifications: {
Driver: 'CP210X',
GNSS: 'NEO-6M',
},
},
],
Driver: "CP210X",
GNSS: "NEO-6M"
}
}
]
};

View file

@ -1,66 +1,66 @@
import { IDevice, Stability, UseCase } from '../device';
import { IDevice, Stability, UseCase } from "../device";
export const hydra: IDevice = {
name: 'Hydra',
name: "Hydra",
misc: {
Stability: Stability.Stable,
SuggestedUse: [UseCase.Portable],
Gradient: 'bg-gradient-to-r from-indigo-200 via-red-200 to-yellow-100',
Gradient: "bg-gradient-to-r from-indigo-200 via-red-200 to-yellow-100"
},
images: {
Front: '/img/hardware/Hydra-PCB.2.1.svg',
Back: '',
Front: "/img/hardware/Hydra-PCB.2.1.svg",
Back: ""
},
features: {
BLE: true,
WiFi: true,
Modules: [
'cannedMessage',
'externalNotification',
'rangeTest',
'rotaryEncoder',
'storeAndForward',
'telemetry',
],
"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',
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',
LoRa: "SX1262",
PSRAM: 8,
RAM: undefined,
RAM: undefined
},
variants: [
{
name: 'TBeam 0.7',
name: "TBeam 0.7",
misc: {
Stability: Stability.Unstable,
Stability: Stability.Unstable
},
specifications: {
Driver: 'CP210X',
GNSS: 'NEO-6M',
Frequencies: [868, 915],
},
Driver: "CP210X",
GNSS: "NEO-6M",
Frequencies: [868, 915]
}
},
{
name: 'TBeam 1.0',
name: "TBeam 1.0",
specifications: {
Frequencies: [868, 915],
},
Frequencies: [868, 915]
}
},
{
name: 'TBeam 1.1',
name: "TBeam 1.1",
specifications: {
Driver: 'CP210X',
GNSS: 'NEO-6M',
},
},
],
Driver: "CP210X",
GNSS: "NEO-6M"
}
}
]
};

View file

@ -1,66 +1,66 @@
import { IDevice, Stability, UseCase } from '../device';
import { IDevice, Stability, UseCase } from "../device";
export const nano_g1: IDevice = {
name: 'Nano G1',
name: "Nano G1",
misc: {
Stability: Stability.Unstable,
SuggestedUse: [UseCase.Portable],
Gradient: 'bg-gradient-to-r from-green-200 to-green-500',
Gradient: "bg-gradient-to-r from-green-200 to-green-500"
},
images: {
Front: '/img/hardware/nano_g1_front.svg',
Back: '/img/hardware/nano_g1_back.svg',
Front: "/img/hardware/nano_g1_front.svg",
Back: "/img/hardware/nano_g1_back.svg"
},
features: {
BLE: true,
WiFi: true,
Modules: [
'cannedMessage',
'externalNotification',
'rangeTest',
'rotaryEncoder',
'storeAndForward',
'telemetry',
],
"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',
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',
LoRa: "SX1262",
PSRAM: 8,
RAM: undefined,
RAM: undefined
},
variants: [
{
name: 'TBeam 0.7',
name: "TBeam 0.7",
misc: {
Stability: Stability.Unstable,
Stability: Stability.Unstable
},
specifications: {
Driver: 'CP210X',
GNSS: 'NEO-6M',
Frequencies: [868, 915],
},
Driver: "CP210X",
GNSS: "NEO-6M",
Frequencies: [868, 915]
}
},
{
name: 'TBeam 1.0',
name: "TBeam 1.0",
specifications: {
Frequencies: [868, 915],
},
Frequencies: [868, 915]
}
},
{
name: 'TBeam 1.1',
name: "TBeam 1.1",
specifications: {
Driver: 'CP210X',
GNSS: 'NEO-6M',
},
},
],
Driver: "CP210X",
GNSS: "NEO-6M"
}
}
]
};

View file

@ -1,66 +1,66 @@
import { IDevice, Stability, UseCase } from '../device';
import { IDevice, Stability, UseCase } from "../device";
export const rak19001: IDevice = {
name: 'WisBlock 19001',
name: "WisBlock 19001",
misc: {
Stability: Stability.Stable,
SuggestedUse: [UseCase.Portable],
Gradient: 'bg-gradient-to-r from-indigo-300 to-purple-400',
Gradient: "bg-gradient-to-r from-indigo-300 to-purple-400"
},
images: {
Front: '/img/hardware/rak/RAK19001.png',
Back: '',
Front: "/img/hardware/rak/RAK19001.png",
Back: ""
},
features: {
BLE: true,
WiFi: true,
Modules: [
'cannedMessage',
'externalNotification',
'rangeTest',
'rotaryEncoder',
'storeAndForward',
'telemetry',
],
"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',
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',
LoRa: "SX1262",
PSRAM: 8,
RAM: undefined,
RAM: undefined
},
variants: [
{
name: 'TBeam 0.7',
name: "TBeam 0.7",
misc: {
Stability: Stability.Unstable,
Stability: Stability.Unstable
},
specifications: {
Driver: 'CP210X',
GNSS: 'NEO-6M',
Frequencies: [868, 915],
},
Driver: "CP210X",
GNSS: "NEO-6M",
Frequencies: [868, 915]
}
},
{
name: 'TBeam 1.0',
name: "TBeam 1.0",
specifications: {
Frequencies: [868, 915],
},
Frequencies: [868, 915]
}
},
{
name: 'TBeam 1.1',
name: "TBeam 1.1",
specifications: {
Driver: 'CP210X',
GNSS: 'NEO-6M',
},
},
],
Driver: "CP210X",
GNSS: "NEO-6M"
}
}
]
};

View file

@ -1,66 +1,66 @@
import { IDevice, Stability, UseCase } from '../device';
import { IDevice, Stability, UseCase } from "../device";
export const rak19003: IDevice = {
name: 'WisBlock 19003',
name: "WisBlock 19003",
misc: {
Stability: Stability.Stable,
SuggestedUse: [UseCase.Portable],
Gradient: 'bg-gradient-to-b from-orange-500 to-yellow-300',
Gradient: "bg-gradient-to-b from-orange-500 to-yellow-300"
},
images: {
Front: '/img/hardware/rak/RAK19003.png',
Back: '',
Front: "/img/hardware/rak/RAK19003.png",
Back: ""
},
features: {
BLE: true,
WiFi: true,
Modules: [
'cannedMessage',
'externalNotification',
'rangeTest',
'rotaryEncoder',
'storeAndForward',
'telemetry',
],
"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',
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',
LoRa: "SX1262",
PSRAM: 8,
RAM: undefined,
RAM: undefined
},
variants: [
{
name: 'TBeam 0.7',
name: "TBeam 0.7",
misc: {
Stability: Stability.Unstable,
Stability: Stability.Unstable
},
specifications: {
Driver: 'CP210X',
GNSS: 'NEO-6M',
Frequencies: [868, 915],
},
Driver: "CP210X",
GNSS: "NEO-6M",
Frequencies: [868, 915]
}
},
{
name: 'TBeam 1.0',
name: "TBeam 1.0",
specifications: {
Frequencies: [868, 915],
},
Frequencies: [868, 915]
}
},
{
name: 'TBeam 1.1',
name: "TBeam 1.1",
specifications: {
Driver: 'CP210X',
GNSS: 'NEO-6M',
},
},
],
Driver: "CP210X",
GNSS: "NEO-6M"
}
}
]
};

View file

@ -1,277 +1,277 @@
import { IDevice, Stability, UseCase } from '../device';
import { IDevice, Stability, UseCase } from "../device";
export const tbeam: IDevice = {
name: 'T-Beam',
name: "T-Beam",
misc: {
Stability: Stability.Stable,
SuggestedUse: [UseCase.Portable],
Gradient: 'bg-gradient-to-r from-pink-500 via-red-500 to-yellow-500',
pinoutSplit: 13,
Gradient: "bg-gradient-to-r from-pink-500 via-red-500 to-yellow-500",
pinoutSplit: 13
},
images: {
Front: '/img/hardware/tbeam-v1.1.svg',
Back: '',
Front: "/img/hardware/tbeam-v1.1.svg",
Back: ""
},
features: {
BLE: true,
WiFi: true,
Modules: [
'cannedMessage',
'externalNotification',
'rangeTest',
'rotaryEncoder',
'storeAndForward',
'telemetry',
],
"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',
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',
LoRa: "SX1262",
PSRAM: 8,
RAM: undefined,
RAM: undefined
},
variants: [
{
name: 'TBeam 0.7',
name: "TBeam 0.7",
misc: {
Stability: Stability.Unstable,
Stability: Stability.Unstable
},
specifications: {
Driver: 'CP210X',
GNSS: 'NEO-6M',
Frequencies: [868, 915],
},
Driver: "CP210X",
GNSS: "NEO-6M",
Frequencies: [868, 915]
}
},
{
name: 'TBeam 1.0',
name: "TBeam 1.0",
specifications: {
Frequencies: [868, 915],
},
Frequencies: [868, 915]
}
},
{
name: 'TBeam 1.1',
name: "TBeam 1.1",
specifications: {
Driver: 'CP210X',
GNSS: 'NEO-6M',
},
},
Driver: "CP210X",
GNSS: "NEO-6M"
}
}
],
pinout: [
{
label: 'VP',
name: 'IO1',
label: "VP",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: 'VN',
name: 'IO1',
label: "VN",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: 'RST',
name: 'IO1',
label: "RST",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '15',
name: 'IO1',
label: "15",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '35',
name: 'IO1',
label: "35",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '32',
name: 'IO1',
label: "32",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '33',
name: 'IO1',
label: "33",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '25',
name: 'IO1',
label: "25",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '14',
name: 'IO1',
label: "14",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '13',
name: 'IO1',
label: "13",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '2',
name: 'IO1',
label: "2",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: 'GND',
name: 'IO1',
label: "GND",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '5V',
name: 'IO1',
label: "5V",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: 'TX',
name: 'IO1',
label: "TX",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: 'RX',
name: 'IO1',
label: "RX",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '23',
name: 'IO1',
label: "23",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '4',
name: 'IO1',
label: "4",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '0',
name: 'IO1',
label: "0",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: 'GND',
name: 'IO1',
label: "GND",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '3V3',
name: 'IO1',
label: "3V3",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: 'GND',
name: 'IO1',
label: "GND",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '22',
name: 'IO1',
label: "22",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '21',
name: 'IO1',
label: "21",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: '3.3V',
name: 'IO1',
label: "3.3V",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: 'LoRa2',
name: 'IO1',
label: "LoRa2",
name: "IO1",
offset: {
x: 5,
y: 5,
},
y: 5
}
},
{
label: 'LoRa1',
name: 'IO1',
label: "LoRa1",
name: "IO1",
offset: {
x: 5,
y: 5,
},
},
],
y: 5
}
}
]
};

View file

@ -1,66 +1,66 @@
import { IDevice, Stability, UseCase } from '../device';
import { IDevice, Stability, UseCase } from "../device";
export const techo: IDevice = {
name: 'T-Echo',
name: "T-Echo",
misc: {
Stability: Stability.Semi,
SuggestedUse: [UseCase.Portable],
Gradient: 'bg-gradient-to-r from-gray-700 via-gray-900 to-black',
Gradient: "bg-gradient-to-r from-gray-700 via-gray-900 to-black"
},
images: {
Front: '/img/hardware/t-echo-lilygo.jpg',
Back: '',
Front: "/img/hardware/t-echo-lilygo.jpg",
Back: ""
},
features: {
BLE: true,
WiFi: true,
Modules: [
'cannedMessage',
'externalNotification',
'rangeTest',
'rotaryEncoder',
'storeAndForward',
'telemetry',
],
"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',
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',
LoRa: "SX1262",
PSRAM: 8,
RAM: undefined,
RAM: undefined
},
variants: [
{
name: 'TBeam 0.7',
name: "TBeam 0.7",
misc: {
Stability: Stability.Unstable,
Stability: Stability.Unstable
},
specifications: {
Driver: 'CP210X',
GNSS: 'NEO-6M',
Frequencies: [868, 915],
},
Driver: "CP210X",
GNSS: "NEO-6M",
Frequencies: [868, 915]
}
},
{
name: 'TBeam 1.0',
name: "TBeam 1.0",
specifications: {
Frequencies: [868, 915],
},
Frequencies: [868, 915]
}
},
{
name: 'TBeam 1.1',
name: "TBeam 1.1",
specifications: {
Driver: 'CP210X',
GNSS: 'NEO-6M',
},
},
],
Driver: "CP210X",
GNSS: "NEO-6M"
}
}
]
};

View file

@ -1,4 +1,4 @@
import { IRegion } from '../region';
import { IRegion } from "../region";
export const ANZ: IRegion = {
name: "ANZ",
@ -9,5 +9,5 @@ export const ANZ: IRegion = {
powerLimit: 30,
audioPermitted: true,
frequencySwitching: false,
wideLora: false,
}
wideLora: false
};

View file

@ -1,4 +1,4 @@
import { IRegion } from '../region';
import { IRegion } from "../region";
export const CN: IRegion = {
name: "CN",
@ -9,5 +9,5 @@ export const CN: IRegion = {
powerLimit: 19,
audioPermitted: true,
frequencySwitching: false,
wideLora: false,
}
wideLora: false
};

View file

@ -1,4 +1,4 @@
import { IRegion } from '../region';
import { IRegion } from "../region";
export const EU_433: IRegion = {
name: "EU_433",
@ -9,5 +9,5 @@ export const EU_433: IRegion = {
powerLimit: 12,
audioPermitted: true,
frequencySwitching: false,
wideLora: false,
}
wideLora: false
};

View file

@ -1,4 +1,4 @@
import { IRegion } from '../region';
import { IRegion } from "../region";
export const EU_868: IRegion = {
name: "EU_868",
@ -9,5 +9,5 @@ export const EU_868: IRegion = {
powerLimit: 27,
audioPermitted: false,
frequencySwitching: false,
wideLora: false,
}
wideLora: false
};

View file

@ -1,4 +1,4 @@
import { IRegion } from '../region';
import { IRegion } from "../region";
export const IN: IRegion = {
name: "IN",
@ -9,5 +9,5 @@ export const IN: IRegion = {
powerLimit: 30,
audioPermitted: true,
frequencySwitching: false,
wideLora: false,
}
wideLora: false
};

View file

@ -1,4 +1,4 @@
import { IRegion } from '../region';
import { IRegion } from "../region";
export const JP: IRegion = {
name: "JP",
@ -9,5 +9,5 @@ export const JP: IRegion = {
powerLimit: 16,
audioPermitted: true,
frequencySwitching: false,
wideLora: false,
}
wideLora: false
};

View file

@ -1,4 +1,4 @@
import { IRegion } from '../region';
import { IRegion } from "../region";
export const KR: IRegion = {
name: "KR",
@ -9,5 +9,5 @@ export const KR: IRegion = {
powerLimit: 0,
audioPermitted: true,
frequencySwitching: false,
wideLora: false,
}
wideLora: false
};

View file

@ -1,4 +1,4 @@
import { IRegion } from '../region';
import { IRegion } from "../region";
export const LORA_24: IRegion = {
name: "LORA_24",
@ -9,5 +9,5 @@ export const LORA_24: IRegion = {
powerLimit: 10,
audioPermitted: true,
frequencySwitching: false,
wideLora: true,
}
wideLora: true
};

View file

@ -1,4 +1,4 @@
import { IRegion } from '../region';
import { IRegion } from "../region";
export const NZ_865: IRegion = {
name: "NZ_865",
@ -9,5 +9,5 @@ export const NZ_865: IRegion = {
powerLimit: 36,
audioPermitted: true,
frequencySwitching: false,
wideLora: false,
}
wideLora: false
};

View file

@ -1,4 +1,4 @@
import { IRegion } from '../region';
import { IRegion } from "../region";
export const RU: IRegion = {
name: "RU",
@ -9,5 +9,5 @@ export const RU: IRegion = {
powerLimit: 20,
audioPermitted: true,
frequencySwitching: false,
wideLora: false,
}
wideLora: false
};

View file

@ -1,4 +1,4 @@
import { IRegion } from '../region';
import { IRegion } from "../region";
export const TH: IRegion = {
name: "TH",
@ -9,5 +9,5 @@ export const TH: IRegion = {
powerLimit: 16,
audioPermitted: true,
frequencySwitching: false,
wideLora: false,
}
wideLora: false
};

View file

@ -1,4 +1,4 @@
import { IRegion } from '../region';
import { IRegion } from "../region";
export const TW: IRegion = {
name: "TW",
@ -9,5 +9,5 @@ export const TW: IRegion = {
powerLimit: 0,
audioPermitted: true,
frequencySwitching: false,
wideLora: false,
}
wideLora: false
};

View file

@ -1,4 +1,4 @@
import { IRegion } from '../region';
import { IRegion } from "../region";
export const UNSET: IRegion = {
name: "UNSET",
@ -9,5 +9,5 @@ export const UNSET: IRegion = {
powerLimit: 30,
audioPermitted: true,
frequencySwitching: false,
wideLora: false,
}
wideLora: false
};

View file

@ -1,4 +1,4 @@
import { IRegion } from '../region';
import { IRegion } from "../region";
export const US: IRegion = {
name: "US",
@ -9,5 +9,5 @@ export const US: IRegion = {
powerLimit: 30,
audioPrmitted: true,
frequencySwitching: false,
wideLora: false,
}
wideLora: false
};

View file

@ -1,11 +1,11 @@
import React from 'react';
import React from "react";
import { Showcase } from '../utils/apiTypes.js';
import { useSelectedTags } from './useSelectedTags';
import { Showcase } from "../utils/apiTypes.js";
import { useSelectedTags } from "./useSelectedTags";
const filterNetworks = (
showcaseNetworks: Showcase[],
selectedTags: string[],
selectedTags: string[]
) => {
if (selectedTags.length === 0) {
return showcaseNetworks;
@ -15,7 +15,7 @@ const filterNetworks = (
return false;
}
return selectedTags.every((queryTag) =>
showcaseNetwork.tags.find((searchTag) => searchTag.label === queryTag),
showcaseNetwork.tags.find((searchTag) => searchTag.label === queryTag)
);
});
};
@ -24,6 +24,6 @@ export const useFilteredNetworks = (networks: Showcase[]) => {
const selectedTags = useSelectedTags();
return React.useMemo(
() => filterNetworks(networks, selectedTags),
[selectedTags],
[selectedTags]
);
};

View file

@ -1,8 +1,8 @@
import React from 'react';
import React from "react";
import { useLocation } from '@docusaurus/router';
import { useLocation } from "@docusaurus/router";
import { readSearchTags } from '../pages/showcase/_components/TagSelect';
import { readSearchTags } from "../pages/showcase/_components/TagSelect";
export const useSelectedTags = () => {
const location = useLocation();

View file

@ -1,45 +1,44 @@
import React from 'react';
import React from "react";
import { FiTwitter } from 'react-icons/fi';
import { ChevronRightIcon } from '@heroicons/react/20/solid';
import FlipClockCountdown from '@leenguyen/react-flip-clock-countdown';
import Layout from '@theme/Layout';
import { Dark, Light } from '/src/components/ColorMode';
import { FiTwitter } from "react-icons/fi";
import { ChevronRightIcon } from "@heroicons/react/20/solid";
import FlipClockCountdown from "@leenguyen/react-flip-clock-countdown";
import Layout from "@theme/Layout";
import { Dark, Light } from "/src/components/ColorMode";
const TwoPointZero = (): JSX.Element => {
const stats = [
{ label: 'Active Nodes', value: 'A Lot!' },
{ label: 'Community Members', value: '4000+' },
{ label: 'Firmware Commits', value: '4900+' },
{ label: 'Community Donations', value: '$5700+' },
{ label: "Active Nodes", value: "A Lot!" },
{ label: "Community Members", value: "4000+" },
{ label: "Firmware Commits", value: "4900+" },
{ label: "Community Donations", value: "$5700+" }
];
const logos = [
{
name: 'Vercel',
url: '/2.0/vercel-logotype-dark.svg',
name: "Vercel",
url: "/2.0/vercel-logotype-dark.svg"
},
{
name: 'Cloudflare',
url: '/2.0/CF_logo_horizontal_blktype.svg',
name: "Cloudflare",
url: "/2.0/CF_logo_horizontal_blktype.svg"
},
{
name: 'RAK Wireless',
url: '/2.0/RAK-blue-main.svg',
name: "RAK Wireless",
url: "/2.0/RAK-blue-main.svg"
},
{
name: 'Open Collective',
url: '/2.0/opencollectivelogo.svg',
name: "Open Collective",
url: "/2.0/opencollectivelogo.svg"
},
{
name: 'LILYGO',
url: '/2.0/LILYGO.png',
name: "LILYGO",
url: "/2.0/LILYGO.png"
},
{
name: 'Discord',
url: '/2.0/discord.svg',
},
name: "Discord",
url: "/2.0/discord.svg"
}
];
return (
<Layout title="Meshtastic 2.0" description="Meshtastic 2.0 Landing Page">
@ -246,8 +245,8 @@ const TwoPointZero = (): JSX.Element => {
<path d="M9.352 4C4.456 7.456 1 13.12 1 19.36c0 5.088 3.072 8.064 6.624 8.064 3.36 0 5.856-2.688 5.856-5.856 0-3.168-2.208-5.472-5.088-5.472-.576 0-1.344.096-1.536.192.48-3.264 3.552-7.104 6.624-9.024L9.352 4zm16.512 0c-4.8 3.456-8.256 9.12-8.256 15.36 0 5.088 3.072 8.064 6.624 8.064 3.264 0 5.856-2.688 5.856-5.856 0-3.168-2.304-5.472-5.184-5.472-.576 0-1.248.096-1.44.192.48-3.264 3.456-7.104 6.528-9.024L25.864 4z" />
</svg>
<p className="relative">
Meshtastic is the neatest open source project I've ever
seen!
Meshtastic is the neatest open source project I've
ever seen!
</p>
</div>

View file

@ -4,6 +4,4 @@ title: Meshtastic URL
sidebar_label: c
---
# Error : Something happened
Please go to [Android Usage](/docs/software/android/usage#join-a-channel) for more information.

View file

@ -1,4 +1,4 @@
import React from 'react';
import React from "react";
export interface avatarProps {
imgUrl: string;
@ -15,41 +15,31 @@ export const Avatar = ({
imgUrl,
name,
userName,
description,
description
}: avatarProps): JSX.Element => {
return (
<div className="card m-4 border-2 border-secondary">
<div className="card__body">
<div className="avatar">
<img
className="avatar__photo avatar__photo--sm"
src={imgUrl}
/>
<img className="avatar__photo avatar__photo--sm" src={imgUrl} />
<div className="avatar__intro">
<div className="avatar__name">
{name}
</div>
<small class="avatar__subtitle">
{description}
</small>
<div className="avatar__name">{name}</div>
<small className="avatar__subtitle">{description}</small>
</div>
</div>
</div>
</div>
)
}
);
};
export const AvatarLayout = ({
list
} :avatarLayoutProps): JSX.Element => {
export const AvatarLayout = ({ list }: avatarLayoutProps): JSX.Element => {
return (
<div className="container">
<div className="flex flex-wrap justify-center bg-primary">
{list.map((e) => {
return <Avatar/>
})
}
return <Avatar />;
})}
</div>
</div>
)
}
);
};

View file

@ -1,38 +1,35 @@
import React from 'react';
import Layout from '@theme/Layout';
import Link from '@docusaurus/Link';
import React from "react";
import Layout from "@theme/Layout";
import Link from "@docusaurus/Link";
import {
Avatar,
AvatarLayout
} from './_components/Avatar';
import { Avatar, AvatarLayout } from "./_components/Avatar";
const Credits = (): JSX.Element => {
const partnerLogos = [
{
name: 'Vercel',
url: '/2.0/vercel-logotype-dark.svg',
name: "Vercel",
url: "/2.0/vercel-logotype-dark.svg"
},
{
name: 'Cloudflare',
url: '/2.0/CF_logo_horizontal_blktype.svg',
name: "Cloudflare",
url: "/2.0/CF_logo_horizontal_blktype.svg"
},
{
name: 'RAK Wireless',
url: '/2.0/RAK-blue-main.svg',
name: "RAK Wireless",
url: "/2.0/RAK-blue-main.svg"
},
{
name: 'Open Collective',
url: '/2.0/opencollectivelogo.svg',
name: "Open Collective",
url: "/2.0/opencollectivelogo.svg"
},
{
name: 'LILYGO',
url: '/2.0/LILYGO.png',
name: "LILYGO",
url: "/2.0/LILYGO.png"
},
{
name: 'Discord',
url: '/2.0/discord.svg',
},
name: "Discord",
url: "/2.0/discord.svg"
}
];
return (
<Layout
@ -43,33 +40,80 @@ const Credits = (): JSX.Element => {
<div className="container mx-auto p-6 leading-normal space-y-4">
<h1>Credits</h1>
<p>
Meshtastic is community driven. Thousands of hours have been donated by volunteers who want to develop this amazing project. Whether you've submitted a pull request or triaged a bug in our Discord/Forum. You've made Meshtastic possible. Thank you for your contributions.
Meshtastic is community driven. Thousands of hours have been donated
by volunteers who want to develop this amazing project. Whether
you've submitted a pull request or triaged a bug in our
Discord/Forum. You've made Meshtastic possible. Thank you for your
contributions.
</p>
<p>
We would also like to recognize those who have donated financially to the project. As Meshtastic has grown, we've aquired some ongoing costs to keep the project running. Thank you for your generous donations.
We would also like to recognize those who have donated financially
to the project. As Meshtastic has grown, we've aquired some ongoing
costs to keep the project running. Thank you for your generous
donations.
</p>
</div>
<div className="container mx-auto p-6 leading-normal space-y-4">
<h2>Fiscal Sponsors</h2>
<p>
We have partnered with both the <a className="underline" href="https://opencollective.com" target="_blank">Open Collective</a> and the <a className="underline" href="https://www.oscollective.org" target="_blank">Open Source Collective</a> to help us with a fiscal management framework and banking needs. They help support over three thousand open source projects including the PHP Foundation, F-Droid, Sonarr, LinuxServer and DarkReader. We are in good hands and good company.
We have partnered with both the{" "}
<a
className="underline"
href="https://opencollective.com"
target="_blank"
>
Open Collective
</a>{" "}
and the{" "}
<a
className="underline"
href="https://www.oscollective.org"
target="_blank"
>
Open Source Collective
</a>{" "}
to help us with a fiscal management framework and banking needs.
They help support over three thousand open source projects including
the PHP Foundation, F-Droid, Sonarr, LinuxServer and DarkReader. We
are in good hands and good company.
</p>
<p>
As with everything we do here, Open Collective provides a fully transparent framework for our budget and expenses. You can see what were bringing in, who is spending money and where that money is going <a className="underline" href="https://opencollective.com/meshtastic" target="_blank">here</a>.
As with everything we do here, Open Collective provides a fully
transparent framework for our budget and expenses. You can see what
were bringing in, who is spending money and where that money is
going{" "}
<a
className="underline"
href="https://opencollective.com/meshtastic"
target="_blank"
>
here
</a>
.
</p>
<p>
In addition to our partnership with Open Collective and Open Source Collective, we have also been approved into the <a className="underline" href="https://github.com/sponsors" target="_blank">GitHub Sponsors</a> program where we can set fundraising goals with GitHub.
In addition to our partnership with Open Collective and Open Source
Collective, we have also been approved into the{" "}
<a
className="underline"
href="https://github.com/sponsors"
target="_blank"
>
GitHub Sponsors
</a>{" "}
program where we can set fundraising goals with GitHub.
</p>
<p>
All donations made through GitHub will be deposited to our account with the Open Source Collective and managed by the Open Collective. This means we have a single place to monitor and maintain transparency of our finances.
</p>
<p>
If you are able, please contribute to this amazing project.
All donations made through GitHub will be deposited to our account
with the Open Source Collective and managed by the Open Collective.
This means we have a single place to monitor and maintain
transparency of our finances.
</p>
<p>If you are able, please contribute to this amazing project.</p>
<div className="indexCtasBody">
<Link
className={'button button--outline button--lg cta--button'}
to={'https://opencollective.com/meshtastic/donate'}
className={"button button--outline button--lg cta--button"}
to={"https://opencollective.com/meshtastic/donate"}
>
Sponsor Meshtastic
</Link>
@ -93,11 +137,7 @@ const Credits = (): JSX.Element => {
key={logo.name}
className="col-span-1 flex justify-center bg-gray-50 py-8 px-8"
>
<img
className="max-h-12"
src={logo.url}
alt={logo.name}
/>
<img className="max-h-12" src={logo.url} alt={logo.name} />
</div>
))}
</div>
@ -105,7 +145,10 @@ const Credits = (): JSX.Element => {
<div className="container mx-auto p-6 leading-normal space-y-4">
<h2>Contributors</h2>
<p>
Literally thousands of hours have gone into creating, maintaining, and improving Meshtastic. Without our contributors none of this would be possible. Thank you for donating the time for each and every commit, issue, and pull request.
Literally thousands of hours have gone into creating, maintaining,
and improving Meshtastic. Without our contributors none of this
would be possible. Thank you for donating the time for each and
every commit, issue, and pull request.
</p>
{/*GitHub Organization Contributors*/}
<AvatarLayout list={[]} />
@ -116,7 +159,7 @@ const Credits = (): JSX.Element => {
</div>
</main>
</Layout>
)
}
);
};
export default Credits;

View file

@ -4,6 +4,4 @@ title: Meshtastic URL
sidebar_label: d
---
# Error : Something happened
Please go to [Android Usage](/docs/software/android/usage#join-a-channel) for more information.

View file

@ -1,4 +1,4 @@
import React from 'react';
import React from "react";
export interface downloadCardProps {
client: string;
@ -17,19 +17,19 @@ export const DownloadCard = ({
imgUrl2,
url2,
notes,
buttonText,
buttonText
}: downloadCardProps): JSX.Element => {
return (
<div className="card">
<div
className="card__header"
style={{ display: 'flex', justifyContent: 'space-between' }}
style={{ display: "flex", justifyContent: "space-between" }}
>
<h3>{client}</h3>
</div>
<div
className="card__body"
style={{ display: 'flex', justifyContent: 'center' }}
style={{ display: "flex", justifyContent: "center" }}
>
{buttonText ? (
<a href={url} className="button button--secondary button--block">
@ -38,10 +38,10 @@ export const DownloadCard = ({
) : (
<div>
<a href={url}>
<img alt="img1" style={{ height: '4rem' }} src={imgUrl}></img>
<img alt="img1" style={{ height: "4rem" }} src={imgUrl}></img>
</a>
<a href={url2}>
<img alt="img2" style={{ height: '4rem' }} src={imgUrl2}></img>
<img alt="img2" style={{ height: "4rem" }} src={imgUrl2}></img>
</a>
</div>
)}
@ -56,89 +56,89 @@ export const PlaceholderCard = (): JSX.Element => {
<div
className="card"
style={{
width: '100%',
animation: 'pulse 2s infinite',
transform: 'scale(1)',
display: 'flex',
gap: '1rem',
padding: '1rem',
width: "100%",
animation: "pulse 2s infinite",
transform: "scale(1)",
display: "flex",
gap: "1rem",
padding: "1rem"
}}
>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
marginBottom: '1rem',
display: "flex",
justifyContent: "space-between",
marginBottom: "1rem"
}}
>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
height: '2rem',
width: '8rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
height: "2rem",
width: "8rem"
}}
/>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
marginTop: '1rem',
height: '1rem',
width: '8rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
marginTop: "1rem",
height: "1rem",
width: "8rem"
}}
/>
</div>
<div
className="card__body"
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
height: '3rem',
display: 'flex',
jusifyContent: 'center',
alignItems: 'center',
borderRadius: "0.4rem",
backgroundColor: "gray",
height: "3rem",
display: "flex",
jusifyContent: "center",
alignItems: "center"
}}
/>
<a className="button disabled button--primary button--block">&nbsp;</a>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: '8rem',
height: '2rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
width: "8rem",
height: "2rem"
}}
/>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: '11rem',
height: '1rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
width: "11rem",
height: "1rem"
}}
/>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: '9rem',
height: '1rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
width: "9rem",
height: "1rem"
}}
/>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: '13rem',
height: '1rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
width: "13rem",
height: "1rem"
}}
/>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: '11rem',
height: '1rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
width: "11rem",
height: "1rem"
}}
/>
</div>

View file

@ -1,6 +1,6 @@
import React from 'react';
import React from "react";
import { DeviceFirmwareResource } from '../../../utils/apiTypes.js';
import { DeviceFirmwareResource } from "../../../utils/apiTypes.js";
export interface releaseCardProps {
variant: string;
@ -11,13 +11,13 @@ export interface releaseCardProps {
export const FirmwareCard = ({
variant,
description,
release,
release
}: releaseCardProps): JSX.Element => {
return (
<div className="card m-4 border-2 border-secondary">
<div
className="card__header"
style={{ display: 'flex', justifyContent: 'space-between' }}
style={{ display: "flex", justifyContent: "space-between" }}
>
<h3>{variant}</h3>
{release?.length && (
@ -64,86 +64,86 @@ export const PlaceholderFirmwareCard = (): JSX.Element => {
<div
className="card"
style={{
width: '100%',
animation: 'pulse 2s infinite',
transform: 'scale(1)',
display: 'flex',
gap: '1rem',
padding: '1rem',
width: "100%",
animation: "pulse 2s infinite",
transform: "scale(1)",
display: "flex",
gap: "1rem",
padding: "1rem"
}}
>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
marginBottom: '1rem',
display: "flex",
justifyContent: "space-between",
marginBottom: "1rem"
}}
>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
height: '2rem',
width: '8rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
height: "2rem",
width: "8rem"
}}
/>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
marginTop: '1rem',
height: '1rem',
width: '8rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
marginTop: "1rem",
height: "1rem",
width: "8rem"
}}
/>
</div>
<div
className="card__body"
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
height: '3rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
height: "3rem"
}}
/>
<a className="button disabled button--primary button--block">&nbsp;</a>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: '8rem',
height: '2rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
width: "8rem",
height: "2rem"
}}
/>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: '11rem',
height: '1rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
width: "11rem",
height: "1rem"
}}
/>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: '9rem',
height: '1rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
width: "9rem",
height: "1rem"
}}
/>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: '13rem',
height: '1rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
width: "13rem",
height: "1rem"
}}
/>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: '11rem',
height: '1rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
width: "11rem",
height: "1rem"
}}
/>
</div>

View file

@ -1,4 +1,4 @@
import React from 'react';
import React from "react";
export const HeaderText = ({ type, text, link }): JSX.Element => {
const Header = type;

View file

@ -1,28 +1,28 @@
import React from 'react';
import React from "react";
import { FaAndroid, FaApple } from 'react-icons/fa';
import useSWR from 'swr';
import { FaAndroid, FaApple } from "react-icons/fa";
import useSWR from "swr";
import {
ArrowTopRightOnSquareIcon,
BoltIcon,
ComputerDesktopIcon,
CpuChipIcon,
GlobeAltIcon,
} from '@heroicons/react/24/solid';
import Layout from '@theme/Layout';
GlobeAltIcon
} from "@heroicons/react/24/solid";
import Layout from "@theme/Layout";
import { FirmwareReleases } from '../../utils/apiTypes.js';
import { fetcher } from '../../utils/swr';
import { FirmwareReleases } from "../../utils/apiTypes.js";
import { fetcher } from "../../utils/swr";
import {
FirmwareCard,
PlaceholderFirmwareCard,
} from './_components/FirmwareCard';
PlaceholderFirmwareCard
} from "./_components/FirmwareCard";
const Firmware = (): JSX.Element => {
const { data, error } = useSWR<FirmwareReleases>(
'https://api.meshtastic.org/github/firmware/list',
fetcher,
"https://api.meshtastic.org/github/firmware/list",
fetcher
);
return (

View file

@ -9,8 +9,8 @@ sidebar_label: e
<meta property="og:site_name" content="Meshtastic.org" />
</head>
# QR Code Share Channel URL Should be opened in the appropriate app
## QR Code Share Channel URL Should be opened in the appropriate app
## Meshtastic QR Code URL Format For Firmware version 2.0
### Meshtastic QR Code URL Format For Firmware version 2.0
For Android use the QR code scanner in the app, on Apple devices use the camera to open the QR code URL in the Meshtastic App.

View file

@ -1,19 +1,19 @@
import React, { useState } from 'react';
import React, { useState } from "react";
import { FiPlus } from 'react-icons/fi';
import { FiPlus } from "react-icons/fi";
import { HardwareModal } from '@site/src/components/hardware/HardwareModal';
import { IDevice } from '@site/src/data/device';
import { HardwareModal } from "@site/src/components/hardware/HardwareModal";
import { IDevice } from "@site/src/data/device";
import { HardwareCard } from '../../components/hardware/HardwareCard';
import { PageLayout } from '../../components/PageLayout';
import { heltec } from '../../data/devices/heltec';
import { hydra } from '../../data/devices/hydra';
import { nano_g1 } from '../../data/devices/nano_g1';
import { rak19001 } from '../../data/devices/rak19001';
import { rak19003 } from '../../data/devices/rak19003';
import { tbeam } from '../../data/devices/tbeam';
import { techo } from '../../data/devices/techo';
import { HardwareCard } from "../../components/hardware/HardwareCard";
import { PageLayout } from "../../components/PageLayout";
import { heltec } from "../../data/devices/heltec";
import { hydra } from "../../data/devices/hydra";
import { nano_g1 } from "../../data/devices/nano_g1";
import { rak19001 } from "../../data/devices/rak19001";
import { rak19003 } from "../../data/devices/rak19003";
import { tbeam } from "../../data/devices/tbeam";
import { techo } from "../../data/devices/techo";
const Hardware = (): JSX.Element => {
const hardware = [tbeam, hydra, rak19003, rak19001, nano_g1, heltec, techo];
@ -31,7 +31,7 @@ const Hardware = (): JSX.Element => {
<a
href="#"
className="border-indigo-500 text-indigo-600"
aria-current={'page'}
aria-current={"page"}
>
Devices
</a>

View file

@ -1,21 +1,21 @@
import 'react-responsive-carousel/lib/styles/carousel.min.css'; // requires a loader
import "react-responsive-carousel/lib/styles/carousel.min.css"; // requires a loader
import React from 'react';
import React from "react";
import { Carousel } from 'react-responsive-carousel';
import { Carousel } from "react-responsive-carousel";
import Head from '@docusaurus/Head';
import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import Layout from '@theme/Layout';
import Head from "@docusaurus/Head";
import Link from "@docusaurus/Link";
import useBaseUrl from "@docusaurus/useBaseUrl";
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import Layout from "@theme/Layout";
import { SocialCard, SocialCardProps } from '../components/homepage/SocialCard';
import { SocialCard, SocialCardProps } from "../components/homepage/SocialCard";
const features = [
{
title: 'Radio Mesh Text Messaging',
imageUrl: 'img/homepage/messages.svg',
title: "Radio Mesh Text Messaging",
imageUrl: "img/homepage/messages.svg",
description: (
<>
Off-grid messaging using inexpensive hardware to create your personal
@ -23,11 +23,11 @@ const features = [
Communicate kilometers/miles between nodes. Internet-connected relay
nodes enable the conversation to move online too.
</>
),
)
},
{
title: 'Encryption',
imageUrl: 'img/homepage/encryption.svg',
title: "Encryption",
imageUrl: "img/homepage/encryption.svg",
description: (
<>
Messages are AES256 encrypted. Only radios supplied with your channel
@ -35,22 +35,22 @@ const features = [
Using multichannel settings you can send encrypted messages on one
channel and still participate in a default Meshtastic mesh.
</>
),
)
},
{
title: 'Conserve Battery',
imageUrl: 'img/homepage/battery.svg',
title: "Conserve Battery",
imageUrl: "img/homepage/battery.svg",
description: (
<>
Go for days on end and on a single battery or extend it infinitely with
a solar cell. Power management ensures the device will last the duration
of your use.
</>
),
)
},
{
title: 'Extensible',
imageUrl: 'img/homepage/extendable.svg',
title: "Extensible",
imageUrl: "img/homepage/extendable.svg",
description: (
<>
Create a highly scalable mesh with hardware on a multitude of platforms
@ -58,77 +58,98 @@ const features = [
and produce real-time heatmaps, or maybe decentralized, encrypted
messaging network, your imagination is the limit.
</>
),
)
},
{
title: 'Platform Agnostic',
imageUrl: 'img/homepage/platforms.svg',
title: "Platform Agnostic",
imageUrl: "img/homepage/platforms.svg",
description: (
<>
Meshtastic clients are built or being built for all major desktop and
mobile platforms. Linux, Windows, Mac, Android, and iOS are all
supported or well on their way to being supported.
</>
),
)
},
{
title: 'Open Source',
imageUrl: 'img/homepage/opensource.svg',
title: "Open Source",
imageUrl: "img/homepage/opensource.svg",
description: (
<>
All Meshtastic software is open source. If you want an improvement,
submit a pull request or file an issue on Github. Happy coding!
</>
),
},
)
}
];
const SocialCards: SocialCardProps[] = [
{
color: 'bg-[#5865F2]',
link: 'https://discord.com/invite/UQJ5QuM7vq',
color: "bg-[#5865F2]",
link: "https://discord.com/invite/UQJ5QuM7vq",
children: (
<img alt="discord" className="m-auto h-10" src="/img/homepage/Discord-Logo-White.svg" />
),
<img
alt="discord"
className="m-auto h-10"
src="/img/homepage/Discord-Logo-White.svg"
/>
)
},
{
color: 'bg-[#ffffff]',
link: 'https://twitter.com/TheMeshtastic',
color: "bg-[#ffffff]",
link: "https://twitter.com/TheMeshtastic",
children: (
<img alt="twitter" className="m-auto h-10" src="/img/homepage/Twitter-logo.svg" />
),
<img
alt="twitter"
className="m-auto h-10"
src="/img/homepage/Twitter-logo.svg"
/>
)
},
{
color: 'bg-[#FF0000]',
link: 'https://www.youtube.com/meshtastic',
color: "bg-[#FF0000]",
link: "https://www.youtube.com/meshtastic",
children: (
<img alt="youtube" className="m-auto h-16" src="/img/homepage/YouTube-Logo-White.svg" />
),
<img
alt="youtube"
className="m-auto h-16"
src="/img/homepage/YouTube-Logo-White.svg"
/>
)
},
{
color: 'bg-[#ffffff]',
link: 'https://meshtastic.discourse.group',
color: "bg-[#ffffff]",
link: "https://meshtastic.discourse.group",
children: (
<img alt="discourse"
<img
alt="discourse"
className="m-auto h-12"
src="/img/homepage/Discourse-Logo-White.svg"
/>
),
)
},
{
color: 'bg-[#FF4500]',
link: 'https://reddit.com/r/meshtastic',
color: "bg-[#FF4500]",
link: "https://reddit.com/r/meshtastic",
children: (
<img alt="reddit" className="m-auto h-20" src="/img/homepage/Reddit-Logo-White.svg" />
),
<img
alt="reddit"
className="m-auto h-20"
src="/img/homepage/Reddit-Logo-White.svg"
/>
)
},
{
color: 'bg-[#ffffff]',
link: 'https://github.com/meshtastic',
color: "bg-[#ffffff]",
link: "https://github.com/meshtastic",
children: (
<img alt="github" className="m-auto w-12" src="/img/homepage/GitHub-Logo-White.svg" />
),
},
<img
alt="github"
className="m-auto w-12"
src="/img/homepage/GitHub-Logo-White.svg"
/>
)
}
];
function Feature({ imageUrl, title, description }) {
@ -155,7 +176,7 @@ function Home() {
<meta property="og:title" content="Meshtastic" />
<meta
property="og:image"
content={useBaseUrl('design/web/social-preview-1200x630.png')}
content={useBaseUrl("design/web/social-preview-1200x630.png")}
/>
<meta
property="og:description"
@ -164,14 +185,14 @@ function Home() {
<meta property="og:url" content="https://meshtastic.org/" />
<meta name="twitter:card" content="summary_large_image" />
</Head>
<header style={{ textAlign: 'center' }} className="hero hero--primary">
<header style={{ textAlign: "center" }} className="hero hero--primary">
<div className="container">
<h1 className="hero__title">
<img
style={{ paddingTop: '2rem', paddingBottom: '2rem' }}
style={{ paddingTop: "2rem", paddingBottom: "2rem" }}
alt="Meshtastic Logo"
className="header__logo"
src={useBaseUrl('design/typelogo/typelogo.svg')}
src={useBaseUrl("design/typelogo/typelogo.svg")}
/>
</h1>
<p className="hero__subtitle">{siteConfig.tagline}</p>
@ -222,23 +243,23 @@ function Home() {
<ul
className="mx-auto"
style={{
position: 'relative',
display: 'grid',
gap: '1.5rem',
gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))',
paddingLeft: '0',
position: "relative",
display: "grid",
gap: "1.5rem",
gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
paddingLeft: "0"
}}
>
<div className="card">
<div
className="card__header"
style={{ display: 'flex', justifyContent: 'space-between' }}
style={{ display: "flex", justifyContent: "space-between" }}
>
<h3>1. Purchase Supported Hardware</h3>
</div>
<div
className="card__body"
style={{ display: 'flex', justifyContent: 'center' }}
style={{ display: "flex", justifyContent: "center" }}
>
<p>
Hardware you will want to consider:
@ -258,13 +279,13 @@ function Home() {
<div className="card">
<div
className="card__header"
style={{ display: 'flex', justifyContent: 'space-between' }}
style={{ display: "flex", justifyContent: "space-between" }}
>
<h3>2. Flash & Configure Node</h3>
</div>
<div
className="card__body"
style={{ display: 'flex', justifyContent: 'center' }}
style={{ display: "flex", justifyContent: "center" }}
>
<p>
The Meshtastic Flasher application can assist you in flashing
@ -275,13 +296,13 @@ function Home() {
<div className="card">
<div
className="card__header"
style={{ display: 'flex', justifyContent: 'space-between' }}
style={{ display: "flex", justifyContent: "space-between" }}
>
<h3>3. Connect to Node</h3>
</div>
<div
className="card__body"
style={{ display: 'flex', justifyContent: 'center' }}
style={{ display: "flex", justifyContent: "center" }}
>
<p>
Applications are available for the following systems:

View file

@ -1,8 +1,8 @@
import React from 'react';
import React from "react";
import { Showcase } from '../../../utils/apiTypes';
import { mapUrl } from '../../../utils/map';
import { CardTags } from './CardTags';
import { Showcase } from "../../../utils/apiTypes";
import { mapUrl } from "../../../utils/map";
import { CardTags } from "./CardTags";
export interface CardProps {
network: Showcase;
@ -11,7 +11,7 @@ export interface CardProps {
export const Card = React.memo(({ network }: CardProps) => (
<div className="card">
<div className="card__image">
<div style={{ height: '140px' }}>
<div style={{ height: "140px" }}>
<img img={mapUrl(network.nodes ?? [])} alt={network.title} />
</div>
</div>
@ -23,7 +23,7 @@ export const Card = React.memo(({ network }: CardProps) => (
<a
href={`?id=${network.id}`}
className="button button--primary button--block"
style={{ marginBottom: '0.5rem' }}
style={{ marginBottom: "0.5rem" }}
>
Read more
</a>
@ -36,72 +36,72 @@ export const PlaceholderCard = (): JSX.Element => (
<div
className="card"
style={{
animation: 'pulse 2s infinite',
transform: 'scale(1)',
animation: "pulse 2s infinite",
transform: "scale(1)"
}}
>
<div className="card__image">
<div
style={{
height: '140px',
height: "140px"
}}
/>
</div>
<div className="card__body">
<div
style={{
width: '30%',
height: '2rem',
borderRadius: '0.4rem',
backgroundColor: 'gray',
marginBottom: '1rem',
width: "30%",
height: "2rem",
borderRadius: "0.4rem",
backgroundColor: "gray",
marginBottom: "1rem"
}}
/>
<div
style={{
width: '100%',
height: '1rem',
borderRadius: '0.4rem',
backgroundColor: 'gray',
marginBottom: '0.5rem',
width: "100%",
height: "1rem",
borderRadius: "0.4rem",
backgroundColor: "gray",
marginBottom: "0.5rem"
}}
/>
<div
style={{
width: '100%',
height: '1rem',
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: "100%",
height: "1rem",
borderRadius: "0.4rem",
backgroundColor: "gray"
}}
/>
</div>
<div className="card__footer">
<a
className="button disabled button--primary button--block"
style={{ marginBottom: '0.5rem' }}
style={{ marginBottom: "0.5rem" }}
>
&nbsp;
</a>
<div
style={{
display: 'flex',
gap: '0.5rem',
display: "flex",
gap: "0.5rem"
}}
>
<div
style={{
width: '4rem',
height: '1.5rem',
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: "4rem",
height: "1.5rem",
borderRadius: "0.4rem",
backgroundColor: "gray"
}}
/>
<div
style={{
width: '4rem',
height: '1.5rem',
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: "4rem",
height: "1.5rem",
borderRadius: "0.4rem",
backgroundColor: "gray"
}}
/>
</div>

View file

@ -1,6 +1,6 @@
import React from 'react';
import React from "react";
import { ShowcaseTag } from '../../../utils/apiTypes';
import { ShowcaseTag } from "../../../utils/apiTypes";
export interface CardTagsProps {
tags: ShowcaseTag[];
@ -16,8 +16,8 @@ export const CardTags = ({ tags }: CardTagsProps) => {
key={index}
style={{
backgroundColor: color,
marginRight: '0.3rem',
userSelect: 'none',
marginRight: "0.3rem",
userSelect: "none"
}}
>
{label}

View file

@ -1,21 +1,21 @@
import React from 'react';
import React from "react";
import { FiHeart } from 'react-icons/fi';
import useSWR from 'swr';
import { FiHeart } from "react-icons/fi";
import useSWR from "swr";
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import { fetcher } from '@site/src/utils/swr';
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import { fetcher } from "@site/src/utils/swr";
import { ShowcaseTag } from '../../../utils/apiTypes';
import { ShowcaseTag } from "../../../utils/apiTypes";
// import { TagList, Tags } from '../../../utils/showcase';
import { PlaceholderTagSelect, TagSelect } from './TagSelect';
import { PlaceholderTagSelect, TagSelect } from "./TagSelect";
export const Filters = (): JSX.Element => {
const { siteConfig } = useDocusaurusContext();
const { data, error } = useSWR<ShowcaseTag[]>(
`${siteConfig.customFields.API_URL}/showcase/tags`,
fetcher,
fetcher
);
return (
@ -23,10 +23,10 @@ export const Filters = (): JSX.Element => {
{data && !error ? (
<ul
style={{
padding: '0',
display: 'flex',
alignItems: 'center',
flexWrap: 'wrap',
padding: "0",
display: "flex",
alignItems: "center",
flexWrap: "wrap"
}}
>
{data.map((tag, i) => {
@ -37,17 +37,17 @@ export const Filters = (): JSX.Element => {
<div
key={i}
style={{
boxSizing: 'border-box',
position: 'relative',
display: 'inline-flex',
alignItems: 'center',
height: '2rem',
marginTop: '0.5rem',
marginRight: '0.5rem',
fontSize: '0.875rem',
lineHeight: '1.25rem',
verticalAlign: 'middle',
userSelect: 'none',
boxSizing: "border-box",
position: "relative",
display: "inline-flex",
alignItems: "center",
height: "2rem",
marginTop: "0.5rem",
marginRight: "0.5rem",
fontSize: "0.875rem",
lineHeight: "1.25rem",
verticalAlign: "middle",
userSelect: "none"
}}
>
<TagSelect
@ -55,12 +55,12 @@ export const Filters = (): JSX.Element => {
id={id}
label={label}
icon={
tag.label === 'Favorite' ? (
tag.label === "Favorite" ? (
<span
style={{
display: 'flex',
marginLeft: '0.5rem',
color: 'rgb(190 24 93)',
display: "flex",
marginLeft: "0.5rem",
color: "rgb(190 24 93)"
}}
>
<FiHeart />
@ -71,8 +71,8 @@ export const Filters = (): JSX.Element => {
backgroundColor: color,
width: 10,
height: 10,
borderRadius: '50%',
marginLeft: 8,
borderRadius: "50%",
marginLeft: 8
}}
/>
)

View file

@ -1,11 +1,11 @@
import React from 'react';
import React from "react";
import useSWR from 'swr';
import useSWR from "swr";
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import { Showcase } from '@site/src/utils/apiTypes';
import { User } from '@site/src/utils/github';
import { fetcher } from '@site/src/utils/swr';
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import { Showcase } from "@site/src/utils/apiTypes";
import { User } from "@site/src/utils/github";
import { fetcher } from "@site/src/utils/swr";
interface NetworkProps {
id: string;
@ -16,12 +16,12 @@ export const Network = ({ id }: NetworkProps): JSX.Element => {
const { data, error } = useSWR<Showcase>(
`${siteConfig.customFields.API_URL}/showcase/${id}`,
fetcher,
fetcher
);
const githubData = useSWR<User>(
`https://api.github.com/users/${data?.author?.githubUsername}`,
fetcher,
fetcher
).data;
return (
@ -48,15 +48,15 @@ export const Network = ({ id }: NetworkProps): JSX.Element => {
<div
className="card"
style={{
marginLeft: 'auto',
marginRight: 'auto',
maxWidth: '900px',
marginLeft: "auto",
marginRight: "auto",
maxWidth: "900px"
}}
>
<div
className="card__header"
style={{
margin: '8px',
margin: "8px"
}}
>
<h2>Bill of Materials</h2>
@ -66,14 +66,14 @@ export const Network = ({ id }: NetworkProps): JSX.Element => {
<div
key={index}
style={{
borderTop: '2px solid gray',
display: 'flex',
borderTop: "2px solid gray",
display: "flex"
}}
>
<div
style={{
width: '4rem',
display: 'flex',
width: "4rem",
display: "flex"
}}
>
<img
@ -81,13 +81,13 @@ export const Network = ({ id }: NetworkProps): JSX.Element => {
height="auto"
width="100%"
style={{
margin: 'auto',
padding: '4px',
display: 'block',
maxWidth: '60px',
maxHeight: '60px',
width: 'auto',
height: 'auto',
margin: "auto",
padding: "4px",
display: "block",
maxWidth: "60px",
maxHeight: "60px",
width: "auto",
height: "auto"
}}
/>
</div>
@ -103,8 +103,8 @@ export const Network = ({ id }: NetworkProps): JSX.Element => {
href={material.url}
className="button button--outline button--secondary"
style={{
marginTop: 'auto',
marginBottom: 'auto',
marginTop: "auto",
marginBottom: "auto"
}}
>
View
@ -129,74 +129,74 @@ export const PlaceholderNetwork = (): JSX.Element => {
<div
className="container"
style={{
display: 'flex',
flexDirection: window.innerWidth > 768 ? 'row' : 'column',
gap: '2rem',
display: "flex",
flexDirection: window.innerWidth > 768 ? "row" : "column",
gap: "2rem"
}}
>
<div
style={{
width: window.innerWidth > 768 ? '60%' : '100%',
width: window.innerWidth > 768 ? "60%" : "100%"
}}
>
<div
className="card"
style={{
width: '100%',
animation: 'pulse 2s infinite',
transform: 'scale(1)',
display: 'flex',
flexDirection: 'column',
gap: '2rem',
padding: '2rem',
width: "100%",
animation: "pulse 2s infinite",
transform: "scale(1)",
display: "flex",
flexDirection: "column",
gap: "2rem",
padding: "2rem"
}}
>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
height: '4rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
height: "4rem"
}}
/>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
height: '12rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
height: "12rem"
}}
/>
<div style={{ display: 'flex', gap: '1rem' }}>
<div style={{ display: "flex", gap: "1rem" }}>
<div
style={{
borderRadius: '999px',
backgroundColor: 'gray',
height: '4rem',
width: '4rem',
minWidth: '4rem',
borderRadius: "999px",
backgroundColor: "gray",
height: "4rem",
width: "4rem",
minWidth: "4rem"
}}
/>
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: '1rem',
width: '100%',
display: "flex",
flexDirection: "column",
gap: "1rem",
width: "100%"
}}
>
<div
style={{
width: '100%',
borderRadius: '0.4rem',
backgroundColor: 'gray',
height: '1rem',
width: "100%",
borderRadius: "0.4rem",
backgroundColor: "gray",
height: "1rem"
}}
/>
<div
style={{
width: '100%',
borderRadius: '0.4rem',
backgroundColor: 'gray',
height: '2rem',
width: "100%",
borderRadius: "0.4rem",
backgroundColor: "gray",
height: "2rem"
}}
/>
</div>
@ -205,108 +205,108 @@ export const PlaceholderNetwork = (): JSX.Element => {
</div>
<div
style={{
width: window.innerWidth > 768 ? '40%' : '100%',
width: window.innerWidth > 768 ? "40%" : "100%"
}}
>
<div
className="card"
style={{
width: '100%',
animation: 'pulse 2s infinite',
transform: 'scale(1)',
display: 'flex',
flexDirection: 'column',
gap: '2rem',
padding: '2rem',
width: "100%",
animation: "pulse 2s infinite",
transform: "scale(1)",
display: "flex",
flexDirection: "column",
gap: "2rem",
padding: "2rem"
}}
>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
height: '12rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
height: "12rem"
}}
/>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
height: '2rem',
borderRadius: "0.4rem",
backgroundColor: "gray",
height: "2rem"
}}
/>
<div style={{ display: 'flex', gap: '0.5rem' }}>
<div style={{ display: "flex", gap: "0.5rem" }}>
<div
style={{
width: '7rem',
height: '1.8rem',
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: "7rem",
height: "1.8rem",
borderRadius: "0.4rem",
backgroundColor: "gray"
}}
/>
<div
style={{
width: '7rem',
height: '1.8rem',
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: "7rem",
height: "1.8rem",
borderRadius: "0.4rem",
backgroundColor: "gray"
}}
/>
<div
style={{
width: '7rem',
height: '1.8rem',
borderRadius: '0.4rem',
backgroundColor: 'gray',
width: "7rem",
height: "1.8rem",
borderRadius: "0.4rem",
backgroundColor: "gray"
}}
/>
</div>
<div
style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}
style={{ display: "flex", flexDirection: "column", gap: "1rem" }}
>
<div style={{ display: 'flex', gap: '1rem' }}>
<div style={{ display: "flex", gap: "1rem" }}>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
height: '2.5rem',
width: '20%',
borderRadius: "0.4rem",
backgroundColor: "gray",
height: "2.5rem",
width: "20%"
}}
/>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
height: '2.5rem',
width: '60%',
borderRadius: "0.4rem",
backgroundColor: "gray",
height: "2.5rem",
width: "60%"
}}
/>
<a
className="button disabled button--primary button--block"
style={{ width: '20%' }}
style={{ width: "20%" }}
>
&nbsp;
</a>
</div>
<div style={{ display: 'flex', gap: '1rem' }}>
<div style={{ display: "flex", gap: "1rem" }}>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
height: '2.5rem',
width: '20%',
borderRadius: "0.4rem",
backgroundColor: "gray",
height: "2.5rem",
width: "20%"
}}
/>
<div
style={{
borderRadius: '0.4rem',
backgroundColor: 'gray',
height: '2.5rem',
width: '60%',
borderRadius: "0.4rem",
backgroundColor: "gray",
height: "2.5rem",
width: "60%"
}}
/>
<a
className="button disabled button--primary button--block"
style={{ width: '20%' }}
style={{ width: "20%" }}
>
&nbsp;
</a>

View file

@ -1,7 +1,7 @@
import React from 'react';
import React from "react";
import { Showcase } from '../../../utils/apiTypes';
import { Card, PlaceholderCard } from './Card';
import { Showcase } from "../../../utils/apiTypes";
import { Card, PlaceholderCard } from "./Card";
interface NetworkSectionProps {
title: string;
@ -14,26 +14,26 @@ export const NetworkSection = ({
title,
icon,
iconColor,
networks,
networks
}: NetworkSectionProps): JSX.Element => {
return (
<div className="margin-top--lg container">
<div
className="margin-bottom--sm"
style={{
display: 'flex',
alignItems: 'center',
display: "flex",
alignItems: "center"
}}
>
<h2>{title}</h2>
{icon && (
<span
style={{
marginBottom: '0.5rem',
marginLeft: '0.5rem',
fontSize: '1.25rem',
lineHeight: '1.75rem',
color: iconColor,
marginBottom: "0.5rem",
marginLeft: "0.5rem",
fontSize: "1.25rem",
lineHeight: "1.75rem",
color: iconColor
}}
>
{icon}
@ -42,11 +42,11 @@ export const NetworkSection = ({
</div>
<ul
style={{
position: 'relative',
display: 'grid',
gap: '1.5rem',
gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))',
paddingLeft: '0',
position: "relative",
display: "grid",
gap: "1.5rem",
gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
paddingLeft: "0"
}}
>
{networks ? (

View file

@ -1,22 +1,22 @@
import React from 'react';
import React from "react";
import { FiHeart, FiSearch } from 'react-icons/fi';
import useSWR from 'swr';
import { FiHeart, FiSearch } from "react-icons/fi";
import useSWR from "swr";
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import { useSelectedTags } from '@site/src/hooks/useSelectedTags';
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import { useSelectedTags } from "@site/src/hooks/useSelectedTags";
import { useFilteredNetworks } from '../../../hooks/useFilteredNetworks';
import { Showcase } from '../../../utils/apiTypes';
import { fetcher } from '../../../utils/swr';
import { NetworkSection } from './NetworkSection';
import { useFilteredNetworks } from "../../../hooks/useFilteredNetworks";
import { Showcase } from "../../../utils/apiTypes";
import { fetcher } from "../../../utils/swr";
import { NetworkSection } from "./NetworkSection";
export const Networks = (): JSX.Element => {
const { siteConfig } = useDocusaurusContext();
const { data, error } = useSWR<Showcase[]>(
`${siteConfig.customFields.API_URL}/showcase`,
fetcher,
fetcher
);
const selectedTags = useSelectedTags();
@ -32,7 +32,7 @@ export const Networks = (): JSX.Element => {
icon={<FiHeart />}
iconColor="rgb(190 24 93)"
networks={data?.filter((network) =>
network.tags.find((tag) => tag.label === 'Favorite'),
network.tags.find((tag) => tag.label === "Favorite")
)}
/>
<NetworkSection title="All networks" networks={data} />

View file

@ -1,26 +1,26 @@
import 'url-search-params-polyfill';
import "url-search-params-polyfill";
import React from 'react';
import React from "react";
import { useHistory, useLocation } from '@docusaurus/router';
import { ShowcaseTag } from '@site/src/utils/apiTypes';
import { useHistory, useLocation } from "@docusaurus/router";
import { ShowcaseTag } from "@site/src/utils/apiTypes";
import { toggleListItem } from '../../../utils/showcase';
import { toggleListItem } from "../../../utils/showcase";
interface Props extends React.ComponentProps<'input'> {
icon: React.ReactElement<React.ComponentProps<'svg'>>;
interface Props extends React.ComponentProps<"input"> {
icon: React.ReactElement<React.ComponentProps<"svg">>;
label: React.ReactNode;
tag: ShowcaseTag;
}
export function readSearchTags(search: string): string[] {
return new URLSearchParams(search).getAll('tags');
return new URLSearchParams(search).getAll("tags");
}
function replaceSearchTags(search: string, newTags: string[]) {
const searchParams = new URLSearchParams(search);
searchParams.delete('tags');
newTags.forEach((tag) => searchParams.append('tags', tag));
searchParams.delete("tags");
newTags.forEach((tag) => searchParams.append("tags", tag));
return searchParams.toString();
}
@ -42,11 +42,11 @@ export const TagSelect = React.forwardRef<HTMLLabelElement, Props>(
return (
<button
style={{
display: 'flex',
alignItems: 'center',
display: "flex",
alignItems: "center"
}}
className={`button button--sm button--outline button--secondary ${
selected ? 'button--active' : ''
selected ? "button--active" : ""
}`}
onClick={() => {
toggleTag();
@ -56,55 +56,55 @@ export const TagSelect = React.forwardRef<HTMLLabelElement, Props>(
{icon}
</button>
);
},
}
);
export const PlaceholderTagSelect = (): JSX.Element => (
<div
style={{
boxSizing: 'border-box',
position: 'relative',
display: 'inline-flex',
alignItems: 'center',
height: '2rem',
marginTop: '0.5rem',
marginRight: '0.5rem',
fontSize: '0.875rem',
lineHeight: '1.25rem',
verticalAlign: 'middle',
userSelect: 'none',
boxSizing: "border-box",
position: "relative",
display: "inline-flex",
alignItems: "center",
height: "2rem",
marginTop: "0.5rem",
marginRight: "0.5rem",
fontSize: "0.875rem",
lineHeight: "1.25rem",
verticalAlign: "middle",
userSelect: "none"
}}
>
<div
style={{
width: '7rem',
height: '1.8rem',
borderRadius: '0.4rem',
backgroundColor: 'gray',
animation: 'pulse 2s infinite',
transform: 'scale(1)',
width: "7rem",
height: "1.8rem",
borderRadius: "0.4rem",
backgroundColor: "gray",
animation: "pulse 2s infinite",
transform: "scale(1)"
}}
/>
<div
style={{
width: '7rem',
height: '1.8rem',
borderRadius: '0.4rem',
backgroundColor: 'gray',
animation: 'pulse 2s infinite',
transform: 'scale(1)',
marginLeft: 8,
width: "7rem",
height: "1.8rem",
borderRadius: "0.4rem",
backgroundColor: "gray",
animation: "pulse 2s infinite",
transform: "scale(1)",
marginLeft: 8
}}
/>
<div
style={{
width: '7rem',
height: '1.8rem',
borderRadius: '0.4rem',
backgroundColor: 'gray',
animation: 'pulse 2s infinite',
transform: 'scale(1)',
marginLeft: 8,
width: "7rem",
height: "1.8rem",
borderRadius: "0.4rem",
backgroundColor: "gray",
animation: "pulse 2s infinite",
transform: "scale(1)",
marginLeft: 8
}}
/>
</div>

View file

@ -1,17 +1,17 @@
import 'url-search-params-polyfill';
import "url-search-params-polyfill";
import React from 'react';
import React from "react";
import { useLocation } from '@docusaurus/router';
import Layout from '@theme/Layout';
import { useLocation } from "@docusaurus/router";
import Layout from "@theme/Layout";
import { Filters } from './_components/Filters';
import { Network } from './_components/Network';
import { Networks } from './_components/Networks';
import { Filters } from "./_components/Filters";
import { Network } from "./_components/Network";
import { Networks } from "./_components/Networks";
const Showcase = (): JSX.Element => {
const location = useLocation();
const id = new URLSearchParams(location.search).get('id');
const id = new URLSearchParams(location.search).get("id");
return (
<Layout
@ -19,7 +19,7 @@ const Showcase = (): JSX.Element => {
description="Portfolio of projects from the Meshtastic community"
>
<main className="margin-vert--lg">
{!!id ? (
{id ? (
<Network id={id} />
) : (
<>

View file

@ -1,19 +1,19 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState } from "react";
import { fromByteArray, toByteArray } from 'base64-js';
import { fromByteArray, toByteArray } from "base64-js";
import { Protobuf } from '@meshtastic/meshtasticjs';
import Layout from '@theme/Layout';
import { Protobuf } from "@meshtastic/meshtasticjs";
import Layout from "@theme/Layout";
const OEM = (): JSX.Element => {
const [oemAesKey, setOemAesKey] = useState<Uint8Array>(new Uint8Array());
const [oemFont, setOemFont] = useState<Protobuf.ScreenFonts>(
Protobuf.ScreenFonts.FONT_MEDIUM,
Protobuf.ScreenFonts.FONT_MEDIUM
);
const [oemIconBits, setOemIconBits] = useState<Uint8Array>(new Uint8Array());
const [oemIconHeight, setOemIconHeight] = useState<number>(0);
const [oemIconWidth, setOemIconWidth] = useState<number>(0);
const [oemText, setOemText] = useState<string>('');
const [oemText, setOemText] = useState<string>("");
const [oemBytes, setOemBytes] = useState<Uint8Array>(new Uint8Array());
const encoder = new TextEncoder();
@ -26,14 +26,14 @@ const OEM = (): JSX.Element => {
oemIconBits,
oemIconHeight,
oemIconWidth,
oemText,
}),
oemText
})
);
}, [oemAesKey, oemFont, oemIconBits, oemIconHeight, oemIconWidth, oemText]);
const enumOptions = Protobuf.ScreenFonts
? Object.entries(Protobuf.ScreenFonts).filter(
(value) => typeof value[1] === 'number',
(value) => typeof value[1] === "number"
)
: [];
@ -102,8 +102,8 @@ const OEM = (): JSX.Element => {
readFile(e.target.files[0]).then((data) => {
setOemIconBits(
new Uint8Array(
data.split(',').map((s) => parseInt(s.trim(), 16)),
),
data.split(",").map((s) => parseInt(s.trim(), 16))
)
);
});
}}
@ -137,7 +137,7 @@ const OEM = (): JSX.Element => {
download="OEM.bin"
onClick={() => {
const blob = new Blob([oemBytes], {
type: 'application/octet-stream',
type: "application/octet-stream"
});
window.open(URL.createObjectURL(blob));
}}

View file

@ -1,12 +1,12 @@
import { Node } from './apiTypes.js';
import { Node } from "./apiTypes.js";
export const mapUrl = (nodes: Node[]): string => {
const width = 900;
const height = 400;
const access_token =
'pk.eyJ1Ijoic2FjaGF3IiwiYSI6ImNrNW9meXozZjBsdW0zbHBjM2FnNnV6cmsifQ.3E4n8eFGD9ZOFo-XDVeZnQ';
"pk.eyJ1Ijoic2FjaGF3IiwiYSI6ImNrNW9meXozZjBsdW0zbHBjM2FnNnV6cmsifQ.3E4n8eFGD9ZOFo-XDVeZnQ";
const nodeCoords = nodes.map(
({ latitude, longitude }) => `pin-l+67ea94(${longitude},${latitude})`,
({ latitude, longitude }) => `pin-l+67ea94(${longitude},${latitude})`
);
return `https://api.mapbox.com/styles/v1/mapbox/satellite-v9/static/${nodeCoords}/auto/${width}x${height}@2x?access_token=${access_token}`;

View file

@ -1,8 +1,7 @@
export const sortBy = <T>(array: T[], getter: (item: T) => unknown): T[] => {
const sortedArray = [...array];
sortedArray.sort((a, b) =>
// @ts-ignore
getter(a) > getter(b) ? 1 : getter(b) > getter(a) ? -1 : 0,
getter(a) > getter(b) ? 1 : getter(b) > getter(a) ? -1 : 0
);
return sortedArray;
};

View file

@ -1,20 +1,22 @@
// trunk-ignore(eslint/no-undef)
module.exports = {
content: ['./src/**/*.{js,jsx,ts,tsx}'],
darkMode: 'class',
content: ["./src/**/*.{js,jsx,ts,tsx}"],
darkMode: "class",
theme: {
extend: {
colors: {
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)',
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')],
// trunk-ignore(eslint/no-undef)
plugins: [require("@tailwindcss/typography")]
};