Add more settings
This commit is contained in:
@@ -1,35 +1,32 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
type DefaultInputProps = JSX.IntrinsicElements['input'];
|
||||||
|
|
||||||
export interface InputProps {
|
export interface InputProps {
|
||||||
valid?: boolean;
|
valid?: boolean;
|
||||||
placeholder?: string;
|
|
||||||
validationMessage?: string;
|
validationMessage?: string;
|
||||||
icon?: JSX.Element;
|
icon?: JSX.Element;
|
||||||
type: string;
|
label: string;
|
||||||
name: string;
|
|
||||||
value?: string;
|
|
||||||
disabled?: boolean;
|
|
||||||
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Input = ({
|
export const Input = React.forwardRef<
|
||||||
|
HTMLInputElement,
|
||||||
|
InputProps & DefaultInputProps
|
||||||
|
>(function Input(
|
||||||
|
{
|
||||||
valid,
|
valid,
|
||||||
placeholder,
|
|
||||||
validationMessage,
|
validationMessage,
|
||||||
icon,
|
icon,
|
||||||
type,
|
label,
|
||||||
name,
|
id,
|
||||||
value,
|
...props
|
||||||
disabled,
|
}: InputProps & DefaultInputProps,
|
||||||
onChange,
|
ref,
|
||||||
}: InputProps): JSX.Element => {
|
) {
|
||||||
return (
|
return (
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<label
|
<label htmlFor={id} className="block text-sm font-medium dark:text-white">
|
||||||
htmlFor={name}
|
{label}
|
||||||
className="block text-sm font-medium dark:text-white"
|
|
||||||
>
|
|
||||||
{name}
|
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
{icon && (
|
{icon && (
|
||||||
@@ -40,16 +37,11 @@ export const Input = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<input
|
<input
|
||||||
type={type}
|
ref={ref}
|
||||||
name={name}
|
{...props}
|
||||||
id={name}
|
|
||||||
value={value}
|
|
||||||
onChange={onChange}
|
|
||||||
className={`block w-full h-11 rounded-md border shadow-sm focus:outline-none focus:border-primary dark:focus:border-primary dark:bg-secondaryDark dark:border-gray-600 dark:text-white ${
|
className={`block w-full h-11 rounded-md border shadow-sm focus:outline-none focus:border-primary dark:focus:border-primary dark:bg-secondaryDark dark:border-gray-600 dark:text-white ${
|
||||||
icon ? 'pl-9' : 'pl-2'
|
icon ? 'pl-9' : 'pl-2'
|
||||||
}`}
|
}`}
|
||||||
placeholder={placeholder}
|
|
||||||
disabled={disabled}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{!valid && (
|
{!valid && (
|
||||||
@@ -57,4 +49,4 @@ export const Input = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type DefaultSelectProps = JSX.IntrinsicElements['select'];
|
||||||
|
|
||||||
|
export interface SelectProps {
|
||||||
|
options: {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
}[];
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Select = React.forwardRef<
|
||||||
|
HTMLSelectElement,
|
||||||
|
SelectProps & DefaultSelectProps
|
||||||
|
>(function Select(
|
||||||
|
{ options, label, id, ...props }: SelectProps & DefaultSelectProps,
|
||||||
|
ref,
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<div className="space-y-1">
|
||||||
|
<label htmlFor={id} className="block text-sm font-medium dark:text-white">
|
||||||
|
{label}
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
className="block w-full p-2 border dark:border-gray-600 rounded-md shadow-sm dark:bg-secondaryDark"
|
||||||
|
>
|
||||||
|
{options.map((option) => (
|
||||||
|
<option key={option.value} value={option.value}>
|
||||||
|
{option.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -1,26 +1,33 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Switch } from '@headlessui/react';
|
type DefaultInputProps = JSX.IntrinsicElements['input'];
|
||||||
|
|
||||||
export interface ToggleProps {
|
export interface ToggleProps {
|
||||||
enabled: boolean;
|
label: string;
|
||||||
setEnabled: (state: boolean) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Toggle = ({ enabled, setEnabled }: ToggleProps): JSX.Element => {
|
export const Toggle = React.forwardRef<
|
||||||
|
HTMLInputElement,
|
||||||
|
ToggleProps & DefaultInputProps
|
||||||
|
>(function Input(
|
||||||
|
{ label, id, checked, ...props }: ToggleProps & DefaultInputProps,
|
||||||
|
ref,
|
||||||
|
) {
|
||||||
return (
|
return (
|
||||||
<Switch
|
<div className="flex flex-col">
|
||||||
checked={enabled}
|
<span className="block text-sm font-medium dark:text-white">{label}</span>
|
||||||
onChange={setEnabled}
|
<div className="relative w-14 mr-2 ml-auto select-none">
|
||||||
className={`${enabled ? 'bg-primary' : 'bg-gray-300 dark:bg-gray-700'}
|
<input
|
||||||
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`}
|
ref={ref}
|
||||||
>
|
{...props}
|
||||||
<span className="sr-only">Use setting</span>
|
type="checkbox"
|
||||||
<span
|
className="peer checked:right-0 absolute w-7 h-7 rounded-full bg-white appearance-none cursor-pointer"
|
||||||
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>
|
<label
|
||||||
|
htmlFor={id}
|
||||||
|
className="block overflow-hidden h-7 rounded-full peer-checked:bg-primary shadow-sm bg-gray-300 dark:bg-gray-700 cursor-pointer"
|
||||||
|
></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|||||||
+81
-15
@@ -1,10 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { Protobuf } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
import { Input } from '../components/form/Input';
|
import { Input } from '../components/form/Input';
|
||||||
|
import { Select } from '../components/form/Select';
|
||||||
import { Toggle } from '../components/form/Toggle';
|
import { Toggle } from '../components/form/Toggle';
|
||||||
import { PrimaryTemplate } from '../components/templates/PrimaryTemplate';
|
import { PrimaryTemplate } from '../components/templates/PrimaryTemplate';
|
||||||
|
import { connection } from '../connection';
|
||||||
import { useAppDispatch, useAppSelector } from '../hooks/redux';
|
import { useAppDispatch, useAppSelector } from '../hooks/redux';
|
||||||
import {
|
import {
|
||||||
setHostOverride,
|
setHostOverride,
|
||||||
@@ -21,6 +26,16 @@ export const Settings = (): JSX.Element => {
|
|||||||
(state) => state.meshtastic.hostOverrideEnabled,
|
(state) => state.meshtastic.hostOverrideEnabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { register, handleSubmit } =
|
||||||
|
useForm<Protobuf.RadioConfig_UserPreferences>({
|
||||||
|
defaultValues: radioConfig,
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = handleSubmit((data) => {
|
||||||
|
console.log(data);
|
||||||
|
connection.setPreferences(data);
|
||||||
|
});
|
||||||
|
|
||||||
const [localHostOverride, setLocalHostOverride] =
|
const [localHostOverride, setLocalHostOverride] =
|
||||||
React.useState(hostOverride);
|
React.useState(hostOverride);
|
||||||
const [localHostOverrideEnabled, setLocalHostOverrideEnabled] =
|
const [localHostOverrideEnabled, setLocalHostOverrideEnabled] =
|
||||||
@@ -28,36 +43,84 @@ export const Settings = (): JSX.Element => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<PrimaryTemplate title="Settings" tagline="Device">
|
<PrimaryTemplate title="Settings" tagline="Device">
|
||||||
<div className="flex mb-8 dark:text-white">
|
<form onSubmit={onSubmit}>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="flex pb-2 dark:text-white border-b dark:border-gray-600">
|
||||||
<div className="w-1/3 text-lg">WiFi</div>
|
<div className="w-1/3 text-lg">WiFi</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2 w-full max-w-xs">
|
||||||
<Input
|
<Input
|
||||||
name={t('strings.wifi_ssid')}
|
label={t('strings.wifi_ssid')}
|
||||||
value={radioConfig.wifiSsid}
|
{...register('wifiSsid', {})}
|
||||||
onChange={(event) => {}}
|
|
||||||
type="text"
|
type="text"
|
||||||
valid={true}
|
valid={true}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
name={t('strings.wifi_psk')}
|
label={t('strings.wifi_psk')}
|
||||||
value={radioConfig.wifiPassword}
|
{...register('wifiPassword', {})}
|
||||||
onChange={(event) => {}}
|
|
||||||
type="password"
|
type="password"
|
||||||
valid={true}
|
valid={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex dark:text-white">
|
<div className="flex pb-2 dark:text-white border-b dark:border-gray-600">
|
||||||
<div className="w-1/3 text-lg">Client</div>
|
<div className="w-1/3 text-lg">Node</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2 w-full max-w-xs">
|
||||||
|
<Toggle label={'Is router node'} {...register('isRouter', {})} />
|
||||||
<Toggle
|
<Toggle
|
||||||
enabled={localHostOverrideEnabled}
|
label={'Is router node'}
|
||||||
setEnabled={(state) => {
|
{...register('isLowPower', {})}
|
||||||
setLocalHostOverrideEnabled(state);
|
/>
|
||||||
|
<Toggle
|
||||||
|
label={'Is router node'}
|
||||||
|
{...register('fixedPosition', {})}
|
||||||
|
/>
|
||||||
|
<Toggle
|
||||||
|
label={'Is serial disabled'}
|
||||||
|
{...register('serialDisabled', {})}
|
||||||
|
/>
|
||||||
|
<Toggle
|
||||||
|
label={'Is router low power'}
|
||||||
|
{...register('isLowPower', {})}
|
||||||
|
/>
|
||||||
|
<Toggle
|
||||||
|
label={'Is MQTT disabled'}
|
||||||
|
{...register('mqttDisabled', {})}
|
||||||
|
/>
|
||||||
|
<Toggle
|
||||||
|
label={'Debug log enabled'}
|
||||||
|
{...register('debugLogEnabled', {})}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
label="Region"
|
||||||
|
{...register('region', {
|
||||||
|
valueAsNumber: true,
|
||||||
|
})}
|
||||||
|
options={(() => {
|
||||||
|
return Object.keys(Protobuf.RegionCode)
|
||||||
|
.filter((value) => isNaN(Number(value)) === false)
|
||||||
|
.map((key) => {
|
||||||
|
return {
|
||||||
|
value: key,
|
||||||
|
label: Protobuf.RegionCode[parseInt(key)],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
})()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex pb-2 dark:text-white border-b dark:border-gray-600">
|
||||||
|
<div className="w-1/3 text-lg">Client</div>
|
||||||
|
<div className="space-y-2 w-full max-w-xs">
|
||||||
|
<Toggle
|
||||||
|
label={'Enable host override'}
|
||||||
|
checked={localHostOverrideEnabled}
|
||||||
|
onChange={(event) => {
|
||||||
|
console.log(event.target.checked);
|
||||||
|
setLocalHostOverrideEnabled(event.target.checked);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
name={'Host override'}
|
label={'Host override'}
|
||||||
placeholder={'meshtastic.local'}
|
placeholder={'meshtastic.local'}
|
||||||
value={localHostOverride}
|
value={localHostOverride}
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
@@ -69,8 +132,10 @@ export const Settings = (): JSX.Element => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
type="submit"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
dispatch(setHostOverride(localHostOverride));
|
dispatch(setHostOverride(localHostOverride));
|
||||||
dispatch(setHostOverrideEnabled(localHostOverrideEnabled));
|
dispatch(setHostOverrideEnabled(localHostOverrideEnabled));
|
||||||
@@ -79,6 +144,7 @@ export const Settings = (): JSX.Element => {
|
|||||||
>
|
>
|
||||||
{t('strings.save_changes')}
|
{t('strings.save_changes')}
|
||||||
</button>
|
</button>
|
||||||
|
</form>
|
||||||
</PrimaryTemplate>
|
</PrimaryTemplate>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user