19 changed files with 105 additions and 255 deletions
@ -2,7 +2,7 @@ lockfileVersion: 5.3 |
|||||
|
|
||||
specifiers: |
specifiers: |
||||
'@headlessui/react': ^1.4.2 |
'@headlessui/react': ^1.4.2 |
||||
'@meshtastic/meshtasticjs': ^0.6.24 |
'@meshtastic/meshtasticjs': ^0.6.25 |
||||
'@reduxjs/toolkit': ^1.6.2 |
'@reduxjs/toolkit': ^1.6.2 |
||||
'@snowpack/plugin-dotenv': ^2.2.0 |
'@snowpack/plugin-dotenv': ^2.2.0 |
||||
'@snowpack/plugin-postcss': ^1.4.3 |
'@snowpack/plugin-postcss': ^1.4.3 |
||||
@ -39,7 +39,6 @@ specifiers: |
|||||
react-apexcharts: ^1.3.9 |
react-apexcharts: ^1.3.9 |
||||
react-dom: ^17.0.2 |
react-dom: ^17.0.2 |
||||
react-file-icon: ^1.1.0 |
react-file-icon: ^1.1.0 |
||||
react-flags-select: ^2.1.2 |
|
||||
react-hook-form: ^7.19.1 |
react-hook-form: ^7.19.1 |
||||
react-i18next: ^11.13.0 |
react-i18next: ^11.13.0 |
||||
react-icons: ^4.3.1 |
react-icons: ^4.3.1 |
||||
@ -54,7 +53,7 @@ specifiers: |
|||||
|
|
||||
dependencies: |
dependencies: |
||||
'@headlessui/react': 1.4[email protected][email protected] |
'@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] |
'@reduxjs/toolkit': 1.6[email protected][email protected] |
||||
apexcharts: 3.29.0 |
apexcharts: 3.29.0 |
||||
boring-avatars: 1.5.8 |
boring-avatars: 1.5.8 |
||||
@ -65,7 +64,6 @@ dependencies: |
|||||
react-apexcharts: 1.3[email protected][email protected] |
react-apexcharts: 1.3[email protected][email protected] |
||||
react-dom: 17.0[email protected] |
react-dom: 17.0[email protected] |
||||
react-file-icon: 1.1[email protected][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-hook-form: 7.19[email protected] |
||||
react-i18next: 11.13[email protected][email protected] |
react-i18next: 11.13[email protected][email protected] |
||||
react-icons: 4.3[email protected] |
react-icons: 4.3[email protected] |
||||
@ -426,8 +424,8 @@ packages: |
|||||
resolution: {integrity: sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==} |
resolution: {integrity: sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==} |
||||
dev: true |
dev: true |
||||
|
|
||||
/@meshtastic/meshtasticjs/0.6.24: |
/@meshtastic/meshtasticjs/0.6.25: |
||||
resolution: {integrity: sha512-zdIxyIL6a+UUgZdZvxeRhK/xVhLYB0ZeB5OuA9peRFVE/ICHmAhkmNb58G1hDr0Lq3mPtmlsnh0DiPkI5O4TnQ==} |
resolution: {integrity: sha512-/FVmKIFpzSo2xguJ0+HfnpN9/6TS3ReMOXL29U7CsPnqGwePC3JJd3THNn2+ofOa//Iy7xGTYah0nF+LH1znJQ==} |
||||
dependencies: |
dependencies: |
||||
'@protobuf-ts/runtime': 2.0.7 |
'@protobuf-ts/runtime': 2.0.7 |
||||
node-fetch: 3.1.0 |
node-fetch: 3.1.0 |
||||
@ -1582,10 +1580,6 @@ packages: |
|||||
resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} |
resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} |
||||
dev: true |
dev: true |
||||
|
|
||||
/classnames/2.3.1: |
|
||||
resolution: {integrity: sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==} |
|
||||
dev: false |
|
||||
|
|
||||
/clean-stack/2.2.0: |
/clean-stack/2.2.0: |
||||
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} |
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} |
||||
engines: {node: '>=6'} |
engines: {node: '>=6'} |
||||
@ -4466,17 +4460,6 @@ packages: |
|||||
tinycolor2: 1.4.2 |
tinycolor2: 1.4.2 |
||||
dev: false |
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]: |
/react-hook-form/[email protected]: |
||||
resolution: {integrity: sha512-e0Oii07qNAa72JeGUT5czVCMwdAFPxmxYvd1Y9oPy2KVD6ZGblN6DG1G7AwL9Bz2lOPFZu15SRNnn0Vpx/eGdg==} |
resolution: {integrity: sha512-e0Oii07qNAa72JeGUT5czVCMwdAFPxmxYvd1Y9oPy2KVD6ZGblN6DG1G7AwL9Bz2lOPFZu15SRNnn0Vpx/eGdg==} |
||||
peerDependencies: |
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