From e1f8f519006d313b4124d92de65a207f620fc26f Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 1 Mar 2024 14:45:51 +0200 Subject: [PATCH] UI: Color picker design improvement --- .../components/color-input.component.ts | 8 +- .../color-picker-panel.component.html | 26 ++++--- .../color-picker-panel.component.scss | 17 ++++- .../color-picker-panel.component.ts | 16 +++- .../color-picker/color-picker.component.html | 57 +++++++------- .../color-picker/color-picker.component.scss | 49 +++++++++++- .../color-picker/color-picker.component.ts | 4 +- .../color-picker/hex-input.component.html | 36 +++++++++ .../color-picker/hex-input.component.scss | 48 ++++++++++++ .../color-picker/hex-input.component.ts | 75 +++++++++++++++++++ .../dialog/color-picker-dialog.component.html | 8 +- .../dialog/color-picker-dialog.component.scss | 28 +++++++ .../shared/components/popover.component.ts | 3 +- .../app/shared/components/popover.service.ts | 9 ++- ui-ngx/src/app/shared/shared.module.ts | 16 ++-- 15 files changed, 333 insertions(+), 67 deletions(-) create mode 100644 ui-ngx/src/app/shared/components/color-picker/hex-input.component.html create mode 100644 ui-ngx/src/app/shared/components/color-picker/hex-input.component.scss create mode 100644 ui-ngx/src/app/shared/components/color-picker/hex-input.component.ts diff --git a/ui-ngx/src/app/shared/components/color-input.component.ts b/ui-ngx/src/app/shared/components/color-input.component.ts index ad772ba861..706db50677 100644 --- a/ui-ngx/src/app/shared/components/color-input.component.ts +++ b/ui-ngx/src/app/shared/components/color-input.component.ts @@ -189,13 +189,13 @@ export class ColorInputComponent extends PageComponent implements OnInit, Contro this.popoverService.hidePopover(trigger); } else { const colorPickerPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, ColorPickerPanelComponent, ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], true, null, + this.viewContainerRef, ColorPickerPanelComponent, ['left'], true, null, { color: this.colorFormGroup.get('color').value, - colorClearButton: this.colorClearButton + colorClearButton: this.colorClearButton, + colorCancelButton: true }, - {}, - {}, {}, true); + {}, {}, {}, false, () => {}, {padding: '12px 4px 12px 12px'}); colorPickerPopover.tbComponentRef.instance.popover = colorPickerPopover; colorPickerPopover.tbComponentRef.instance.colorSelected.subscribe((color) => { colorPickerPopover.hide(); diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.html b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.html index 40e6653867..6ddae212e1 100644 --- a/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.html +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.html @@ -16,8 +16,7 @@ -->
-
color.color
- +
- + +
+ + +
diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.scss b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.scss index d25f6b9d85..fc71d69822 100644 --- a/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.scss +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.scss @@ -13,11 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@import "../scss/constants"; + .tb-color-picker-panel { - width: 328px; + width: 342px; display: flex; flex-direction: column; - gap: 16px; + max-height: calc(100vh - 24px); + min-height: 100%; + @media #{$mat-sm} { + width: 578px; + } .tb-color-picker-title { font-size: 16px; font-weight: 500; @@ -25,12 +31,17 @@ letter-spacing: 0.25px; color: rgba(0, 0, 0, 0.87); } + .tb-color-picker { + padding-right: 4px; + overflow-y: scroll; + } .tb-color-picker-panel-buttons { height: 60px; + padding: 8px 8px 0 0; display: flex; flex-direction: row; gap: 16px; - justify-content: flex-end; + justify-content: space-between; align-items: flex-end; } } diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.ts b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.ts index 8ed2d304ae..443dd6967f 100644 --- a/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.ts +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.ts @@ -38,12 +38,19 @@ export class ColorPickerPanelComponent extends PageComponent implements OnInit { @coerceBoolean() colorClearButton = false; + @Input() + @coerceBoolean() + colorCancelButton = false; + @Input() popover: TbPopoverComponent; @Output() colorSelected = new EventEmitter(); + @Output() + colorCancelDialog = new EventEmitter(); + colorPickerControl: UntypedFormControl; constructor(protected store: Store) { @@ -61,4 +68,11 @@ export class ColorPickerPanelComponent extends PageComponent implements OnInit { clearColor() { this.colorSelected.emit(null); } -} + + cancelColor() { + if (this.popover) { + this.popover.hide(); + } else { + this.colorCancelDialog.emit(); + } + }} diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.html b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.html index 7940f1ec73..888c5b0b0b 100644 --- a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.html +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.html @@ -15,35 +15,38 @@ limitations under the License. --> - - -
- - -
- - -
-
- -
- - HEX - RGBA - HSLA - -
- - - +
+ + +
+
+ + +
+ + +
+
+ +
+ + HEX + RGBA + HSLA + +
+ + + +
+
- +
diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.scss b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.scss index 9aca580994..ef22ac203f 100644 --- a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.scss +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.scss @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@import "../scss/constants"; + :host { width: 100%; display: flex; @@ -20,10 +22,34 @@ gap: 32px; overflow: auto; + .color-input-container { + display: flex; + flex-direction: column; + gap: 32px; + @media #{$mat-sm} { + flex-direction: row; + gap: 12px; + } + } + + .control-input-container { + display: flex; + flex-direction: column; + gap: 32px; + @media #{$mat-sm} { + width: 100%; + justify-content: center; + } + } + .saturation-component { + width: 100%; height: 238px; - min-height: 80px; + min-height: 160px; border-radius: 8px; + @media #{$mat-sm} { + max-height: 160px; + } } .control-component { @@ -54,7 +80,9 @@ } .color-input-block { + height: 56px; display: flex; + align-items: center; gap: 20px; .presentation-select { @@ -74,8 +102,13 @@ .color-presets-block { .color-presets-component { display: flex; - flex-direction: column; - gap: 12px; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + gap: 8px; + @media #{$mat-xs} { + flex-direction: column; + } } } } @@ -111,13 +144,21 @@ .color-presets-component { .presets-row { - gap: 10px; + gap: 8px; justify-content: space-between; } color-preset { height: 20px; width: 20px; border-radius: 4px; + @media #{$mat-xs} { + height: 40px; + width: 48px; + } + @media #{$mat-sm} { + height: 40px; + width: 40px; + } } } } diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.ts b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.ts index 5cca12a968..100d1177cf 100644 --- a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.ts +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.ts @@ -31,8 +31,8 @@ export enum ColorType { } const colorPresetsHex = - ['#435B63', '#F44336', '#E89623', '#F5DD00', '#8BC34A', '#4CAF50', '#009688', '#048AD3', '#673AB7', '#9C27B0', '#E91E63', - '#A1ADB1', '#F9A19B', '#FFD190', '#FFF59D', '#C5E1A4', '#A5D7A7', '#80CBC3', '#81C4E9', '#B39CDB', '#CD93D7', '#F48FB1']; + ['#435B63', '#F44336', '#E89623', '#F5DD00', '#8BC34A', '#4CAF50', '#009688', '#048AD3', '#673AB7', '#9C27B0', '#E91E63', '#6F113A', + '#A1ADB1', '#F9A19B', '#FFD190', '#FFF59D', '#C5E1A4', '#A5D7A7', '#80CBC3', '#81C4E9', '#B39CDB', '#CD93D7', '#F48FB1', '#BC91A4']; @Component({ selector: `tb-color-picker`, diff --git a/ui-ngx/src/app/shared/components/color-picker/hex-input.component.html b/ui-ngx/src/app/shared/components/color-picker/hex-input.component.html new file mode 100644 index 0000000000..c3faa497ce --- /dev/null +++ b/ui-ngx/src/app/shared/components/color-picker/hex-input.component.html @@ -0,0 +1,36 @@ + +
+ + {{prefixValue}} + + + + + + + % + +
diff --git a/ui-ngx/src/app/shared/components/color-picker/hex-input.component.scss b/ui-ngx/src/app/shared/components/color-picker/hex-input.component.scss new file mode 100644 index 0000000000..0f5125874c --- /dev/null +++ b/ui-ngx/src/app/shared/components/color-picker/hex-input.component.scss @@ -0,0 +1,48 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +:host { + .hex-input-container { + display: flex; + gap: 8px; + } + .hex-input { + max-width: 190px; + } + .alpha-input { + min-width: 60px; + max-width: 60px; + } + + ::ng-deep { + .mdc-text-field--filled, .mat-mdc-form-field-focus-overlay { + &:before { + background-color: transparent !important; + } + } + .mat-mdc-form-field-icon-prefix, .mdc-line-ripple, .copy-button { + opacity: 0.4; + } + .alpha-input { + .mat-mdc-text-field-wrapper { + padding-left: 0; + } + } + + } +} + + diff --git a/ui-ngx/src/app/shared/components/color-picker/hex-input.component.ts b/ui-ngx/src/app/shared/components/color-picker/hex-input.component.ts new file mode 100644 index 0000000000..fcd91a2397 --- /dev/null +++ b/ui-ngx/src/app/shared/components/color-picker/hex-input.component.ts @@ -0,0 +1,75 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; +import { Color } from '@iplab/ngx-color-picker'; + +@Component({ + selector: `tb-hex-input`, + templateUrl: `./hex-input.component.html`, + styleUrls: ['./hex-input.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class HexInputComponent { + + @Input() + public color: Color; + + @Output() + public colorChange = new EventEmitter(false); + + @Input() + public labelVisible = false; + + @Input() + public prefixValue = '#'; + + public get value() { + return this.color ? this.color.toHexString(this.color.getRgba().alpha < 1).replace('#', '') : ''; + } + + public get copyColor() { + return this.prefixValue + this.value; + } + + public get hueValue(): string { + return this.color ? Math.round(this.color.getRgba().alpha * 100).toString() : ''; + } + + public onHueInputChange(event: KeyboardEvent, inputValue: string): void { + const color = this.color.getRgba(); + const alpha = +inputValue / 100; + if (color.getAlpha() !== alpha) { + const newColor = new Color().setRgba(color.red, color.green, color.blue, alpha).toHexString(true); + this.colorChange.emit(new Color(newColor)); + } + } + + public onInputChange(event: KeyboardEvent, inputValue: string): void { + const value = inputValue.toLowerCase(); + if ( + ((event.keyCode === 13 || event.key.toLowerCase() === 'enter') && value.length === 3) + || value.length === 6 || value.length === 8 + ) { + const hex = parseInt(value, 16); + const hexStr = hex.toString(16); + if (hexStr.padStart(value.length, '0') === value && this.value !== value) { + const newColor = new Color(`#${value}`); + this.colorChange.emit(newColor); + } + } + } +} diff --git a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.html b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.html index 3d37d83c15..35b560bb3a 100644 --- a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.html +++ b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.html @@ -16,14 +16,10 @@ -->
-
diff --git a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.scss b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.scss index 2a4ec55f7d..e5b24d78e1 100644 --- a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.scss +++ b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.scss @@ -13,10 +13,38 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@import "../scss/constants"; + :host { .tb-close-button { position: absolute; top: 6px; right: 6px; } + ::ng-deep { + .mat-mdc-dialog-content { + max-height: 100%; + overflow: hidden; + padding: 12px 4px 12px 12px !important; + } + .tb-color-picker-panel { + @media #{$mat-sm} { + width: 342px; + .color-input-container { + flex-direction: column !important; + } + .color-presets-component color-preset { + width: 48px; + } + } + + @media #{$mat-xs} { + width: 100%; + .hex-input { + flex: 1; + max-width: 100% !important; + } + } + } + } } diff --git a/ui-ngx/src/app/shared/components/popover.component.ts b/ui-ngx/src/app/shared/components/popover.component.ts index de2c328204..f0aa4981af 100644 --- a/ui-ngx/src/app/shared/components/popover.component.ts +++ b/ui-ngx/src/app/shared/components/popover.component.ts @@ -340,7 +340,7 @@ export class TbPopoverDirective implements OnChanges, OnDestroy, AfterViewInit {