mirror of
https://github.com/meshtastic/meshtastic.git
synced 2024-11-13 17:14:25 -08:00
Hardwar page work
This commit is contained in:
parent
ebaa8951ff
commit
f89b477cbb
|
@ -15,11 +15,13 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@algolia/client-search": "^4.13.0",
|
"@algolia/client-search": "^4.13.0",
|
||||||
"@docusaurus/core": "^2.0.0-beta.18",
|
"@docusaurus/core": "^2.0.0-beta.18",
|
||||||
|
"@docusaurus/plugin-content-docs": "^2.0.0-beta.18",
|
||||||
"@docusaurus/preset-classic": "^2.0.0-beta.18",
|
"@docusaurus/preset-classic": "^2.0.0-beta.18",
|
||||||
"@headlessui/react": "^1.5.0",
|
"@headlessui/react": "^1.5.0",
|
||||||
"@mdx-js/react": "^1.6.22",
|
"@mdx-js/react": "^1.6.22",
|
||||||
"autoprefixer": "^10.4.4",
|
"autoprefixer": "^10.4.4",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
|
"framer-motion": "^6.2.8",
|
||||||
"postcss": "^8.4.12",
|
"postcss": "^8.4.12",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
@ -29,6 +31,7 @@
|
||||||
"swr": "^1.2.2",
|
"swr": "^1.2.2",
|
||||||
"tailwindcss": "^3.0.23",
|
"tailwindcss": "^3.0.23",
|
||||||
"url-search-params-polyfill": "^8.1.1",
|
"url-search-params-polyfill": "^8.1.1",
|
||||||
|
"use-breakpoint": "^3.0.2",
|
||||||
"victory": "^36.3.1"
|
"victory": "^36.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -4,6 +4,7 @@ specifiers:
|
||||||
'@algolia/client-search': ^4.13.0
|
'@algolia/client-search': ^4.13.0
|
||||||
'@docusaurus/core': ^2.0.0-beta.18
|
'@docusaurus/core': ^2.0.0-beta.18
|
||||||
'@docusaurus/module-type-aliases': ^2.0.0-beta.18
|
'@docusaurus/module-type-aliases': ^2.0.0-beta.18
|
||||||
|
'@docusaurus/plugin-content-docs': ^2.0.0-beta.18
|
||||||
'@docusaurus/preset-classic': ^2.0.0-beta.18
|
'@docusaurus/preset-classic': ^2.0.0-beta.18
|
||||||
'@headlessui/react': ^1.5.0
|
'@headlessui/react': ^1.5.0
|
||||||
'@mdx-js/react': ^1.6.22
|
'@mdx-js/react': ^1.6.22
|
||||||
|
@ -16,6 +17,7 @@ specifiers:
|
||||||
'@types/w3c-web-serial': ^1.0.2
|
'@types/w3c-web-serial': ^1.0.2
|
||||||
autoprefixer: ^10.4.4
|
autoprefixer: ^10.4.4
|
||||||
dotenv: ^16.0.0
|
dotenv: ^16.0.0
|
||||||
|
framer-motion: ^6.2.8
|
||||||
postcss: ^8.4.12
|
postcss: ^8.4.12
|
||||||
prettier: ^2.6.1
|
prettier: ^2.6.1
|
||||||
react: ^17.0.2
|
react: ^17.0.2
|
||||||
|
@ -27,16 +29,19 @@ specifiers:
|
||||||
tailwindcss: ^3.0.23
|
tailwindcss: ^3.0.23
|
||||||
typescript: ^4.6.3
|
typescript: ^4.6.3
|
||||||
url-search-params-polyfill: ^8.1.1
|
url-search-params-polyfill: ^8.1.1
|
||||||
|
use-breakpoint: ^3.0.2
|
||||||
victory: ^36.3.1
|
victory: ^36.3.1
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
'@algolia/client-search': 4.13.0
|
'@algolia/client-search': 4.13.0
|
||||||
'@docusaurus/core': 2.0.0-beta.18_28e7016540b0a32b5f8d7be755522ab7
|
'@docusaurus/core': 2.0.0-beta.18_28e7016540b0a32b5f8d7be755522ab7
|
||||||
|
'@docusaurus/plugin-content-docs': 2.0.0-beta.18_28e7016540b0a32b5f8d7be755522ab7
|
||||||
'@docusaurus/preset-classic': 2.0.0-beta.18_cd2ecee38e568e94b4890eebc445da58
|
'@docusaurus/preset-classic': 2.0.0-beta.18_cd2ecee38e568e94b4890eebc445da58
|
||||||
'@headlessui/react': 1.5.0_react-dom@17.0.2+react@17.0.2
|
'@headlessui/react': 1.5.0_react-dom@17.0.2+react@17.0.2
|
||||||
'@mdx-js/react': 1.6.22_react@17.0.2
|
'@mdx-js/react': 1.6.22_react@17.0.2
|
||||||
autoprefixer: 10.4.4_postcss@8.4.12
|
autoprefixer: 10.4.4_postcss@8.4.12
|
||||||
dotenv: 16.0.0
|
dotenv: 16.0.0
|
||||||
|
framer-motion: 6.2.8_react-dom@17.0.2+react@17.0.2
|
||||||
postcss: 8.4.12
|
postcss: 8.4.12
|
||||||
react: 17.0.2
|
react: 17.0.2
|
||||||
react-dom: 17.0.2_react@17.0.2
|
react-dom: 17.0.2_react@17.0.2
|
||||||
|
@ -46,6 +51,7 @@ dependencies:
|
||||||
swr: 1.2.2_react@17.0.2
|
swr: 1.2.2_react@17.0.2
|
||||||
tailwindcss: 3.0.23_autoprefixer@10.4.4
|
tailwindcss: 3.0.23_autoprefixer@10.4.4
|
||||||
url-search-params-polyfill: 8.1.1
|
url-search-params-polyfill: 8.1.1
|
||||||
|
use-breakpoint: 3.0.2_react-dom@17.0.2+react@17.0.2
|
||||||
victory: 36.3.1_react@17.0.2
|
victory: 36.3.1_react@17.0.2
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
@ -638,7 +644,7 @@ packages:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.12.9
|
'@babel/core': 7.12.9
|
||||||
'@babel/helper-plugin-utils': 7.10.4
|
'@babel/helper-plugin-utils': 7.16.7
|
||||||
'@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.12.9
|
'@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.12.9
|
||||||
'@babel/plugin-transform-parameters': 7.16.7_@babel+core@7.12.9
|
'@babel/plugin-transform-parameters': 7.16.7_@babel+core@7.12.9
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -2182,6 +2188,19 @@ packages:
|
||||||
- webpack-cli
|
- webpack-cli
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/is-prop-valid/0.8.8:
|
||||||
|
resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==}
|
||||||
|
requiresBuild: true
|
||||||
|
dependencies:
|
||||||
|
'@emotion/memoize': 0.7.4
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@emotion/memoize/0.7.4:
|
||||||
|
resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==}
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
/@eslint/eslintrc/1.2.1:
|
/@eslint/eslintrc/1.2.1:
|
||||||
resolution: {integrity: sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==}
|
resolution: {integrity: sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
|
@ -5182,6 +5201,29 @@ packages:
|
||||||
resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
|
resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/framer-motion/6.2.8_react-dom@17.0.2+react@17.0.2:
|
||||||
|
resolution: {integrity: sha512-4PtBWFJ6NqR350zYVt9AsFDtISTqsdqna79FvSYPfYDXuuqFmiKtZdkTnYPslnsOMedTW0pEvaQ7eqjD+sA+HA==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16.8 || ^17.0.0 || ^18.0.0'
|
||||||
|
react-dom: '>=16.8 || ^17.0.0 || ^18.0.0'
|
||||||
|
dependencies:
|
||||||
|
framesync: 6.0.1
|
||||||
|
hey-listen: 1.0.8
|
||||||
|
popmotion: 11.0.3
|
||||||
|
react: 17.0.2
|
||||||
|
react-dom: 17.0.2_react@17.0.2
|
||||||
|
style-value-types: 5.0.0
|
||||||
|
tslib: 2.3.1
|
||||||
|
optionalDependencies:
|
||||||
|
'@emotion/is-prop-valid': 0.8.8
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/framesync/6.0.1:
|
||||||
|
resolution: {integrity: sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==}
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.3.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/fresh/0.5.2:
|
/fresh/0.5.2:
|
||||||
resolution: {integrity: sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=}
|
resolution: {integrity: sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
@ -5519,6 +5561,10 @@ packages:
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/hey-listen/1.0.8:
|
||||||
|
resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/history/4.10.1:
|
/history/4.10.1:
|
||||||
resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==}
|
resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -6976,6 +7022,15 @@ packages:
|
||||||
find-up: 3.0.0
|
find-up: 3.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/popmotion/11.0.3:
|
||||||
|
resolution: {integrity: sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==}
|
||||||
|
dependencies:
|
||||||
|
framesync: 6.0.1
|
||||||
|
hey-listen: 1.0.8
|
||||||
|
style-value-types: 5.0.0
|
||||||
|
tslib: 2.3.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/portfinder/1.0.28:
|
/portfinder/1.0.28:
|
||||||
resolution: {integrity: sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==}
|
resolution: {integrity: sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==}
|
||||||
engines: {node: '>= 0.12.0'}
|
engines: {node: '>= 0.12.0'}
|
||||||
|
@ -8567,6 +8622,13 @@ packages:
|
||||||
inline-style-parser: 0.1.1
|
inline-style-parser: 0.1.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/style-value-types/5.0.0:
|
||||||
|
resolution: {integrity: sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==}
|
||||||
|
dependencies:
|
||||||
|
hey-listen: 1.0.8
|
||||||
|
tslib: 2.3.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/stylehacks/5.1.0_postcss@8.4.12:
|
/stylehacks/5.1.0_postcss@8.4.12:
|
||||||
resolution: {integrity: sha512-SzLmvHQTrIWfSgljkQCw2++C9+Ne91d/6Sp92I8c5uHTcy/PgeHamwITIbBW9wnFTY/3ZfSXR9HIL6Ikqmcu6Q==}
|
resolution: {integrity: sha512-SzLmvHQTrIWfSgljkQCw2++C9+Ne91d/6Sp92I8c5uHTcy/PgeHamwITIbBW9wnFTY/3ZfSXR9HIL6Ikqmcu6Q==}
|
||||||
engines: {node: ^10 || ^12 || >=14.0}
|
engines: {node: ^10 || ^12 || >=14.0}
|
||||||
|
@ -9005,6 +9067,17 @@ packages:
|
||||||
resolution: {integrity: sha512-KmkCs6SjE6t4ihrfW9JelAPQIIIFbJweaaSLTh/4AO+c58JlDcb+GbdPt8yr5lRcFg4rPswRFRRhBGpWwh0K/Q==}
|
resolution: {integrity: sha512-KmkCs6SjE6t4ihrfW9JelAPQIIIFbJweaaSLTh/4AO+c58JlDcb+GbdPt8yr5lRcFg4rPswRFRRhBGpWwh0K/Q==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/use-breakpoint/3.0.2_react-dom@17.0.2+react@17.0.2:
|
||||||
|
resolution: {integrity: sha512-O7qfp6QOOQI3CqLnJg6e5TgV2lSuLv3jQT48RAtScYTPbYjuGogPDQUS+Bz/MC0ZCYdZge262rKBi+jgZgCSHw==}
|
||||||
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16.8'
|
||||||
|
react-dom: '>=16.8'
|
||||||
|
dependencies:
|
||||||
|
react: 17.0.2
|
||||||
|
react-dom: 17.0.2_react@17.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/use-composed-ref/1.2.1_react@17.0.2:
|
/use-composed-ref/1.2.1_react@17.0.2:
|
||||||
resolution: {integrity: sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw==}
|
resolution: {integrity: sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
16
src/components/Button.tsx
Normal file
16
src/components/Button.tsx
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { HTMLMotionProps, motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export const Button = ({ children, ...props }: HTMLMotionProps<'div'>) => {
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
{...props}
|
||||||
|
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"
|
||||||
|
>
|
||||||
|
<div className="m-auto">{children}</div>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,6 +1,8 @@
|
||||||
import React, { Fragment } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Dialog, Transition } from '@headlessui/react';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
|
|
||||||
|
import { Dialog } from '@headlessui/react';
|
||||||
|
|
||||||
export interface ModalProps {
|
export interface ModalProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
@ -10,45 +12,38 @@ export interface ModalProps {
|
||||||
|
|
||||||
export const Modal = ({ open, onClose, children }: ModalProps): JSX.Element => {
|
export const Modal = ({ open, onClose, children }: ModalProps): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<Transition appear show={open} as={Fragment}>
|
<AnimatePresence initial={false} exitBeforeEnter={true}>
|
||||||
<Dialog
|
<Dialog
|
||||||
as="div"
|
as="div"
|
||||||
className="fixed inset-0 z-10 overflow-y-auto"
|
className="fixed inset-0 z-10 overflow-y-auto"
|
||||||
|
open={open}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
>
|
>
|
||||||
<div className="min-h-screen px-4 text-center">
|
<div className="min-h-screen px-4 text-center">
|
||||||
<Transition.Child
|
<motion.div
|
||||||
as={Fragment}
|
initial={{ opacity: 0 }}
|
||||||
enter="ease-out duration-100"
|
animate={{ opacity: 1 }}
|
||||||
enterFrom="opacity-0"
|
exit={{ opacity: 0 }}
|
||||||
enterTo="opacity-100"
|
|
||||||
leave="ease-in duration-100"
|
|
||||||
leaveFrom="opacity-100"
|
|
||||||
leaveTo="opacity-0"
|
|
||||||
>
|
>
|
||||||
<Dialog.Overlay className="fixed inset-0 backdrop-blur-md" />
|
<Dialog.Overlay className="fixed inset-0 backdrop-blur-md" />
|
||||||
</Transition.Child>
|
</motion.div>
|
||||||
|
|
||||||
{/* This element is to trick the browser into centering the modal contents. */}
|
|
||||||
<span
|
<span
|
||||||
className="inline-block h-screen align-middle"
|
className="inline-block h-screen align-middle"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
>
|
||||||
​
|
​
|
||||||
</span>
|
</span>
|
||||||
<Transition.Child
|
<div className="inline-block w-full transform text-left align-middle transition-all 2xl:max-w-7xl">
|
||||||
as={Fragment}
|
<div className="group relative">
|
||||||
enter="ease-out duration-100"
|
<div className="animate-tilt absolute -inset-0.5 rotate-2 rounded-lg bg-accent shadow-md transition duration-1000 group-hover:opacity-100 group-hover:duration-200"></div>
|
||||||
enterFrom="opacity-0 scale-95"
|
<div className="relative flex aspect-[3/2] flex-col overflow-hidden rounded-2xl bg-base shadow-md md:aspect-[2/1] md:flex-row md:bg-primary">
|
||||||
enterTo="opacity-100 scale-100"
|
|
||||||
leave="ease-in duration-200"
|
|
||||||
leaveFrom="opacity-100 scale-100"
|
|
||||||
leaveTo="opacity-0 scale-95"
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</Transition.Child>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Transition>
|
</AnimatePresence>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { IDevice, Stability } from '@site/src/data/device';
|
import { IDevice, Stability } from '@site/src/data/device';
|
||||||
|
|
||||||
import { HardwareModal } from './HardwareModal';
|
|
||||||
|
|
||||||
export interface HardwareCardProps {
|
export interface HardwareCardProps {
|
||||||
device: IDevice;
|
device: IDevice;
|
||||||
|
setDevice: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HardwareCard = ({ device }: HardwareCardProps): JSX.Element => {
|
export const HardwareCard = ({
|
||||||
const [open, setOpen] = useState(false);
|
device,
|
||||||
|
setDevice,
|
||||||
|
}: HardwareCardProps): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<li
|
<li
|
||||||
className="group relative"
|
className="group relative"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpen(true);
|
setDevice();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="overflow-hidden rounded-lg">
|
<div className="overflow-hidden rounded-lg">
|
||||||
|
@ -24,7 +23,7 @@ export const HardwareCard = ({ device }: HardwareCardProps): JSX.Element => {
|
||||||
className={`flex aspect-[4/3] overflow-hidden ${device.misc.Gradient}`}
|
className={`flex aspect-[4/3] overflow-hidden ${device.misc.Gradient}`}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={device.misc.ImagePath}
|
src={device.images.Front}
|
||||||
alt=""
|
alt=""
|
||||||
className="pointer-events-none m-auto max-h-full max-w-full object-cover p-2 group-hover:opacity-75"
|
className="pointer-events-none m-auto max-h-full max-w-full object-cover p-2 group-hover:opacity-75"
|
||||||
/>
|
/>
|
||||||
|
@ -55,13 +54,5 @@ export const HardwareCard = ({ device }: HardwareCardProps): JSX.Element => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<HardwareModal
|
|
||||||
open={open}
|
|
||||||
close={() => {
|
|
||||||
setOpen(false);
|
|
||||||
}}
|
|
||||||
device={device}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
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 { FiBluetooth, FiChevronRight, FiWifi, FiX } from 'react-icons/fi';
|
||||||
|
import { useBreakpoint } from 'use-breakpoint';
|
||||||
|
|
||||||
import { Tab, Transition } from '@headlessui/react';
|
import { Tab } from '@headlessui/react';
|
||||||
import type { IDevice } from '@site/src/data/device';
|
import type { IDevice } from '@site/src/data/device';
|
||||||
|
|
||||||
|
import { Button } from '../../components/Button';
|
||||||
|
import { BREAKPOINTS } from '../../utils/breakpoints';
|
||||||
import { Modal } from '../Modal';
|
import { Modal } from '../Modal';
|
||||||
import { Badge } from './Badge';
|
import { Badge } from './Badge';
|
||||||
import { CardTab } from './CardTab';
|
import { CardTab } from './CardTab';
|
||||||
|
@ -24,41 +28,71 @@ export const HardwareModal = ({
|
||||||
open,
|
open,
|
||||||
close,
|
close,
|
||||||
}: HardwareModal): JSX.Element => {
|
}: HardwareModal): JSX.Element => {
|
||||||
const colors = ['#428517', '#77D200', '#D6D305', '#EC8E19', '#C92B05'];
|
|
||||||
const [hideDetails, setHideDetails] = useState(false);
|
const [hideDetails, setHideDetails] = useState(false);
|
||||||
|
const { breakpoint } = useBreakpoint(BREAKPOINTS);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal open={open} onClose={close}>
|
<Modal open={open} onClose={close}>
|
||||||
<div className="inline-block w-full max-w-md transform overflow-hidden rounded-2xl bg-base text-left align-middle transition-all md:max-w-2xl md:bg-primary lg:max-w-4xl xl:max-w-6xl">
|
<div className="absolute right-0 z-20 m-2 md:flex">
|
||||||
<div className="flex aspect-[3/2] flex-col md:aspect-[2/1] md:flex-row">
|
<Button onClick={close}>
|
||||||
<div
|
<FiX />
|
||||||
className={`relative flex h-full rounded-t-2xl md:rounded-l-2xl md:rounded-tr-none ${
|
</Button>
|
||||||
device.misc.Gradient
|
</div>
|
||||||
} ${hideDetails ? 'w-full' : ''}`}
|
<motion.div
|
||||||
|
layout
|
||||||
|
animate={hideDetails ? 'hidden' : 'visible'}
|
||||||
|
variants={{
|
||||||
|
hidden: breakpoint === 'sm' ? { height: '100%' } : { width: '100%' },
|
||||||
|
visible: breakpoint === 'sm' ? { height: '25%' } : { width: '20%' },
|
||||||
|
}}
|
||||||
|
transition={{
|
||||||
|
type: 'just',
|
||||||
|
}}
|
||||||
|
className="absolute inset-0 flex flex-col md:h-full md:flex-row"
|
||||||
>
|
>
|
||||||
<img
|
<motion.div
|
||||||
src={device.misc.ImagePath}
|
layout
|
||||||
|
className={`relative z-10 flex h-full w-full rounded-t-2xl md:rounded-l-2xl md:rounded-tr-none ${device.misc.Gradient}`}
|
||||||
|
>
|
||||||
|
<motion.img
|
||||||
|
layout
|
||||||
|
src={device.images.Front}
|
||||||
alt=""
|
alt=""
|
||||||
className="pointer-events-none m-auto object-cover p-2 group-hover:opacity-75"
|
className="pointer-events-none m-auto max-h-full max-w-full object-cover p-2"
|
||||||
/>
|
/>
|
||||||
<div className="absolute -bottom-4 flex w-full md:bottom-auto md:-right-4 md:h-full md:w-auto ">
|
<div className="absolute -bottom-5 z-20 flex w-full md:bottom-auto md:-right-5 md:h-full md:w-auto">
|
||||||
<div
|
<Button
|
||||||
|
animate={hideDetails ? 'hidden' : 'visible'}
|
||||||
|
variants={{
|
||||||
|
hidden: breakpoint === 'sm' ? { rotate: -90 } : { rotate: 180 },
|
||||||
|
visible: breakpoint === 'sm' ? { rotate: 90 } : { rotate: 0 },
|
||||||
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setHideDetails(!hideDetails);
|
setHideDetails(!hideDetails);
|
||||||
}}
|
}}
|
||||||
className="m-auto flex cursor-pointer rounded-full bg-secondary p-2 shadow-md hover:bg-tertiary"
|
|
||||||
>
|
>
|
||||||
<FiChevronRight
|
<FiChevronRight />
|
||||||
className={`m-auto ${
|
</Button>
|
||||||
hideDetails
|
|
||||||
? 'rotate-90 md:rotate-180'
|
|
||||||
: '-rotate-90 md:rotate-0'
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<AnimatePresence>
|
||||||
{!hideDetails && (
|
{!hideDetails && (
|
||||||
<div className="absolute -bottom-3 right-0 m-auto mr-2 ml-auto flex gap-2 md:bottom-2 md:mr-14 md:mt-2">
|
<>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
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'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<VariantSelectButton options={device.variants} />
|
||||||
|
</motion.div>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
className="absolute -bottom-3 right-0 m-auto mr-2 ml-auto flex gap-2 md:bottom-2 md:mr-14 md:mt-2"
|
||||||
|
>
|
||||||
{device.features.BLE && (
|
{device.features.BLE && (
|
||||||
<Badge
|
<Badge
|
||||||
name="Bluetooth"
|
name="Bluetooth"
|
||||||
|
@ -67,60 +101,48 @@ export const HardwareModal = ({
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{device.features.WiFi && (
|
{device.features.WiFi && (
|
||||||
<Badge name="WiFi" color="bg-orange-500" icon={<FiWifi />} />
|
<Badge
|
||||||
|
name="WiFi"
|
||||||
|
color="bg-orange-500"
|
||||||
|
icon={<FiWifi />}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</motion.div>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</AnimatePresence>
|
||||||
|
</motion.div>
|
||||||
<div
|
<div
|
||||||
className="absolute right-0 mr-2 flex cursor-pointer rounded-b-full bg-secondary p-3 shadow-md hover:bg-tertiary md:mt-2 md:rounded-full"
|
className={`h-7 bg-base opacity-0 md:h-auto md:w-7 ${
|
||||||
onClick={close}
|
hideDetails ? 'flex' : 'hidden'
|
||||||
>
|
|
||||||
<FiX className="m-auto" />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`transition-[all] duration-100 ease-linear ${
|
|
||||||
hideDetails ? 'h-7 bg-base md:h-auto md:w-7' : 'w-full'
|
|
||||||
}`}
|
}`}
|
||||||
>
|
/>
|
||||||
<Transition
|
</motion.div>
|
||||||
appear
|
<div className="mt-[25%] flex h-full flex-col md:ml-[20%] md:mt-0 md:w-4/5">
|
||||||
as={'div'}
|
<div className="z-0 hidden pb-2 md:flex">
|
||||||
className="flex h-full flex-col"
|
|
||||||
show={!hideDetails}
|
|
||||||
enter="ease-out duration-100 delay-100"
|
|
||||||
enterFrom="opacity-0"
|
|
||||||
enterTo="opacity-100"
|
|
||||||
leave="ease-in duration-100 delay-100"
|
|
||||||
leaveFrom="opacity-100"
|
|
||||||
leaveTo="opacity-0"
|
|
||||||
>
|
|
||||||
<>
|
|
||||||
<div className="flex shadow-md md:pb-2">
|
|
||||||
<VariantSelectButton options={device.variants} />
|
<VariantSelectButton options={device.variants} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex h-full bg-base p-2 md:p-4">
|
<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'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<Tab.Group
|
<Tab.Group
|
||||||
as="div"
|
as="div"
|
||||||
className="flex-grow rounded-2xl bg-primary p-2"
|
className="flex flex-grow flex-col rounded-2xl bg-primary p-2"
|
||||||
>
|
>
|
||||||
<Tab.List className="flex gap-2">
|
<Tab.List className="flex gap-2">
|
||||||
<CardTab title="Info" />
|
<CardTab title="Info" />
|
||||||
<CardTab title="Power" />
|
<CardTab title="Power" />
|
||||||
<CardTab title="Pinout" />
|
<CardTab title="Pinout" />
|
||||||
</Tab.List>
|
</Tab.List>
|
||||||
<Tab.Panels as="div" className="">
|
<Tab.Panels as="div" className="flex-grow overflow-y-auto">
|
||||||
<InfoTab device={device} />
|
<InfoTab device={device} />
|
||||||
<PowerTab device={device} />
|
<PowerTab device={device} />
|
||||||
<PinoutTab device={device} />
|
<PinoutTab device={device} />
|
||||||
</Tab.Panels>
|
</Tab.Panels>
|
||||||
</Tab.Group>
|
</Tab.Group>
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
</Transition>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,5 +9,40 @@ export interface InfoTabProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const InfoTab = ({ device }: InfoTabProps): JSX.Element => {
|
export const InfoTab = ({ device }: InfoTabProps): JSX.Element => {
|
||||||
return <Tab.Panel className="h-32">Content 1</Tab.Panel>;
|
return (
|
||||||
|
<Tab.Panel>
|
||||||
|
<div className="px-4 py-5 sm:p-0">
|
||||||
|
<dl className="sm:divide-y sm:divide-gray-200">
|
||||||
|
<div className="py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-5 sm:px-6">
|
||||||
|
<dt className="text-sm font-medium text-secondaryInv">
|
||||||
|
BLE/WiFi Version
|
||||||
|
</dt>
|
||||||
|
<dd className="mt-1 flex gap-1 text-sm text-tertiaryInv sm:col-span-2 sm:mt-0">
|
||||||
|
<span className="rounded-md bg-secondary px-0.5">
|
||||||
|
{device.specifications.BLEVersion}
|
||||||
|
</span>
|
||||||
|
/
|
||||||
|
<span className="rounded-md bg-secondary px-0.5">
|
||||||
|
{device.specifications.WiFiVersion}
|
||||||
|
</span>
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div className="py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-5 sm:px-6">
|
||||||
|
<dt className="text-sm font-medium text-secondaryInv">
|
||||||
|
BLE/WiFi Antenna
|
||||||
|
</dt>
|
||||||
|
<dd className="mt-1 flex gap-1 text-sm text-tertiaryInv sm:col-span-2 sm:mt-0">
|
||||||
|
<span className="rounded-md bg-secondary px-0.5">
|
||||||
|
{device.specifications.BLEAntenna}
|
||||||
|
</span>
|
||||||
|
/
|
||||||
|
<span className="rounded-md bg-secondary px-0.5">
|
||||||
|
{device.specifications.WiFiAntenna}
|
||||||
|
</span>
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</Tab.Panel>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { Fragment, useState } from 'react';
|
import React, { Fragment, useState } from 'react';
|
||||||
|
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
import { FiCheck } from 'react-icons/fi';
|
import { FiCheck } from 'react-icons/fi';
|
||||||
import { HiSelector } from 'react-icons/hi';
|
import { HiSelector } from 'react-icons/hi';
|
||||||
|
|
||||||
|
@ -19,8 +20,13 @@ export const VariantSelectButton = ({
|
||||||
<Listbox value={selected} onChange={setSelected}>
|
<Listbox value={selected} onChange={setSelected}>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<>
|
<>
|
||||||
<div className="relative">
|
<div className="relative select-none">
|
||||||
<Listbox.Button className="relative -mt-5 ml-2 flex w-fit gap-1 rounded-lg bg-secondary p-2 py-2 pl-3 pr-10 text-lg font-medium leading-6 shadow-md hover:bg-tertiary md:mt-2">
|
<Listbox.Button as={Fragment}>
|
||||||
|
<motion.button
|
||||||
|
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"
|
||||||
|
>
|
||||||
<span className="block truncate">{selected.name}</span>
|
<span className="block truncate">{selected.name}</span>
|
||||||
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||||
<HiSelector
|
<HiSelector
|
||||||
|
@ -28,6 +34,7 @@ export const VariantSelectButton = ({
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
</motion.button>
|
||||||
</Listbox.Button>
|
</Listbox.Button>
|
||||||
|
|
||||||
<Transition
|
<Transition
|
||||||
|
@ -37,7 +44,7 @@ export const VariantSelectButton = ({
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<Listbox.Options className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-primary py-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
|
<Listbox.Options className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-primary py-1 shadow-md ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
|
||||||
{options.map((variant, index) => (
|
{options.map((variant, index) => (
|
||||||
<Listbox.Option
|
<Listbox.Option
|
||||||
key={index}
|
key={index}
|
||||||
|
|
|
@ -19,8 +19,9 @@ export const SocialCard = ({
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<a
|
<a
|
||||||
className="absolute top-0 left-0 right-0 bottom-0 hidden rounded-xl border border-accent bg-secondaryDark bg-opacity-95 text-2xl shadow-xl group-hover:flex"
|
className="absolute top-0 left-0 right-0 bottom-0 hidden rounded-xl border border-accent bg-secondary bg-opacity-95 text-2xl shadow-xl group-hover:flex"
|
||||||
href={link}
|
href={link}
|
||||||
|
rel="noreferrer"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<FiExternalLink className="m-auto" />
|
<FiExternalLink className="m-auto" />
|
||||||
|
|
|
@ -48,9 +48,12 @@ export interface IDevice {
|
||||||
misc: {
|
misc: {
|
||||||
SuggestedUse: UseCase[];
|
SuggestedUse: UseCase[];
|
||||||
Stability: Stability;
|
Stability: Stability;
|
||||||
ImagePath: string;
|
|
||||||
Gradient: string;
|
Gradient: string;
|
||||||
};
|
};
|
||||||
|
images: {
|
||||||
|
Front: string;
|
||||||
|
Back: string;
|
||||||
|
};
|
||||||
features: {
|
features: {
|
||||||
BLE: boolean;
|
BLE: boolean;
|
||||||
WiFi: boolean;
|
WiFi: boolean;
|
||||||
|
|
|
@ -5,8 +5,11 @@ export const heltec: IDevice = {
|
||||||
misc: {
|
misc: {
|
||||||
Stability: Stability.Unstable,
|
Stability: Stability.Unstable,
|
||||||
SuggestedUse: [UseCase.Portable],
|
SuggestedUse: [UseCase.Portable],
|
||||||
ImagePath: '/img/hardware/heltec-v2.png',
|
Gradient: 'bg-gradient-to-r from-pink-300 via-purple-300 to-indigo-400',
|
||||||
Gradient: 'from-pink-300 via-purple-300 to-indigo-400',
|
},
|
||||||
|
images: {
|
||||||
|
Front: '/img/hardware/heltec-v2.png',
|
||||||
|
Back: '',
|
||||||
},
|
},
|
||||||
features: {
|
features: {
|
||||||
BLE: true,
|
BLE: true,
|
||||||
|
|
|
@ -5,9 +5,12 @@ export const hydra: IDevice = {
|
||||||
misc: {
|
misc: {
|
||||||
Stability: Stability.Stable,
|
Stability: Stability.Stable,
|
||||||
SuggestedUse: [UseCase.Portable],
|
SuggestedUse: [UseCase.Portable],
|
||||||
ImagePath: '/img/hardware/Hydra-PCB.2.1.svg',
|
|
||||||
Gradient: 'bg-gradient-to-r from-indigo-200 via-red-200 to-yellow-100',
|
Gradient: 'bg-gradient-to-r from-indigo-200 via-red-200 to-yellow-100',
|
||||||
},
|
},
|
||||||
|
images: {
|
||||||
|
Front: '/img/hardware/Hydra-PCB.2.1.svg',
|
||||||
|
Back: '',
|
||||||
|
},
|
||||||
features: {
|
features: {
|
||||||
BLE: true,
|
BLE: true,
|
||||||
WiFi: true,
|
WiFi: true,
|
||||||
|
|
66
src/data/devices/nano_g1.ts
Normal file
66
src/data/devices/nano_g1.ts
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import { IDevice, Stability, UseCase } from '../device';
|
||||||
|
|
||||||
|
export const nano_g1: IDevice = {
|
||||||
|
name: 'Nano G1',
|
||||||
|
misc: {
|
||||||
|
Stability: Stability.Unstable,
|
||||||
|
SuggestedUse: [UseCase.Portable],
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
features: {
|
||||||
|
BLE: true,
|
||||||
|
WiFi: true,
|
||||||
|
Modules: [
|
||||||
|
'cannedMessage',
|
||||||
|
'externalNotification',
|
||||||
|
'rangeTest',
|
||||||
|
'rotaryEncoder',
|
||||||
|
'storeAndForward',
|
||||||
|
'telemetry',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
specifications: {
|
||||||
|
BLEVersion: '4.2',
|
||||||
|
BLEAntenna: 'Integrated',
|
||||||
|
WiFiVersion: '2.4GHz 802.11 b/g/n WPA/WPA2/WPA2-Enterprise/SPS',
|
||||||
|
WiFiAntenna: 'Integrated',
|
||||||
|
Chipset: 'ESP32',
|
||||||
|
Driver: 'CH9102',
|
||||||
|
GNSS: 'NEO-6M',
|
||||||
|
FlashSize: 4,
|
||||||
|
Frequencies: [433, 868, 915, 923],
|
||||||
|
LoRa: 'SX1262',
|
||||||
|
PSRAM: 8,
|
||||||
|
RAM: undefined,
|
||||||
|
},
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
name: 'TBeam 0.7',
|
||||||
|
misc: {
|
||||||
|
Stability: Stability.Unstable,
|
||||||
|
},
|
||||||
|
specifications: {
|
||||||
|
Driver: 'CP210X',
|
||||||
|
GNSS: 'NEO-6M',
|
||||||
|
Frequencies: [868, 915],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'TBeam 1.0',
|
||||||
|
specifications: {
|
||||||
|
Frequencies: [868, 915],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'TBeam 1.1',
|
||||||
|
specifications: {
|
||||||
|
Driver: 'CP210X',
|
||||||
|
GNSS: 'NEO-6M',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
66
src/data/devices/rak19001.ts
Normal file
66
src/data/devices/rak19001.ts
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import { IDevice, Stability, UseCase } from '../device';
|
||||||
|
|
||||||
|
export const rak19001: IDevice = {
|
||||||
|
name: 'WisBlock 19001',
|
||||||
|
misc: {
|
||||||
|
Stability: Stability.Stable,
|
||||||
|
SuggestedUse: [UseCase.Portable],
|
||||||
|
Gradient: 'bg-gradient-to-r from-indigo-300 to-purple-400',
|
||||||
|
},
|
||||||
|
images: {
|
||||||
|
Front: '/img/hardware/rak/RAK19001.png',
|
||||||
|
Back: '',
|
||||||
|
},
|
||||||
|
features: {
|
||||||
|
BLE: true,
|
||||||
|
WiFi: true,
|
||||||
|
Modules: [
|
||||||
|
'cannedMessage',
|
||||||
|
'externalNotification',
|
||||||
|
'rangeTest',
|
||||||
|
'rotaryEncoder',
|
||||||
|
'storeAndForward',
|
||||||
|
'telemetry',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
specifications: {
|
||||||
|
BLEVersion: '4.2',
|
||||||
|
BLEAntenna: 'Integrated',
|
||||||
|
WiFiVersion: '2.4GHz 802.11 b/g/n WPA/WPA2/WPA2-Enterprise/SPS',
|
||||||
|
WiFiAntenna: 'Integrated',
|
||||||
|
Chipset: 'ESP32',
|
||||||
|
Driver: 'CH9102',
|
||||||
|
GNSS: 'NEO-6M',
|
||||||
|
FlashSize: 4,
|
||||||
|
Frequencies: [433, 868, 915, 923],
|
||||||
|
LoRa: 'SX1262',
|
||||||
|
PSRAM: 8,
|
||||||
|
RAM: undefined,
|
||||||
|
},
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
name: 'TBeam 0.7',
|
||||||
|
misc: {
|
||||||
|
Stability: Stability.Unstable,
|
||||||
|
},
|
||||||
|
specifications: {
|
||||||
|
Driver: 'CP210X',
|
||||||
|
GNSS: 'NEO-6M',
|
||||||
|
Frequencies: [868, 915],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'TBeam 1.0',
|
||||||
|
specifications: {
|
||||||
|
Frequencies: [868, 915],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'TBeam 1.1',
|
||||||
|
specifications: {
|
||||||
|
Driver: 'CP210X',
|
||||||
|
GNSS: 'NEO-6M',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
|
@ -5,9 +5,12 @@ export const rak19003: IDevice = {
|
||||||
misc: {
|
misc: {
|
||||||
Stability: Stability.Stable,
|
Stability: Stability.Stable,
|
||||||
SuggestedUse: [UseCase.Portable],
|
SuggestedUse: [UseCase.Portable],
|
||||||
ImagePath: '/img/hardware/rak/RAK19003.png',
|
|
||||||
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: '',
|
||||||
|
},
|
||||||
features: {
|
features: {
|
||||||
BLE: true,
|
BLE: true,
|
||||||
WiFi: true,
|
WiFi: true,
|
||||||
|
|
|
@ -5,9 +5,12 @@ export const tbeam: IDevice = {
|
||||||
misc: {
|
misc: {
|
||||||
Stability: Stability.Stable,
|
Stability: Stability.Stable,
|
||||||
SuggestedUse: [UseCase.Portable],
|
SuggestedUse: [UseCase.Portable],
|
||||||
ImagePath: '/img/hardware/tbeam-v1.1.svg',
|
|
||||||
Gradient: 'bg-gradient-to-r from-pink-500 via-red-500 to-yellow-500',
|
Gradient: 'bg-gradient-to-r from-pink-500 via-red-500 to-yellow-500',
|
||||||
},
|
},
|
||||||
|
images: {
|
||||||
|
Front: '/img/hardware/tbeam-v1.1.svg',
|
||||||
|
Back: '',
|
||||||
|
},
|
||||||
features: {
|
features: {
|
||||||
BLE: true,
|
BLE: true,
|
||||||
WiFi: true,
|
WiFi: true,
|
||||||
|
|
|
@ -5,8 +5,11 @@ export const techo: IDevice = {
|
||||||
misc: {
|
misc: {
|
||||||
Stability: Stability.Semi,
|
Stability: Stability.Semi,
|
||||||
SuggestedUse: [UseCase.Portable],
|
SuggestedUse: [UseCase.Portable],
|
||||||
ImagePath: '/img/hardware/t-echo-lilygo.jpg',
|
Gradient: 'bg-gradient-to-r from-gray-700 via-gray-900 to-black',
|
||||||
Gradient: 'from-gray-700 via-gray-900 to-black',
|
},
|
||||||
|
images: {
|
||||||
|
Front: '/img/hardware/t-echo-lilygo.jpg',
|
||||||
|
Back: '',
|
||||||
},
|
},
|
||||||
features: {
|
features: {
|
||||||
BLE: true,
|
BLE: true,
|
||||||
|
|
|
@ -1,28 +1,23 @@
|
||||||
import React 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 { HardwareCard } from '../../components/hardware/HardwareCard';
|
import { HardwareCard } from '../../components/hardware/HardwareCard';
|
||||||
import { PageLayout } from '../../components/PageLayout';
|
import { PageLayout } from '../../components/PageLayout';
|
||||||
import { heltec } from '../../data/devices/heltec';
|
import { heltec } from '../../data/devices/heltec';
|
||||||
import { hydra } from '../../data/devices/hydra';
|
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 { rak19003 } from '../../data/devices/rak19003';
|
||||||
import { tbeam } from '../../data/devices/tbeam';
|
import { tbeam } from '../../data/devices/tbeam';
|
||||||
import { techo } from '../../data/devices/techo';
|
import { techo } from '../../data/devices/techo';
|
||||||
|
|
||||||
const Hardware = (): JSX.Element => {
|
const Hardware = (): JSX.Element => {
|
||||||
const hardware = [
|
const hardware = [tbeam, hydra, rak19003, rak19001, nano_g1, heltec, techo];
|
||||||
tbeam,
|
const [modalData, setModalData] = useState<IDevice>();
|
||||||
hydra,
|
|
||||||
rak19003,
|
|
||||||
heltec,
|
|
||||||
techo,
|
|
||||||
rak19003,
|
|
||||||
rak19003,
|
|
||||||
rak19003,
|
|
||||||
rak19003,
|
|
||||||
rak19003,
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageLayout title="Hardware" description="Supported hardware">
|
<PageLayout title="Hardware" description="Supported hardware">
|
||||||
|
@ -57,7 +52,13 @@ const Hardware = (): JSX.Element => {
|
||||||
className="grid grid-cols-2 gap-x-2 gap-y-4 sm:grid-cols-3 sm:gap-x-6 lg:grid-cols-4 xl:grid-cols-5 xl:gap-x-4"
|
className="grid grid-cols-2 gap-x-2 gap-y-4 sm:grid-cols-3 sm:gap-x-6 lg:grid-cols-4 xl:grid-cols-5 xl:gap-x-4"
|
||||||
>
|
>
|
||||||
{hardware.map((device, index) => (
|
{hardware.map((device, index) => (
|
||||||
<HardwareCard key={index} device={device} />
|
<HardwareCard
|
||||||
|
key={index}
|
||||||
|
device={device}
|
||||||
|
setDevice={(): void => {
|
||||||
|
setModalData(device);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
<li className="group relative">
|
<li className="group relative">
|
||||||
<a
|
<a
|
||||||
|
@ -77,6 +78,15 @@ const Hardware = (): JSX.Element => {
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
{modalData && (
|
||||||
|
<HardwareModal
|
||||||
|
open={!!modalData}
|
||||||
|
close={() => {
|
||||||
|
setModalData(undefined);
|
||||||
|
}}
|
||||||
|
device={modalData}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
1
src/utils/breakpoints.ts
Normal file
1
src/utils/breakpoints.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const BREAKPOINTS = { sm: 640, md: 768, lg: 1024, xl: 1280 };
|
77
static/img/hardware/nano_g1_back.svg
Normal file
77
static/img/hardware/nano_g1_back.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 16 KiB |
77
static/img/hardware/nano_g1_front.svg
Normal file
77
static/img/hardware/nano_g1_front.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 473 KiB |
BIN
static/img/hardware/rak/RAK19001.png
Normal file
BIN
static/img/hardware/rak/RAK19001.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 177 KiB |
BIN
static/img/hardware/rak/RAK19007.png
Normal file
BIN
static/img/hardware/rak/RAK19007.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 156 KiB |
Loading…
Reference in a new issue