diff options
Diffstat (limited to 'frontend/src/components/fields')
-rw-r--r-- | frontend/src/components/fields/CheckField.js | 2 | ||||
-rw-r--r-- | frontend/src/components/fields/TagField.js | 78 | ||||
-rw-r--r-- | frontend/src/components/fields/TagField.scss | 120 |
3 files changed, 199 insertions, 1 deletions
diff --git a/frontend/src/components/fields/CheckField.js b/frontend/src/components/fields/CheckField.js index dd44970..a0e2706 100644 --- a/frontend/src/components/fields/CheckField.js +++ b/frontend/src/components/fields/CheckField.js @@ -35,7 +35,7 @@ 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); } }; diff --git a/frontend/src/components/fields/TagField.js b/frontend/src/components/fields/TagField.js new file mode 100644 index 0000000..f1a48bd --- /dev/null +++ b/frontend/src/components/fields/TagField.js @@ -0,0 +1,78 @@ +/* + * 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 './TagField.scss'; +import './common.scss'; +import {randomClassName} from "../../utils"; +import ReactTags from "react-tag-autocomplete"; + +const classNames = require('classnames'); +const _ = require('lodash'); + +class TagField extends Component { + + constructor(props) { + super(props); + + this.id = `field-${this.props.name || "noname"}-${randomClassName()}`; + } + + state = { + + }; + + onAddition = (tag) => { + if (typeof this.props.onChange === "function") { + const tags = [].concat(this.wrappedTags(), tag); + this.props.onChange(tags.map(t => t.name), true, tag); // true == addition + } + }; + + onDelete = (i) => { + if (typeof this.props.onChange === "function") { + const tags = this.wrappedTags(); + const tag = tags[i]; + tags.splice(i, 1); + this.props.onChange(tags.map(t => t.name), true, tag); // false == delete + } + }; + + wrappedTags = () => this.props.tags.map(t => new Object({"name": t})); + + render() { + const small = this.props.small || false; + const name = this.props.name || null; + + return ( + <div className={classNames( "field", "tag-field", {"field-small": small})}> + { name && + <div className="field-name"> + <label>{name}:</label> + </div> + } + <ReactTags tags={this.wrappedTags() || []} + autoresize={false} + allowNew={this.props.allowNew || true} + onDelete={this.onDelete} onAddition={this.onAddition} + minQueryLength={this.props.min} placeholderText={this.props.placeholder || ""} /> + </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..e77db97 --- /dev/null +++ b/frontend/src/components/fields/TagField.scss @@ -0,0 +1,120 @@ +@import "../../colors.scss"; + +.tag-field { + .react-tags { + font-size: 12px; + position: relative; + z-index: 10; + padding: 0 6px; + cursor: text; + border-radius: 4px; + background-color: $color-primary-2; + } + + .react-tags.is-focused { + border-color: #b1b1b1; + } + + .react-tags__selected { + display: inline; + } + + .react-tags__selected-tag { + font-size: 11px; + display: inline-block; + margin: 0 6px 6px 0; + padding: 2px 4px; + color: $color-primary-3; + border: none; + 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; + } + + .react-tags__search { + display: inline-block; + max-width: 100%; + padding: 7px 10px; + } + + @media screen and (min-width: 30em) { + .react-tags__search { + position: relative; + } + } + + .react-tags__search-input { + font-size: inherit; + line-height: inherit; + max-width: 100%; + margin: 0; + padding: 0; + color: $color-primary-4; + border: 0; + outline: none; + background-color: $color-primary-2; + } + + .react-tags__search-input::-ms-clear { + display: none; + } + + .react-tags__suggestions { + position: absolute; + 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; + color: $color-primary-1; + border-radius: 2px; + background: $color-primary-4; + } + + .react-tags__suggestions li { + padding: 3px 5px; + border-bottom: 1px solid #ddd; + } + + .react-tags__suggestions li mark { + font-weight: 600; + text-decoration: underline; + background: none; + } + + .react-tags__suggestions li:hover { + cursor: pointer; + color: $color-primary-4; + background: $color-primary-0; + } + + .react-tags__suggestions li.is-active { + background: #b7cfe0; + } + + .react-tags__suggestions li.is-disabled { + cursor: auto; + opacity: 0.5; + } +}
\ No newline at end of file |