Polish Inline Label Creation (#12070)

* Condense appearance of inline create label form

Co-Authored-By: Delmer <ofthedelmer@users.noreply.github.com>

* Fine tune copy and click outside behavior

Co-Authored-By: Delmer <ofthedelmer@users.noreply.github.com>

* Show label color error color when invalid hex

Co-Authored-By: Delmer <ofthedelmer@users.noreply.github.com>

* Shrink width of random label color button

Co-Authored-By: Delmer <ofthedelmer@users.noreply.github.com>

* Add full color palette to list of random label colors

Co-Authored-By: Delmer <ofthedelmer@users.noreply.github.com>

* fix(ui/prettier-errors): fix ui prettier errors

Co-authored-by: Alex Paxton <thealexpaxton@gmail.com>
pull/12088/head
alexpaxton 2019-02-21 15:29:06 -08:00 committed by GitHub
parent c664e8e0d8
commit 80ebf933aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 248 additions and 81 deletions

View File

@ -26,30 +26,34 @@
}
.label-selector--menu {
display: flex;
flex-wrap: wrap;
width: 100%;
min-height: 50px;
padding: $ix-marg-b;
padding: $ix-marg-b - ($ix-border / 2);
}
.label-selector--menu-item {
margin: 1px;
display: inline-flex;
align-items: flex-start;
margin: $ix-border / 2;
}
.label-selector--empty {
width: 100%;
font-size: 13px;
font-weight: 500;
user-select: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.label-selector--empty {
padding: $ix-marg-a $ix-marg-b;
color: $g9-mountain;
font-style: italic;
min-height: 30px;
line-height: 30px;
&:first-child {
margin-bottom: $ix-marg-b - ($ix-border / 2);
}
}
.label-selector--selection {

View File

@ -74,15 +74,15 @@ class LabelSelector extends Component<Props, State> {
public render() {
return (
<ClickOutside onClickOutside={this.handleStopSuggesting}>
<div className="label-selector">
<div className="label-selector--selection">
{this.selectedLabels}
{this.clearSelectedButton}
</div>
{this.input}
<div className="label-selector">
<div className="label-selector--selection">
{this.selectedLabels}
{this.clearSelectedButton}
</div>
</ClickOutside>
<ClickOutside onClickOutside={this.handleStopSuggesting}>
{this.input}
</ClickOutside>
</div>
)
}
@ -169,8 +169,9 @@ class LabelSelector extends Component<Props, State> {
private handleStartSuggesting = () => {
const {availableLabels} = this
const {isSuggesting} = this.state
if (_.isEmpty(availableLabels)) {
if (_.isEmpty(availableLabels) && !isSuggesting) {
return this.setState({
isSuggesting: true,
highlightedID: null,

View File

@ -30,8 +30,9 @@ class LabelSelectorMenu extends Component<Props> {
<div className="label-selector--menu-container">
<FancyScrollbar autoHide={false} autoHeight={true} maxHeight={250}>
<div className="label-selector--menu">
{this.resourceLabelForm}
{this.menuItems}
{this.emptyText}
{this.resourceLabelForm}
</div>
</FancyScrollbar>
</div>
@ -60,18 +61,22 @@ class LabelSelectorMenu extends Component<Props> {
/>
))
}
return <div className="label-selector--empty">{this.emptyText}</div>
}
private get emptyText(): string {
const {allLabelsUsed} = this.props
private get emptyText(): JSX.Element {
const {allLabelsUsed, filterValue} = this.props
if (allLabelsUsed) {
return 'You have somehow managed to add all the labels, wow!'
if (!filterValue) {
return null
}
return 'No labels match your query'
let text = `No labels match "${filterValue}" want to create a new label?`
if (allLabelsUsed) {
text = 'You have somehow managed to add all the labels, wow!'
}
return <div className="label-selector--empty">{text}</div>
}
private get resourceLabelForm(): JSX.Element {

View File

@ -26,9 +26,9 @@ class LabelSelectorMenuItem extends Component<Props> {
<span
className="label-selector--menu-item"
onMouseOver={this.handleMouseOver}
onClick={this.handleClick}
>
<Label
onClick={this.handleClick}
name={name}
description={description}
id={id}

View File

@ -9,9 +9,12 @@
display: flex;
align-items: center;
justify-content: center;
margin-bottom: $ix-marg-b;
.label-colors--swatch {
margin-right: $ix-marg-c;
margin-right: $ix-marg-b;
}
> span.button-icon {
margin-right: 0;
}
}

View File

@ -4,10 +4,14 @@ import _ from 'lodash'
// Utils
import {randomPresetColor} from 'src/configuration/utils/labels'
import {IconFont} from 'src/clockface'
import {validateHexCode} from 'src/configuration/utils/labels'
// Styles
import 'src/configuration/components/RandomLabelColor.scss'
// Constants
import {INPUT_ERROR_COLOR} from 'src/configuration/constants/LabelColors'
interface Props {
colorHex: string
onClick: (newRandomHex: string) => void
@ -15,16 +19,16 @@ interface Props {
export default class RandomLabelColorButton extends Component<Props> {
public render() {
const {colorHex} = this.props
return (
<button
className="button button-sm button-default random-color--button "
onClick={this.handleClick}
title="Randomize label color"
>
<div
className="label-colors--swatch"
style={{
backgroundColor: colorHex,
backgroundColor: this.colorHex,
}}
/>
<span className={`button-icon icon ${IconFont.Refresh}`} />
@ -32,6 +36,16 @@ export default class RandomLabelColorButton extends Component<Props> {
)
}
private get colorHex(): string {
const {colorHex} = this.props
if (validateHexCode(colorHex)) {
return INPUT_ERROR_COLOR
}
return colorHex
}
private handleClick = () => {
this.props.onClick(randomPresetColor())
}

View File

@ -58,6 +58,150 @@ export const PRESET_LABEL_COLORS: LabelColor[] = [
name: 'Neutrino',
type: LabelColorType.Preset,
},
{
id: 'label-preset-void',
colorHex: '#311F94',
name: 'Void',
type: LabelColorType.Preset,
},
{
id: 'label-preset-amethyst',
colorHex: '#513CC6',
name: 'Amethyst',
type: LabelColorType.Preset,
},
{
id: 'label-preset-star',
colorHex: '#7A65F2',
name: 'Star',
type: LabelColorType.Preset,
},
{
id: 'label-preset-comet',
colorHex: '#9394FF',
name: 'Comet',
type: LabelColorType.Preset,
},
{
id: 'label-preset-potassium',
colorHex: '#B1B6FF',
name: 'Potassium',
type: LabelColorType.Preset,
},
{
id: 'label-preset-moonstone',
colorHex: '#C9D0FF',
name: 'Moonstone',
type: LabelColorType.Preset,
},
{
id: 'label-preset-emerald',
colorHex: '#108174',
name: 'Emerald',
type: LabelColorType.Preset,
},
{
id: 'label-preset-viridian',
colorHex: '#32B08C',
name: 'Viridian',
type: LabelColorType.Preset,
},
{
id: 'label-preset-rainforest',
colorHex: '#4ED8A0',
name: 'Rainforest',
type: LabelColorType.Preset,
},
{
id: 'label-preset-honeydew',
colorHex: '#7CE490',
name: 'Honeydew',
type: LabelColorType.Preset,
},
{
id: 'label-preset-krypton',
colorHex: '#A5F3B4',
name: 'Krypton',
type: LabelColorType.Preset,
},
{
id: 'label-preset-wasabi',
colorHex: '#C6FFD0',
name: 'Wasabi',
type: LabelColorType.Preset,
},
{
id: 'label-preset-ruby',
colorHex: '#BF3D5E',
name: 'Ruby',
type: LabelColorType.Preset,
},
{
id: 'label-preset-fire',
colorHex: '#DC4E58',
name: 'Fire',
type: LabelColorType.Preset,
},
{
id: 'label-preset-curacao',
colorHex: '#F95F53',
name: 'Curacao',
type: LabelColorType.Preset,
},
{
id: 'label-preset-dreamsicle',
colorHex: '#FF8564',
name: 'Dreamsicle',
type: LabelColorType.Preset,
},
{
id: 'label-preset-tungsten',
colorHex: '#FFB6A0',
name: 'Tungsten',
type: LabelColorType.Preset,
},
{
id: 'label-preset-marmelade',
colorHex: '#FFDCCF',
name: 'Marmelade',
type: LabelColorType.Preset,
},
{
id: 'label-preset-topaz',
colorHex: '#E85B1C',
name: 'Topaz',
type: LabelColorType.Preset,
},
{
id: 'label-preset-tiger',
colorHex: '#F48D38',
name: 'Tiger',
type: LabelColorType.Preset,
},
{
id: 'label-preset-pineapple',
colorHex: '#FFB94A',
name: 'Pineapple',
type: LabelColorType.Preset,
},
{
id: 'label-preset-thunder',
colorHex: '#FFD255',
name: 'Thunder',
type: LabelColorType.Preset,
},
{
id: 'label-preset-sulfur',
colorHex: '#FFE480',
name: 'Sulfur',
type: LabelColorType.Preset,
},
{
id: 'label-preset-daisy',
colorHex: '#FFF6B8',
name: 'Daisy',
type: LabelColorType.Preset,
},
]
export const INPUT_ERROR_COLOR = '#0F0E15'

View File

@ -5,9 +5,12 @@
*/
.resource-label--form {
margin-bottom: $ix-marg-b;
width: 100%;
.resource-label--create-button {
margin-top: $ix-marg-c + 2px;
}
}
.form--element {
margin: 0;
}
.component-spacer--horizontal {
align-items: flex-start;
}
}

View File

@ -7,22 +7,15 @@ import {
Button,
ComponentColor,
ButtonType,
Columns,
ComponentStatus,
} from '@influxdata/clockface'
import {
Grid,
Form,
Input,
InputType,
ComponentSpacer,
Alignment,
} from 'src/clockface'
import {Form, Input, InputType, ComponentSpacer, Alignment} from 'src/clockface'
import RandomLabelColorButton from 'src/configuration/components/RandomLabelColor'
import {Label, LabelProperties} from 'src/types/v2/labels'
// Constants
import {HEX_CODE_CHAR_LENGTH} from 'src/configuration/constants/LabelColors'
const MAX_CREATE_BUTTON_LENGTH = 24
// Utils
import {
@ -72,46 +65,34 @@ export default class ResourceLabelForm extends PureComponent<Props, State> {
public render() {
const {isValid} = this.state
// TODO: Add className prop to ComponentSpacer so we don't need this wrapper div
return (
<div className="resource-label--form">
<Grid.Row>
<Grid.Column widthXS={Columns.Five}>
<Form.Element label="Color">
<ComponentSpacer stretchToFitWidth={true} align={Alignment.Left}>
<RandomLabelColorButton
colorHex={this.colorHex}
onClick={this.handleColorChange}
/>
{this.customColorInput}
</ComponentSpacer>
</Form.Element>
</Grid.Column>
<Grid.Column widthXS={Columns.Five}>
<Form.Element label="Description">
<Input
type={InputType.Text}
placeholder="Add a optional description"
name="description"
value={this.description}
onChange={this.handleInputChange}
/>
</Form.Element>
</Grid.Column>
<Grid.Column widthXS={Columns.Two}>
<Form.Element label="">
<Button
customClass="resource-label--create-button"
text="Create Label"
color={ComponentColor.Success}
type={ButtonType.Submit}
status={
isValid ? ComponentStatus.Default : ComponentStatus.Disabled
}
onClick={this.handleSubmit}
/>
</Form.Element>
</Grid.Column>
</Grid.Row>
<ComponentSpacer align={Alignment.Left}>
<RandomLabelColorButton
colorHex={this.colorHex}
onClick={this.handleColorChange}
/>
{this.customColorInput}
<Input
type={InputType.Text}
placeholder="Add a optional description"
name="description"
value={this.description}
onChange={this.handleInputChange}
/>
<Button
customClass="resource-label--create-button"
text={this.createButtonLabel}
color={ComponentColor.Success}
type={ButtonType.Submit}
status={
isValid ? ComponentStatus.Default : ComponentStatus.Disabled
}
onClick={this.handleSubmit}
/>
</ComponentSpacer>
</div>
)
}
@ -157,6 +138,18 @@ export default class ResourceLabelForm extends PureComponent<Props, State> {
})
}
private get createButtonLabel(): string {
const {labelName} = this.props
let label = `Create "${labelName}"`
if (labelName.length > MAX_CREATE_BUTTON_LENGTH) {
label = `Create "${labelName.slice(0, MAX_CREATE_BUTTON_LENGTH)}..."`
}
return label
}
private get customColorInput(): JSX.Element {
const {colorHex} = this