diff options
author | Emiliano Ciavatta | 2020-10-16 17:06:05 +0000 |
---|---|---|
committer | Emiliano Ciavatta | 2020-10-16 17:06:05 +0000 |
commit | 56f70a72196c777f248038bb2e2e4099e6e1367d (patch) | |
tree | 714ad5aed8698dfffbb472b3fa74909acb8cdead /frontend/src/components/fields | |
parent | 6204c99e69d1707a79c5e56685b47310106c60b0 (diff) | |
parent | 79b8b2fa3e8563c986da8baa3a761f2d4f0c6f47 (diff) |
Merge branch 'develop'
Diffstat (limited to 'frontend/src/components/fields')
-rw-r--r-- | frontend/src/components/fields/ButtonField.js | 32 | ||||
-rw-r--r-- | frontend/src/components/fields/ButtonField.scss | 7 | ||||
-rw-r--r-- | frontend/src/components/fields/CheckField.js | 31 | ||||
-rw-r--r-- | frontend/src/components/fields/ChoiceField.js | 27 | ||||
-rw-r--r-- | frontend/src/components/fields/ChoiceField.scss | 8 | ||||
-rw-r--r-- | frontend/src/components/fields/InputField.js | 37 | ||||
-rw-r--r-- | frontend/src/components/fields/InputField.scss | 21 | ||||
-rw-r--r-- | frontend/src/components/fields/TagField.js | 75 | ||||
-rw-r--r-- | frontend/src/components/fields/TagField.scss | 157 | ||||
-rw-r--r-- | frontend/src/components/fields/TextField.js | 27 | ||||
-rw-r--r-- | frontend/src/components/fields/TextField.scss | 4 | ||||
-rw-r--r-- | frontend/src/components/fields/common.scss | 4 | ||||
-rw-r--r-- | frontend/src/components/fields/extensions/ColorField.js | 34 | ||||
-rw-r--r-- | frontend/src/components/fields/extensions/NumericField.js | 23 |
14 files changed, 427 insertions, 60 deletions
diff --git a/frontend/src/components/fields/ButtonField.js b/frontend/src/components/fields/ButtonField.js index cc32b0f..15ef179 100644 --- a/frontend/src/components/fields/ButtonField.js +++ b/frontend/src/components/fields/ButtonField.js @@ -1,8 +1,25 @@ -import React, {Component} from 'react'; -import './ButtonField.scss'; -import './common.scss'; +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ -const classNames = require('classnames'); +import React, {Component} from "react"; +import "./ButtonField.scss"; +import "./common.scss"; + +const classNames = require("classnames"); class ButtonField extends Component { @@ -38,9 +55,10 @@ class ButtonField extends Component { } return ( - <div className={classNames( "field", "button-field", {"field-small": this.props.small})}> - <button type="button" className={classNames(classNames(buttonClassnames))} - onClick={handler} style={buttonStyle}>{this.props.name}</button> + <div className={classNames("field", "button-field", {"field-small": this.props.small}, + {"field-active": this.props.active})}> + <button type="button" className={classNames(buttonClassnames)} + onClick={handler} style={buttonStyle} disabled={this.props.disabled}>{this.props.name}</button> </div> ); } diff --git a/frontend/src/components/fields/ButtonField.scss b/frontend/src/components/fields/ButtonField.scss index 9e46b9f..99afe08 100644 --- a/frontend/src/components/fields/ButtonField.scss +++ b/frontend/src/components/fields/ButtonField.scss @@ -15,6 +15,13 @@ } } + &.field-active { + button { + color: $color-primary-1; + background-color: $color-primary-4; + } + } + .button-variant-red { color: $color-red-light; background-color: $color-red; diff --git a/frontend/src/components/fields/CheckField.js b/frontend/src/components/fields/CheckField.js index 33f4f83..bfa1c9d 100644 --- a/frontend/src/components/fields/CheckField.js +++ b/frontend/src/components/fields/CheckField.js @@ -1,9 +1,26 @@ -import React, {Component} from 'react'; -import './CheckField.scss'; -import './common.scss'; +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import React, {Component} from "react"; import {randomClassName} from "../../utils"; +import "./CheckField.scss"; +import "./common.scss"; -const classNames = require('classnames'); +const classNames = require("classnames"); class CheckField extends Component { @@ -18,15 +35,15 @@ class CheckField extends Component { const small = this.props.small || false; const name = this.props.name || null; const handler = () => { - if (this.props.onChange) { + if (!this.props.readonly && this.props.onChange) { this.props.onChange(!checked); } }; return ( - <div className={classNames( "field", "check-field", {"field-checked" : checked}, {"field-small": small})}> + <div className={classNames("field", "check-field", {"field-checked": checked}, {"field-small": small})}> <div className="field-input"> - <input type="checkbox" id={this.id} checked={checked} onChange={handler} /> + <input type="checkbox" id={this.id} checked={checked} onChange={handler}/> <label htmlFor={this.id}>{(checked ? "✓ " : "✗ ") + (name != null ? name : "")}</label> </div> </div> diff --git a/frontend/src/components/fields/ChoiceField.js b/frontend/src/components/fields/ChoiceField.js index 73e950d..7e97d89 100644 --- a/frontend/src/components/fields/ChoiceField.js +++ b/frontend/src/components/fields/ChoiceField.js @@ -1,9 +1,26 @@ -import React, {Component} from 'react'; -import './ChoiceField.scss'; -import './common.scss'; +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import React, {Component} from "react"; import {randomClassName} from "../../utils"; +import "./ChoiceField.scss"; +import "./common.scss"; -const classNames = require('classnames'); +const classNames = require("classnames"); class ChoiceField extends Component { @@ -50,7 +67,7 @@ class ChoiceField extends Component { } return ( - <div className={classNames( "field", "choice-field", {"field-inline" : inline}, + <div className={classNames("field", "choice-field", {"field-inline": inline}, {"field-small": this.props.small})}> {!inline && name && <label className="field-name">{name}:</label>} <div className={classNames("field-select", {"select-expanded": this.state.expanded})} diff --git a/frontend/src/components/fields/ChoiceField.scss b/frontend/src/components/fields/ChoiceField.scss index 0b5e510..85986af 100644 --- a/frontend/src/components/fields/ChoiceField.scss +++ b/frontend/src/components/fields/ChoiceField.scss @@ -19,7 +19,7 @@ border-radius: 5px; background-color: $color-primary-2; - &:after { + &::after { position: absolute; right: 10px; content: "⋎"; @@ -27,8 +27,8 @@ } .field-options { - position: absolute; - z-index: 20; + position: static; + z-index: 100; top: 35px; display: none; width: 100%; @@ -58,7 +58,7 @@ display: block; } - .field-value:after { + .field-value::after { content: "⋏"; } } diff --git a/frontend/src/components/fields/InputField.js b/frontend/src/components/fields/InputField.js index 84c981b..e2ea020 100644 --- a/frontend/src/components/fields/InputField.js +++ b/frontend/src/components/fields/InputField.js @@ -1,9 +1,26 @@ -import React, {Component} from 'react'; -import './InputField.scss'; -import './common.scss'; +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import React, {Component} from "react"; import {randomClassName} from "../../utils"; +import "./common.scss"; +import "./InputField.scss"; -const classNames = require('classnames'); +const classNames = require("classnames"); class InputField extends Component { @@ -42,23 +59,23 @@ class InputField extends Component { } return ( - <div className={classNames("field", "input-field", {"field-active" : active}, + <div className={classNames("field", "input-field", {"field-active": active}, {"field-invalid": invalid}, {"field-small": small}, {"field-inline": inline})}> <div className="field-wrapper"> - { name && + {name && <div className="field-name"> <label>{name}:</label> </div> } <div className="field-input"> <div className="field-value"> - { type === "file" && <label for={this.id} className={"file-label"}> - {value.name || this.props.placeholder}</label> } + {type === "file" && <label for={this.id} className={"file-label"}> + {value.name || this.props.placeholder}</label>} <input type={type} placeholder={this.props.placeholder} id={this.id} aria-describedby={this.id} onChange={handler} {...inputProps} - readOnly={this.props.readonly} /> + readOnly={this.props.readonly}/> </div> - { type !== "file" && value !== "" && + {type !== "file" && value !== "" && !this.props.readonly && <div className="field-clear"> <span onClick={() => handler(null)}>del</span> </div> diff --git a/frontend/src/components/fields/InputField.scss b/frontend/src/components/fields/InputField.scss index 7cc34d9..eafb2ab 100644 --- a/frontend/src/components/fields/InputField.scss +++ b/frontend/src/components/fields/InputField.scss @@ -28,7 +28,7 @@ display: none; } - .file-label:after { + .file-label::after { position: absolute; top: 0; right: 0; @@ -47,13 +47,14 @@ background-color: $color-primary-4 !important; } - .field-value input, .field-value .file-label { - color: $color-primary-3 !important; - background-color: $color-primary-4 !important; + .file-label::after { + background-color: $color-secondary-4 !important; } - .file-label:after { - background-color: $color-secondary-4 !important; + .field-value input, + .field-value .file-label { + color: $color-primary-3 !important; + background-color: $color-primary-4 !important; } } @@ -63,12 +64,13 @@ background-color: $color-secondary-2 !important; } - .field-value input, .field-value .file-label { + .field-value input, + .field-value .file-label { color: $color-primary-4 !important; background-color: $color-secondary-2 !important; } - .file-label:after { + .file-label::after { background-color: $color-secondary-1 !important; } } @@ -90,7 +92,8 @@ .field-input { width: 100%; - input, .file-label { + input, + .file-label { padding-left: 3px; border-top-left-radius: 0; border-bottom-left-radius: 0; diff --git a/frontend/src/components/fields/TagField.js b/frontend/src/components/fields/TagField.js new file mode 100644 index 0000000..9a36da4 --- /dev/null +++ b/frontend/src/components/fields/TagField.js @@ -0,0 +1,75 @@ +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import React, {Component} from "react"; +import ReactTags from "react-tag-autocomplete"; +import {randomClassName} from "../../utils"; +import "./common.scss"; +import "./TagField.scss"; + +const classNames = require("classnames"); +const _ = require("lodash"); + +class TagField extends Component { + + state = {}; + + constructor(props) { + super(props); + + this.id = `field-${this.props.name || "noname"}-${randomClassName()}`; + } + + onAddition = (tag) => { + if (typeof this.props.onChange === "function") { + this.props.onChange([].concat(this.props.tags, tag), true, tag); // true == addition + } + }; + + onDelete = (i) => { + if (typeof this.props.onChange === "function") { + const tags = _.clone(this.props.tags); + const tag = tags[i]; + tags.splice(i, 1); + this.props.onChange(tags, true, tag); // false == delete + } + }; + + + render() { + const small = this.props.small || false; + const name = this.props.name || null; + + return ( + <div className={classNames("field", "tag-field", {"field-small": small}, + {"field-inline": this.props.inline})}> + {name && + <div className="field-name"> + <label>{name}:</label> + </div> + } + <div className="field-input"> + <ReactTags {...this.props} tags={this.props.tags || []} autoresize={false} + onDelete={this.onDelete} onAddition={this.onAddition} + placeholderText={this.props.placeholder || ""}/> + </div> + </div> + ); + } +} + +export default TagField; diff --git a/frontend/src/components/fields/TagField.scss b/frontend/src/components/fields/TagField.scss new file mode 100644 index 0000000..723e71f --- /dev/null +++ b/frontend/src/components/fields/TagField.scss @@ -0,0 +1,157 @@ +@import "../../colors.scss"; + +.tag-field { + font-size: 0.9em; + margin: 5px 0; + + .field-name { + label { + margin: 0; + } + } + + .react-tags { + position: relative; + display: flex; + border-radius: 4px; + background-color: $color-primary-2; + + &:focus-within, + &:focus-within .react-tags__search-input { + background-color: $color-primary-1; + } + } + + &.field-small { + font-size: 0.8em; + } + + &.field-inline { + display: flex; + + .field-name { + padding: 6px 0 6px 7px; + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + background-color: $color-primary-2; + } + + .field-input { + flex: 1; + + .react-tags { + padding-left: 3px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } + + &:focus-within .field-name { + background-color: $color-primary-1; + } + } + + .react-tags__selected { + display: inline-block; + flex: 0 1; + margin: 6px 0; + white-space: nowrap; + } + + .react-tags__selected-tag { + font-size: 0.75em; + margin: 0 3px; + padding: 2px 4px; + color: $color-primary-3; + border-radius: 2px; + background: $color-primary-4; + } + + .react-tags__selected-tag::after { + margin-left: 8px; + content: "\2715"; + color: $color-primary-3; + } + + .react-tags__selected-tag:hover, + .react-tags__selected-tag:focus { + border-color: #b1b1b1; + background-color: $color-primary-0; + + &::after { + color: $color-primary-4; + } + } + + .react-tags__search { + flex: 1 0; + } + + @media screen and (min-width: 30em) { + .react-tags__search { + position: relative; + } + } + + .react-tags__search-input { + color: $color-primary-4; + background-color: $color-primary-2; + } + + .react-tags__search-input::-ms-clear { + display: none; + } + + .react-tags__suggestions { + position: absolute; + z-index: 50; + top: 100%; + left: 0; + width: 100%; + } + + @media screen and (min-width: 30em) { + .react-tags__suggestions { + width: 240px; + } + } + + .react-tags__suggestions ul { + font-size: 12px; + margin: 4px -1px; + padding: 0; + list-style: none; + border-radius: 3px; + background: $color-primary-2; + } + + .react-tags__suggestions li { + padding: 5px 10px; + } + + .react-tags__suggestions li mark { + font-weight: 600; + padding: 0; + color: $color-primary-4; + background: none; + } + + .react-tags__suggestions li:hover { + cursor: pointer; + border-radius: 3px; + background: $color-primary-1; + + mark { + color: $color-primary-4; + } + } + + .react-tags__suggestions li.is-active { + background: $color-primary-3; + } + + .react-tags__suggestions li.is-disabled { + cursor: auto; + opacity: 0.5; + } +} diff --git a/frontend/src/components/fields/TextField.js b/frontend/src/components/fields/TextField.js index de68c21..4dd77bd 100644 --- a/frontend/src/components/fields/TextField.js +++ b/frontend/src/components/fields/TextField.js @@ -1,9 +1,26 @@ -import React, {Component} from 'react'; -import './TextField.scss'; -import './common.scss'; +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import React, {Component} from "react"; import {randomClassName} from "../../utils"; +import "./common.scss"; +import "./TextField.scss"; -const classNames = require('classnames'); +const classNames = require("classnames"); class TextField extends Component { @@ -33,7 +50,7 @@ class TextField extends Component { {"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} ref={this.props.textRef} /> + readOnly={this.props.readonly} value={this.props.value} ref={this.props.textRef}/> {error && <div className="field-error">error: {error}</div>} </div> ); diff --git a/frontend/src/components/fields/TextField.scss b/frontend/src/components/fields/TextField.scss index c2d6ef5..5fde9e6 100644 --- a/frontend/src/components/fields/TextField.scss +++ b/frontend/src/components/fields/TextField.scss @@ -51,4 +51,8 @@ padding: 5px 10px; color: $color-secondary-0; } + + &:hover::-webkit-scrollbar-thumb { + background: $color-secondary-2 !important; + } } diff --git a/frontend/src/components/fields/common.scss b/frontend/src/components/fields/common.scss index f37369e..e5dc65c 100644 --- a/frontend/src/components/fields/common.scss +++ b/frontend/src/components/fields/common.scss @@ -1,7 +1,9 @@ @import "../../colors.scss"; .field { - input, textarea { + input, + textarea { + font-family: "Fira Code", monospace; width: 100%; padding: 7px 10px; color: $color-primary-4; diff --git a/frontend/src/components/fields/extensions/ColorField.js b/frontend/src/components/fields/extensions/ColorField.js index 96ebc49..fd30988 100644 --- a/frontend/src/components/fields/extensions/ColorField.js +++ b/frontend/src/components/fields/extensions/ColorField.js @@ -1,19 +1,35 @@ -import React, {Component} from 'react'; +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import React, {Component} from "react"; import {OverlayTrigger, Popover} from "react-bootstrap"; -import './ColorField.scss'; -import InputField from "../InputField"; import validation from "../../../validation"; +import InputField from "../InputField"; +import "./ColorField.scss"; class ColorField extends Component { constructor(props) { super(props); - this.state = { - }; + this.state = {}; - this.colors = ["#E53935", "#D81B60", "#8E24AA", "#5E35B1", "#3949AB", "#1E88E5", "#039BE5", "#00ACC1", - "#00897B", "#43A047", "#7CB342", "#9E9D24", "#F9A825", "#FB8C00", "#F4511E", "#6D4C41"]; + this.colors = ["#e53935", "#d81b60", "#8e24aa", "#5e35b1", "#3949ab", "#1e88e5", "#039be5", "#00acc1", + "#00897b", "#43a047", "#7cb342", "#9e9d24", "#f9a825", "#fb8c00", "#f4511e", "#6d4c41"]; } componentDidUpdate(prevProps, prevState, snapshot) { @@ -38,7 +54,7 @@ class ColorField extends Component { this.props.onChange(color); } document.body.click(); // magic to close popup - }} />); + }}/>); const popover = ( <Popover id="popover-basic"> @@ -65,7 +81,7 @@ class ColorField extends Component { <div className="field color-field"> <div className="color-input"> <InputField {...this.props} onChange={this.onChange} invalid={this.state.invalid} name="color" - error={null} /> + error={null}/> <div className="color-picker"> <OverlayTrigger trigger="click" placement="top" overlay={popover} rootClose> <button type="button" className="picker-button" style={buttonStyles}>pick</button> diff --git a/frontend/src/components/fields/extensions/NumericField.js b/frontend/src/components/fields/extensions/NumericField.js index 19a9e46..a6cba26 100644 --- a/frontend/src/components/fields/extensions/NumericField.js +++ b/frontend/src/components/fields/extensions/NumericField.js @@ -1,4 +1,21 @@ -import React, {Component} from 'react'; +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import React, {Component} from "react"; import InputField from "../InputField"; class NumericField extends Component { @@ -18,7 +35,7 @@ class NumericField extends Component { } onChange = (value) => { - value = value.toString().replace(/[^\d]/gi, ''); + value = value.toString().replace(/[^\d]/gi, ""); let intValue = 0; if (value !== "") { intValue = parseInt(value, 10); @@ -36,7 +53,7 @@ class NumericField extends Component { render() { return ( <InputField {...this.props} onChange={this.onChange} defaultValue={this.props.defaultValue || "0"} - invalid={this.state.invalid} /> + invalid={this.state.invalid}/> ); } |