Use Preact for settings and show validation
This commit is contained in:
parent
44459e39c3
commit
d33b37cdb9
4 changed files with 99 additions and 18 deletions
|
@ -1,5 +1,6 @@
|
|||
import './site.scss';
|
||||
import { h, Component } from 'preact';
|
||||
import Input from './ui/input';
|
||||
import * as settingActions from 'settings/actions/setting';
|
||||
import * as validator from 'shared/validators/setting';
|
||||
|
||||
|
@ -10,6 +11,9 @@ class SettingsComponent extends Component {
|
|||
this.state = {
|
||||
settings: {
|
||||
json: '',
|
||||
},
|
||||
errors: {
|
||||
json: '',
|
||||
}
|
||||
};
|
||||
this.context.store.subscribe(this.stateChanged.bind(this));
|
||||
|
@ -35,39 +39,47 @@ class SettingsComponent extends Component {
|
|||
<h1>Configure Vim-Vixen</h1>
|
||||
<form className='vimvixen-settings-form'>
|
||||
|
||||
<p>Load settings from:</p>
|
||||
<input type='radio' id='setting-source-json'
|
||||
<Input
|
||||
type='radio'
|
||||
name='source'
|
||||
value='json'
|
||||
onChange={this.bindAndSave.bind(this)}
|
||||
checked={this.state.settings.source === 'json'} />
|
||||
<label htmlFor='settings-source-json'>JSON</label>
|
||||
label='Use plain JSON'
|
||||
checked={this.state.settings.source === 'json'}
|
||||
value='json' />
|
||||
|
||||
<textarea name='json' spellCheck='false'
|
||||
onInput={this.validate.bind(this)}
|
||||
<Input
|
||||
type='textarea'
|
||||
name='json'
|
||||
label='Plane JSON'
|
||||
spellCheck='false'
|
||||
error={this.state.errors.json}
|
||||
onChange={this.bindValue.bind(this)}
|
||||
onBlur={this.bindAndSave.bind(this)}
|
||||
value={this.state.settings.json} />
|
||||
value={this.state.settings.json}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
validate(e) {
|
||||
try {
|
||||
let settings = JSON.parse(e.target.value);
|
||||
validate(target) {
|
||||
if (target.name === 'json') {
|
||||
let settings = JSON.parse(target.value);
|
||||
validator.validate(settings);
|
||||
e.target.setCustomValidity('');
|
||||
} catch (err) {
|
||||
e.target.setCustomValidity(err.message);
|
||||
}
|
||||
}
|
||||
|
||||
bindValue(e) {
|
||||
let nextSettings = Object.assign({}, this.state.settings);
|
||||
nextSettings[e.target.name] = e.target.value;
|
||||
let next = Object.assign({}, this.state);
|
||||
|
||||
this.setState({ settings: nextSettings });
|
||||
next.errors.json = '';
|
||||
try {
|
||||
this.validate(e.target);
|
||||
} catch (err) {
|
||||
next.errors.json = err.message;
|
||||
}
|
||||
next.settings[e.target.name] = e.target.value;
|
||||
|
||||
this.setState(next);
|
||||
}
|
||||
|
||||
bindAndSave(e) {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
.vimvixen-settings-form {
|
||||
padding: 2px;
|
||||
|
||||
textarea[name=json] {
|
||||
font-family: monospace;
|
||||
width: 100%;
|
||||
|
|
50
src/settings/components/ui/input.jsx
Normal file
50
src/settings/components/ui/input.jsx
Normal file
|
@ -0,0 +1,50 @@
|
|||
import { h, Component } from 'preact';
|
||||
import './input.scss';
|
||||
|
||||
class Input extends Component {
|
||||
|
||||
renderRadio(props) {
|
||||
let inputClasses = 'form-field-input';
|
||||
if (props.error) {
|
||||
inputClasses += ' input-error';
|
||||
}
|
||||
return <div>
|
||||
<label>
|
||||
<input className={ inputClasses } type='radio' {...props} />
|
||||
{ props.label }
|
||||
</label>
|
||||
</div>;
|
||||
}
|
||||
|
||||
renderTextArea(props) {
|
||||
let inputClasses = 'form-field-input';
|
||||
if (props.error) {
|
||||
inputClasses += ' input-error';
|
||||
}
|
||||
return <div>
|
||||
<label
|
||||
className='form-field-label'
|
||||
htmlFor={props.id}
|
||||
>{ props.label }</label>
|
||||
<textarea className={inputClasses} {...props} />
|
||||
|
||||
<p className='form-field-error'>{ this.props.error }</p>
|
||||
</div>;
|
||||
}
|
||||
|
||||
render() {
|
||||
let { type } = this.props;
|
||||
|
||||
switch (this.props.type) {
|
||||
case 'radio':
|
||||
return this.renderRadio(this.props);
|
||||
case 'textarea':
|
||||
return this.renderTextArea(this.props);
|
||||
default:
|
||||
console.warn(`Unsupported input type ${type}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default Input;
|
17
src/settings/components/ui/input.scss
Normal file
17
src/settings/components/ui/input.scss
Normal file
|
@ -0,0 +1,17 @@
|
|||
.form-field-label {
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
.form-field-error {
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
min-height: 1.5em;
|
||||
}
|
||||
|
||||
.form-field-input {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.form-field-input.input-error {
|
||||
box-shadow: 0 0 2px red;
|
||||
}
|
Reference in a new issue