diff options
Diffstat (limited to 'frontend/src/components/fields')
-rw-r--r-- | frontend/src/components/fields/CheckField.js (renamed from frontend/src/components/fields/BooleanField.js) | 9 | ||||
-rw-r--r-- | frontend/src/components/fields/CheckField.scss (renamed from frontend/src/components/fields/BooleanField.scss) | 3 | ||||
-rw-r--r-- | frontend/src/components/fields/InputField.js (renamed from frontend/src/components/fields/StringField.js) | 29 | ||||
-rw-r--r-- | frontend/src/components/fields/InputField.scss (renamed from frontend/src/components/fields/StringField.scss) | 76 | ||||
-rw-r--r-- | frontend/src/components/fields/TextField.js | 42 | ||||
-rw-r--r-- | frontend/src/components/fields/TextField.scss | 79 |
6 files changed, 199 insertions, 39 deletions
diff --git a/frontend/src/components/fields/BooleanField.js b/frontend/src/components/fields/CheckField.js index 06a6da7..5cceac4 100644 --- a/frontend/src/components/fields/BooleanField.js +++ b/frontend/src/components/fields/CheckField.js @@ -1,10 +1,10 @@ import React, {Component} from 'react'; -import './BooleanField.scss'; +import './CheckField.scss'; import {randomClassName} from "../../utils"; const classNames = require('classnames'); -class BooleanField extends Component { +class CheckField extends Component { constructor(props) { super(props); @@ -13,7 +13,6 @@ class BooleanField extends Component { } render() { - const checked = this.props.checked || false; const small = this.props.small || false; const name = this.props.name || null; @@ -24,7 +23,7 @@ class BooleanField extends Component { }; return ( - <div className={classNames( "boolean-field", {"field-checked" : checked}, {"field-small": small})}> + <div className={classNames( "check-field", {"field-checked" : checked}, {"field-small": small})}> <div className="field-input"> <input type="checkbox" id={this.id} checked={checked} onChange={handler} /> <label htmlFor={this.id}>{(checked ? "✓ " : "✗ ") + name}</label> @@ -34,4 +33,4 @@ class BooleanField extends Component { } } -export default BooleanField; +export default CheckField; diff --git a/frontend/src/components/fields/BooleanField.scss b/frontend/src/components/fields/CheckField.scss index 6ec25f7..7b0ac5f 100644 --- a/frontend/src/components/fields/BooleanField.scss +++ b/frontend/src/components/fields/CheckField.scss @@ -1,7 +1,8 @@ @import '../../colors.scss'; -.boolean-field { +.check-field { font-size: 0.9em; + margin: 5px 0; .field-input { border-radius: 5px; diff --git a/frontend/src/components/fields/StringField.js b/frontend/src/components/fields/InputField.js index 7781b2d..af3b3df 100644 --- a/frontend/src/components/fields/StringField.js +++ b/frontend/src/components/fields/InputField.js @@ -1,10 +1,10 @@ import React, {Component} from 'react'; -import './StringField.scss'; +import './InputField.scss'; import {randomClassName} from "../../utils"; const classNames = require('classnames'); -class StringField extends Component { +class InputField extends Component { constructor(props) { super(props); @@ -13,7 +13,6 @@ class StringField extends Component { } render() { - const active = this.props.active || false; const invalid = this.props.invalid || false; const small = this.props.small || false; @@ -22,31 +21,41 @@ class StringField extends Component { const value = this.props.value || ""; const type = this.props.type || "text"; const error = this.props.error || null; + const defaultValue = this.props.defaultValue || null; const handler = (e) => { if (this.props.onChange) { - if (e == null) { + if (type === "file") { + let file = e.target.files[0]; + this.props.onChange(file); + } else if (e == null) { this.props.onChange(""); } else { this.props.onChange(e.target.value); } } }; + let inputProps = {}; + if (type !== "file") { + inputProps["value"] = value; + } return ( - <div className={classNames("string-field", {"field-active" : active}, {"field-invalid": invalid}, + <div className={classNames("input-field", {"field-active" : active}, {"field-invalid": invalid}, {"field-small": small}, {"field-inline": inline})}> <div className="field-wrapper"> { name && <div className="field-name"> - <label id={this.id}>{name}:</label> + <label>{name}:</label> </div> } <div className="field-input"> <div className="field-value"> - <input type={type} placeholder={this.props.defaultValue} aria-label={name} - aria-describedby={this.id} onChange={handler} value={value} /> + { type === "file" && <label for={this.id} className={"file-label"}> + {value.name || defaultValue}</label> } + <input type={type} placeholder={defaultValue} id={this.id} + aria-describedby={this.id} onChange={handler} {...inputProps} /> </div> - { value !== "" && + { type !== "file" && value !== "" && <div className="field-clear"> <span onClick={() => handler(null)}>del</span> </div> @@ -63,4 +72,4 @@ class StringField extends Component { } } -export default StringField; +export default InputField; diff --git a/frontend/src/components/fields/StringField.scss b/frontend/src/components/fields/InputField.scss index 2523c8d..cdb8c9f 100644 --- a/frontend/src/components/fields/StringField.scss +++ b/frontend/src/components/fields/InputField.scss @@ -1,7 +1,8 @@ @import '../../colors.scss'; -.string-field { +.input-field { font-size: 0.9em; + margin: 5px 0; .field-name { label { @@ -12,31 +13,52 @@ .field-input { position: relative; - .field-value input { - background-color: $color-primary-2; - width: 100%; - border: none; - color: $color-primary-4; - border-radius: 5px; - padding: 7px 10px; - - &:focus { - background-color: $color-primary-1; - color: $color-primary-4; - box-shadow: none; - outline: none; - } - - &[readonly] { + .field-value { + input, .file-label { background-color: $color-primary-2; + width: 100%; border: none; color: $color-primary-4; + border-radius: 5px; + padding: 7px 10px; + + &:focus { + background-color: $color-primary-1; + color: $color-primary-4; + box-shadow: none; + outline: none; + } + + &[readonly] { + background-color: $color-primary-2; + border: none; + color: $color-primary-4; + } + + &[readonly]:focus { + background-color: $color-primary-1; + color: $color-primary-4; + box-shadow: none; + } + } + + input[type="file"] { + display: none; + } + + .file-label { + margin: 0; } - &[readonly]:focus { + .file-label:after { + content: "Browse"; + position: absolute; + right: 0; + top: 0; + padding: 7px 10px 7px 12px; background-color: $color-primary-1; - color: $color-primary-4; - box-shadow: none; + border-bottom-right-radius: 5px; + border-top-right-radius: 5px; } } } @@ -47,10 +69,14 @@ color: $color-primary-3 !important; } - .field-value input { + .field-value input, .field-value .file-label { background-color: $color-primary-4 !important; color: $color-primary-3 !important; } + + .file-label:after { + background-color: $color-secondary-4 !important; + } } &.field-invalid { @@ -59,10 +85,14 @@ color: $color-primary-4 !important; } - .field-value input { + .field-value input, .field-value .file-label { background-color: $color-secondary-2 !important; color: $color-primary-4 !important; } + + .file-label:after { + background-color: $color-secondary-1 !important; + } } &.field-small { @@ -82,7 +112,7 @@ .field-input { width: 100%; - input { + input, .file-label { border-bottom-left-radius: 0; border-top-left-radius: 0; padding-left: 3px; diff --git a/frontend/src/components/fields/TextField.js b/frontend/src/components/fields/TextField.js new file mode 100644 index 0000000..86b98ed --- /dev/null +++ b/frontend/src/components/fields/TextField.js @@ -0,0 +1,42 @@ +import React, {Component} from 'react'; +import './TextField.scss'; +import {randomClassName} from "../../utils"; + +const classNames = require('classnames'); + +class TextField extends Component { + + constructor(props) { + super(props); + + this.id = `field-${this.props.name || "noname"}-${randomClassName()}`; + } + + render() { + const name = this.props.name || null; + const error = this.props.error || null; + const rows = this.props.rows || 3; + + const handler = (e) => { + if (this.props.onChange) { + if (e == null) { + this.props.onChange(""); + } else { + this.props.onChange(e.target.value); + } + } + }; + + return ( + <div className={classNames("text-field", {"field-active": this.props.active}, + {"field-invalid": this.props.invalid}, {"field-small": this.props.small})}> + {name && <label htmlFor={this.id}>{name}:</label>} + <textarea id={this.id} placeholder={this.props.defaultValue} onChange={handler} rows={rows} + readOnly={this.props.readonly} value={this.props.value} /> + {error && <div className="field-error">error: {error}</div>} + </div> + ); + } +} + +export default TextField; diff --git a/frontend/src/components/fields/TextField.scss b/frontend/src/components/fields/TextField.scss new file mode 100644 index 0000000..606f537 --- /dev/null +++ b/frontend/src/components/fields/TextField.scss @@ -0,0 +1,79 @@ +@import '../../colors.scss'; + +.text-field { + font-size: 0.9em; + margin: 5px 0; + + label { + display: block; + margin: 0; + } + + textarea { + background-color: $color-primary-2; + width: 100%; + border: none; + color: $color-primary-4; + border-radius: 5px; + padding: 7px 10px; + resize: none; + + &:focus { + background-color: $color-primary-1; + color: $color-primary-4; + box-shadow: none; + outline: none; + } + + &[readonly] { + background-color: $color-primary-2; + border: none; + color: $color-primary-4; + } + + &[readonly]:focus { + background-color: $color-primary-1; + color: $color-primary-4; + box-shadow: none; + } + } + + &.field-active { + textarea { + background-color: $color-primary-4 !important; + color: $color-primary-3 !important; + } + } + + &.field-invalid { + textarea { + background-color: $color-secondary-2 !important; + color: $color-primary-4 !important; + } + } + + &.field-small { + font-size: 0.8em; + } + + .field-clear { + position: absolute; + right: 8px; + top: 8px; + z-index: 10; + font-size: 0.9em; + font-weight: 600; + letter-spacing: -0.5px; + cursor: pointer; + } + + &.field-active .field-clear { + color: $color-primary-2; + } + + .field-error { + padding: 5px 10px; + font-size: 0.9em; + color: $color-secondary-0; + } +} |