19 changed files with 105 additions and 255 deletions
@ -2,7 +2,7 @@ lockfileVersion: 5.3 |
|||
|
|||
specifiers: |
|||
'@headlessui/react': ^1.4.2 |
|||
'@meshtastic/meshtasticjs': ^0.6.24 |
|||
'@meshtastic/meshtasticjs': ^0.6.25 |
|||
'@reduxjs/toolkit': ^1.6.2 |
|||
'@snowpack/plugin-dotenv': ^2.2.0 |
|||
'@snowpack/plugin-postcss': ^1.4.3 |
|||
@ -39,7 +39,6 @@ specifiers: |
|||
react-apexcharts: ^1.3.9 |
|||
react-dom: ^17.0.2 |
|||
react-file-icon: ^1.1.0 |
|||
react-flags-select: ^2.1.2 |
|||
react-hook-form: ^7.19.1 |
|||
react-i18next: ^11.13.0 |
|||
react-icons: ^4.3.1 |
|||
@ -54,7 +53,7 @@ specifiers: |
|||
|
|||
dependencies: |
|||
'@headlessui/react': 1.4[email protected][email protected] |
|||
'@meshtastic/meshtasticjs': 0.6.24 |
|||
'@meshtastic/meshtasticjs': 0.6.25 |
|||
'@reduxjs/toolkit': 1.6[email protected][email protected] |
|||
apexcharts: 3.29.0 |
|||
boring-avatars: 1.5.8 |
|||
@ -65,7 +64,6 @@ dependencies: |
|||
react-apexcharts: 1.3[email protected][email protected] |
|||
react-dom: 17.0[email protected] |
|||
react-file-icon: 1.1[email protected][email protected] |
|||
react-flags-select: 2.1[email protected][email protected] |
|||
react-hook-form: 7.19[email protected] |
|||
react-i18next: 11.13[email protected][email protected] |
|||
react-icons: 4.3[email protected] |
|||
@ -426,8 +424,8 @@ packages: |
|||
resolution: {integrity: sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==} |
|||
dev: true |
|||
|
|||
/@meshtastic/meshtasticjs/0.6.24: |
|||
resolution: {integrity: sha512-zdIxyIL6a+UUgZdZvxeRhK/xVhLYB0ZeB5OuA9peRFVE/ICHmAhkmNb58G1hDr0Lq3mPtmlsnh0DiPkI5O4TnQ==} |
|||
/@meshtastic/meshtasticjs/0.6.25: |
|||
resolution: {integrity: sha512-/FVmKIFpzSo2xguJ0+HfnpN9/6TS3ReMOXL29U7CsPnqGwePC3JJd3THNn2+ofOa//Iy7xGTYah0nF+LH1znJQ==} |
|||
dependencies: |
|||
'@protobuf-ts/runtime': 2.0.7 |
|||
node-fetch: 3.1.0 |
|||
@ -1582,10 +1580,6 @@ packages: |
|||
resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} |
|||
dev: true |
|||
|
|||
/classnames/2.3.1: |
|||
resolution: {integrity: sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==} |
|||
dev: false |
|||
|
|||
/clean-stack/2.2.0: |
|||
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} |
|||
engines: {node: '>=6'} |
|||
@ -4466,17 +4460,6 @@ packages: |
|||
tinycolor2: 1.4.2 |
|||
dev: false |
|||
|
|||
/react-flags-select/[email protected][email protected]: |
|||
resolution: {integrity: sha512-nx/6mY/nKVJB9sVZOylJoSI6idTYZfu0dtUQ0N1L+cD8VAPNl5c/lxL7yyi9vtn66hDRFy6Sr16GzsBj3aoZfQ==} |
|||
peerDependencies: |
|||
react: '>=16.8.0' |
|||
react-dom: '>=16.8.0' |
|||
dependencies: |
|||
classnames: 2.3.1 |
|||
react: 17.0.2 |
|||
react-dom: 17.0[email protected] |
|||
dev: false |
|||
|
|||
/react-hook-form/[email protected]: |
|||
resolution: {integrity: sha512-e0Oii07qNAa72JeGUT5czVCMwdAFPxmxYvd1Y9oPy2KVD6ZGblN6DG1G7AwL9Bz2lOPFZu15SRNnn0Vpx/eGdg==} |
|||
peerDependencies: |
|||
|
|||
@ -1,84 +0,0 @@ |
|||
import React from 'react'; |
|||
|
|||
import { FiChevronDown } from 'react-icons/fi'; |
|||
|
|||
import { Listbox } from '@headlessui/react'; |
|||
|
|||
export interface SelectProps { |
|||
label: string; |
|||
options: { |
|||
name: string; |
|||
value: string; |
|||
icon: JSX.Element; |
|||
}[]; |
|||
id: string; |
|||
active: { |
|||
name: string; |
|||
value: string; |
|||
icon: JSX.Element; |
|||
}; |
|||
onChange: (value: string) => void; |
|||
} |
|||
|
|||
export const Select = ({ |
|||
label, |
|||
options, |
|||
id, |
|||
active, |
|||
onChange, |
|||
}: SelectProps): JSX.Element => { |
|||
return ( |
|||
<div className="w-full"> |
|||
<label |
|||
htmlFor={id} |
|||
className="block text-sm font-medium text-black dark:text-white" |
|||
> |
|||
{label} |
|||
</label> |
|||
|
|||
<Listbox value={active.value} onChange={onChange}> |
|||
<div className="relative mt-1"> |
|||
<Listbox.Button className="flex w-full text-left bg-white border rounded-md shadow-sm h-11 focus:outline-none focus:border-primary dark:focus:border-primary dark:bg-secondaryDark dark:border-gray-600 dark:text-white"> |
|||
<div className="mx-2 my-auto">{active.icon}</div> |
|||
<span className="block my-auto truncate">{active.name}</span> |
|||
<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none"> |
|||
<FiChevronDown |
|||
className="w-5 h-5 text-gray-400" |
|||
aria-hidden="true" |
|||
/> |
|||
</span> |
|||
</Listbox.Button> |
|||
|
|||
<Listbox.Options className="absolute w-full bg-white border rounded-md shadow-sm focus:outline-none dark:bg-secondaryDark dark:border-gray-600 dark:text-white"> |
|||
{options.map((option) => ( |
|||
<Listbox.Option |
|||
key={option.value} |
|||
className={({ active, selected }): string => |
|||
`cursor-default select-none relative py-2 pr-4 first:rounded-t-md last:rounded-b-md dark:text-white ${ |
|||
active || selected |
|||
? 'bg-gray-200 dark:bg-primaryDark' |
|||
: 'text-gray-900' |
|||
}` |
|||
} |
|||
value={option.value} |
|||
> |
|||
{({ selected }): JSX.Element => ( |
|||
<> |
|||
<span |
|||
className={`flex truncate ${ |
|||
selected ? 'font-medium' : 'font-normal' |
|||
}`}
|
|||
> |
|||
<div className="mx-4 my-auto">{option.icon}</div> |
|||
{option.name} |
|||
</span> |
|||
</> |
|||
)} |
|||
</Listbox.Option> |
|||
))} |
|||
</Listbox.Options> |
|||
</div> |
|||
</Listbox> |
|||
</div> |
|||
); |
|||
}; |
|||
@ -1,73 +0,0 @@ |
|||
import React from 'react'; |
|||
|
|||
import { Switch } from '@headlessui/react'; |
|||
|
|||
import { Label } from './form/Label.jsx'; |
|||
|
|||
type DefaultButtonProps = JSX.IntrinsicElements['button']; |
|||
|
|||
interface ToggleProps extends DefaultButtonProps { |
|||
action?: (enabled: boolean) => void; |
|||
label: string; |
|||
valid?: boolean; |
|||
validationMessage?: string; |
|||
checked?: boolean; |
|||
} |
|||
|
|||
export const Toggle = ({ |
|||
action, |
|||
label, |
|||
valid, |
|||
validationMessage, |
|||
checked, |
|||
id, |
|||
...props |
|||
}: ToggleProps): JSX.Element => { |
|||
const [enabled, setEnabled] = React.useState(false); |
|||
React.useEffect(() => { |
|||
if (checked !== undefined) { |
|||
setEnabled(checked); |
|||
} |
|||
}, [checked]); |
|||
|
|||
const handleToggle = (enabled: boolean) => { |
|||
setEnabled(enabled); |
|||
if (action) { |
|||
action(enabled); |
|||
} |
|||
}; |
|||
|
|||
return ( |
|||
<div className="flex flex-col w-full"> |
|||
<Label label={label} /> |
|||
{/* <label |
|||
htmlFor={id} |
|||
className="block text-sm font-medium text-black dark:text-white" |
|||
> |
|||
{label} |
|||
</label> */} |
|||
<div className="ml-auto"> |
|||
<Switch |
|||
id={id} |
|||
{...props} |
|||
checked={enabled} |
|||
onChange={handleToggle} |
|||
className={`${ |
|||
enabled ? 'bg-primary' : 'bg-gray-200 dark:bg-secondaryDark' |
|||
} |
|||
relative inline-flex flex-shrink-0 h-[38px] w-[74px] border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75`}
|
|||
> |
|||
<span className="sr-only">Use setting</span> |
|||
<span |
|||
aria-hidden="true" |
|||
className={`${enabled ? 'translate-x-9' : 'translate-x-0'} |
|||
pointer-events-none inline-block h-[34px] w-[34px] rounded-full bg-white shadow-lg transform ring-0 transition ease-in-out duration-200`}
|
|||
/> |
|||
</Switch> |
|||
</div> |
|||
{!valid && ( |
|||
<div className="text-sm text-gray-600">{validationMessage}</div> |
|||
)} |
|||
</div> |
|||
); |
|||
}; |
|||
@ -0,0 +1,49 @@ |
|||
import React from 'react'; |
|||
|
|||
import { Label } from './Label.jsx'; |
|||
|
|||
type DefaultInputProps = JSX.IntrinsicElements['input']; |
|||
|
|||
interface CheckboxProps extends DefaultInputProps { |
|||
action?: (enabled: boolean) => void; |
|||
label: string; |
|||
valid?: boolean; |
|||
validationMessage?: string; |
|||
error?: boolean; |
|||
} |
|||
|
|||
export const Checkbox = ({ |
|||
label, |
|||
valid, |
|||
validationMessage, |
|||
id, |
|||
error, |
|||
...props |
|||
}: CheckboxProps): JSX.Element => { |
|||
return ( |
|||
<div className="flex flex-col w-full"> |
|||
<Label label={label} /> |
|||
<div className="ml-auto"> |
|||
<input |
|||
type="checkbox" |
|||
id={id} |
|||
className={`appearance-none w-8 h-8 border rounded-md focus:outline-none checked:bg-primary checked:border-transparent ${ |
|||
props.disabled |
|||
? 'bg-gray-200 text-gray-500 dark:bg-gray-800 dark:text-gray-400 border-gray-400' |
|||
: '' |
|||
} ${ |
|||
error |
|||
? 'border-red-500' |
|||
: props.disabled |
|||
? 'border-gray-200' |
|||
: ' focus-within:border-primary hover:border-primary' |
|||
}`}
|
|||
{...props} |
|||
/> |
|||
</div> |
|||
{!valid && ( |
|||
<div className="text-sm text-gray-600">{validationMessage}</div> |
|||
)} |
|||
</div> |
|||
); |
|||
}; |
|||
Loading…
Reference in new issue