diff --git a/src/components/ha-hs-color-picker.ts b/src/components/ha-hs-color-picker.ts index 1533e2b6c4..ba5d038526 100644 --- a/src/components/ha-hs-color-picker.ts +++ b/src/components/ha-hs-color-picker.ts @@ -186,9 +186,8 @@ class HaHsColorPicker extends LitElement { } if (changedProps.has("value")) { if ( - this.value !== undefined && - (this._localValue?.[0] !== this.value[0] || - this._localValue?.[1] !== this.value[1]) + this._localValue?.[0] !== this.value?.[0] || + this._localValue?.[1] !== this.value?.[1] ) { this._resetPosition(); } @@ -243,7 +242,11 @@ class HaHsColorPicker extends LitElement { } private _resetPosition() { - if (this.value === undefined) return; + if (this.value === undefined) { + this._cursorPosition = undefined; + this._localValue = undefined; + return; + } this._cursorPosition = this._getCoordsFromValue(this.value); this._localValue = this.value; } @@ -384,6 +387,7 @@ class HaHsColorPicker extends LitElement { canvas { width: 100%; height: 100%; + object-fit: contain; border-radius: 50%; cursor: pointer; } diff --git a/src/components/ha-icon-button-group.ts b/src/components/ha-icon-button-group.ts new file mode 100644 index 0000000000..cd739082ab --- /dev/null +++ b/src/components/ha-icon-button-group.ts @@ -0,0 +1,38 @@ +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement } from "lit/decorators"; + +@customElement("ha-icon-button-group") +export class HaIconButtonGroup extends LitElement { + protected render(): TemplateResult { + return html``; + } + + static get styles(): CSSResultGroup { + return css` + :host { + position: relative; + display: flex; + flex-direction: row; + align-items: center; + height: 56px; + border-radius: 28px; + background-color: rgba(139, 145, 151, 0.1); + box-sizing: border-box; + width: auto; + padding: 4px; + gap: 4px; + } + ::slotted(.separator) { + background-color: rgba(var(--rgb-primary-text-color), 0.15); + width: 1px; + height: 40px; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-icon-button-group": HaIconButtonGroup; + } +} diff --git a/src/components/ha-icon-button-toggle.ts b/src/components/ha-icon-button-toggle.ts new file mode 100644 index 0000000000..56d0b37c82 --- /dev/null +++ b/src/components/ha-icon-button-toggle.ts @@ -0,0 +1,52 @@ +import { css, CSSResultGroup } from "lit"; +import { customElement, property } from "lit/decorators"; +import { HaIconButton } from "./ha-icon-button"; + +@customElement("ha-icon-button-toggle") +export class HaIconButtonToggle extends HaIconButton { + @property({ type: Boolean, reflect: true }) selected = false; + + static get styles(): CSSResultGroup { + return css` + :host { + position: relative; + } + mwc-icon-button { + position: relative; + transition: color 180ms ease-in-out; + } + mwc-icon-button::before { + opacity: 0; + transition: opacity 180ms ease-in-out; + background-color: var(--primary-text-color); + border-radius: 20px; + height: 40px; + width: 40px; + content: ""; + position: absolute; + top: -10px; + left: -10px; + bottom: -10px; + right: -10px; + margin: auto; + box-sizing: border-box; + } + :host([border-only]) mwc-icon-button::before { + background-color: transparent; + border: 2px solid var(--primary-text-color); + } + :host([selected]) mwc-icon-button { + color: var(--primary-background-color); + } + :host([selected]) mwc-icon-button::before { + opacity: 1; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-icon-button-toggle": HaIconButtonToggle; + } +} diff --git a/src/components/ha-temp-color-picker.ts b/src/components/ha-temp-color-picker.ts index 9070a46e28..b2f2b26dfc 100644 --- a/src/components/ha-temp-color-picker.ts +++ b/src/components/ha-temp-color-picker.ts @@ -139,7 +139,7 @@ class HaTempColorPicker extends LitElement { this.setAttribute("aria-valuemax", this.max.toString()); } if (changedProps.has("value")) { - if (this.value != null && this._localValue !== this.value) { + if (this._localValue !== this.value) { this._resetPosition(); } } @@ -197,7 +197,11 @@ class HaTempColorPicker extends LitElement { } private _resetPosition() { - if (this.value === undefined) return; + if (this.value === undefined) { + this._cursorPosition = undefined; + this._localValue = undefined; + return; + } const [, y] = this._getCoordsFromValue(this.value); const currentX = this._cursorPosition?.[0] ?? 0; const x = @@ -391,6 +395,7 @@ class HaTempColorPicker extends LitElement { canvas { width: 100%; height: 100%; + object-fit: contain; border-radius: 50%; transition: box-shadow 180ms ease-in-out; cursor: pointer; diff --git a/src/data/light.ts b/src/data/light.ts index 42a2507731..ed42fdeb5f 100644 --- a/src/data/light.ts +++ b/src/data/light.ts @@ -159,3 +159,5 @@ export const computeDefaultFavoriteColors = ( return colors; }; + +export const formatTempColor = (value: number) => `${value} K`; diff --git a/src/dialogs/more-info/components/lights/dialog-light-color-favorite.ts b/src/dialogs/more-info/components/lights/dialog-light-color-favorite.ts index 3c72999412..410ba70c04 100644 --- a/src/dialogs/more-info/components/lights/dialog-light-color-favorite.ts +++ b/src/dialogs/more-info/components/lights/dialog-light-color-favorite.ts @@ -1,16 +1,28 @@ import { mdiClose } from "@mdi/js"; import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-button"; import "../../../../components/ha-dialog"; import "../../../../components/ha-dialog-header"; -import { EntityRegistryEntry } from "../../../../data/entity_registry"; -import { LightColor } from "../../../../data/light"; +import "../../../../components/ha-icon-button-toggle"; +import type { EntityRegistryEntry } from "../../../../data/entity_registry"; +import { + formatTempColor, + LightColor, + LightColorMode, + LightEntity, + lightSupportsColor, + lightSupportsColorMode, +} from "../../../../data/light"; import { haStyleDialog } from "../../../../resources/styles"; -import { HomeAssistant } from "../../../../types"; -import "./light-color-picker"; -import { LightColorFavoriteDialogParams } from "./show-dialog-light-color-favorite"; +import type { HomeAssistant } from "../../../../types"; +import "./light-color-rgb-picker"; +import "./light-color-temp-picker"; +import type { LightColorFavoriteDialogParams } from "./show-dialog-light-color-favorite"; + +export type LightPickerMode = "color_temp" | "color"; @customElement("dialog-light-color-favorite") class DialogLightColorFavorite extends LitElement { @@ -22,11 +34,26 @@ class DialogLightColorFavorite extends LitElement { @state() _color?: LightColor; + @state() private _mode?: LightPickerMode; + + @state() private _modes: LightPickerMode[] = []; + + @state() private _currentValue?: string; + + private _colorHovered(ev: CustomEvent) { + if (ev.detail && "color_temp_kelvin" in ev.detail) { + this._currentValue = formatTempColor(ev.detail.color_temp_kelvin); + } else { + this._currentValue = undefined; + } + } + public async showDialog( dialogParams: LightColorFavoriteDialogParams ): Promise { this._entry = dialogParams.entry; this._dialogParams = dialogParams; + this._updateModes(dialogParams.defaultMode); await this.updateComplete; } @@ -37,10 +64,43 @@ class DialogLightColorFavorite extends LitElement { fireEvent(this, "dialog-closed", { dialog: this.localName }); } + private _updateModes(defaultMode?: LightPickerMode) { + const supportsTemp = lightSupportsColorMode( + this.stateObj!, + LightColorMode.COLOR_TEMP + ); + + const supportsColor = lightSupportsColor(this.stateObj!); + + const modes: LightPickerMode[] = []; + if (supportsColor) { + modes.push("color"); + } + if (supportsTemp) { + modes.push("color_temp"); + } + + this._modes = modes; + this._mode = + defaultMode ?? + (this.stateObj!.attributes.color_mode + ? this.stateObj!.attributes.color_mode === LightColorMode.COLOR_TEMP + ? LightColorMode.COLOR_TEMP + : "color" + : this._modes[0]); + } + private _colorChanged(ev: CustomEvent) { this._color = ev.detail; } + get stateObj() { + return ( + this._entry && + (this.hass.states[this._entry.entity_id] as LightEntity | undefined) + ); + } + private async _cancel() { this._dialogParams?.cancel?.(); this.closeDialog(); @@ -55,8 +115,16 @@ class DialogLightColorFavorite extends LitElement { this.closeDialog(); } + private _modeChanged(ev): void { + const newMode = ev.currentTarget.mode; + if (newMode === this._mode) { + return; + } + this._mode = newMode; + } + protected render() { - if (!this._entry) { + if (!this._entry || !this.stateObj) { return nothing; } @@ -76,13 +144,58 @@ class DialogLightColorFavorite extends LitElement { > ${this._dialogParams?.title} - - +
+ ${this._currentValue} + ${this._modes.length > 1 + ? html` +
+ ${this._modes.map( + (value) => + html` + + + + ` + )} +
+ ` + : nothing} +
+ +
+ ${this._mode === "color_temp" + ? html` + + + ` + : nothing} + ${this._mode === "color" + ? html` + + + ` + : nothing} +
${this.hass.localize("ui.common.cancel")} @@ -101,16 +214,10 @@ class DialogLightColorFavorite extends LitElement { --dialog-content-padding: 0; } - light-color-picker { - display: flex; - flex-direction: column; - flex: 1; - } - @media all and (max-width: 450px), all and (max-height: 500px) { ha-dialog { --dialog-surface-margin-top: 100px; - --mdc-dialog-min-height: calc(100% - 100px); + --mdc-dialog-min-height: auto; --mdc-dialog-max-height: calc(100% - 100px); --ha-dialog-border-radius: var( --ha-dialog-bottom-sheet-border-radius, @@ -118,6 +225,54 @@ class DialogLightColorFavorite extends LitElement { ); } } + + .content { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 24px; + flex: 1; + } + .modes { + display: flex; + flex-direction: row; + justify-content: flex-end; + padding: 0 24px; + } + .wheel { + width: 30px; + height: 30px; + flex: none; + border-radius: 15px; + } + .wheel.color { + background-image: url("/static/images/color_wheel.png"); + background-size: cover; + } + .wheel.color_temp { + background: linear-gradient( + 0, + rgb(166, 209, 255) 0%, + white 50%, + rgb(255, 160, 0) 100% + ); + } + .value { + pointer-events: none; + position: absolute; + top: 0; + left: 0; + right: 0; + margin: auto; + font-style: normal; + font-weight: 500; + font-size: 16px; + height: 48px; + line-height: 48px; + letter-spacing: 0.1px; + text-align: center; + } `, ]; } diff --git a/src/dialogs/more-info/components/lights/ha-more-info-light-favorite-colors.ts b/src/dialogs/more-info/components/lights/ha-more-info-light-favorite-colors.ts index c8c3c8cc1b..ad00a5b105 100644 --- a/src/dialogs/more-info/components/lights/ha-more-info-light-favorite-colors.ts +++ b/src/dialogs/more-info/components/lights/ha-more-info-light-favorite-colors.ts @@ -30,10 +30,16 @@ import { } from "../../../../resources/sortable.ondemand"; import { HomeAssistant } from "../../../../types"; import { showConfirmationDialog } from "../../../generic/show-dialog-box"; +import type { LightPickerMode } from "./dialog-light-color-favorite"; import "./ha-favorite-color-button"; -import type { LightPickerMode } from "./light-color-picker"; import { showLightColorFavoriteDialog } from "./show-dialog-light-color-favorite"; +declare global { + interface HASSDomEvents { + "favorite-color-edit-started"; + } +} + @customElement("ha-more-info-light-favorite-colors") export class HaMoreInfoLightFavoriteColors extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -147,8 +153,8 @@ export class HaMoreInfoLightFavoriteColors extends LitElement { private _edit = async (index) => { // Make sure the current favorite color is set + fireEvent(this, "favorite-color-edit-started"); await this._apply(index); - const defaultMode: LightPickerMode = "color_temp_kelvin" in this._favoriteColors[index] ? "color_temp" diff --git a/src/dialogs/more-info/components/lights/ha-more-info-view-light-color-picker.ts b/src/dialogs/more-info/components/lights/ha-more-info-view-light-color-picker.ts deleted file mode 100644 index b556443f5e..0000000000 --- a/src/dialogs/more-info/components/lights/ha-more-info-view-light-color-picker.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; -import { customElement, property } from "lit/decorators"; -import { HomeAssistant } from "../../../../types"; -import "./light-color-picker"; -import { LightColorPickerViewParams } from "./show-view-light-color-picker"; - -@customElement("ha-more-info-view-light-color-picker") -class MoreInfoViewLightColorPicker extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property() public params?: LightColorPickerViewParams; - - protected render() { - if (!this.params) { - return nothing; - } - - return html` - - - `; - } - - static get styles(): CSSResultGroup { - return [ - css` - :host { - position: relative; - display: flex; - flex-direction: column; - flex: 1; - } - light-color-picker { - display: flex; - flex-direction: column; - flex: 1; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "ha-more-info-view-light-color-picker": MoreInfoViewLightColorPicker; - } -} diff --git a/src/dialogs/more-info/components/lights/light-color-picker.ts b/src/dialogs/more-info/components/lights/light-color-rgb-picker.ts similarity index 59% rename from src/dialogs/more-info/components/lights/light-color-picker.ts rename to src/dialogs/more-info/components/lights/light-color-rgb-picker.ts index 720cd2a5bb..cf50ae5c04 100644 --- a/src/dialogs/more-info/components/lights/light-color-picker.ts +++ b/src/dialogs/more-info/components/lights/light-color-rgb-picker.ts @@ -23,21 +23,18 @@ import { fireEvent } from "../../../../common/dom/fire_event"; import { throttle } from "../../../../common/util/throttle"; import "../../../../components/ha-button-toggle-group"; import "../../../../components/ha-hs-color-picker"; +import "../../../../components/ha-icon"; import "../../../../components/ha-icon-button-prev"; import "../../../../components/ha-labeled-slider"; import "../../../../components/ha-temp-color-picker"; import { - LightColor, getLightCurrentModeRgbColor, + LightColor, LightColorMode, LightEntity, - lightSupportsColor, lightSupportsColorMode, } from "../../../../data/light"; import { HomeAssistant } from "../../../../types"; -import "../../../../components/ha-icon"; - -export type LightPickerMode = "color_temp" | "color"; declare global { interface HASSDomEvents { @@ -45,13 +42,11 @@ declare global { } } -@customElement("light-color-picker") -class LightColorPicker extends LitElement { +@customElement("light-color-rgb-picker") +class LightRgbColorPicker extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property() public entityId!: string; - - @property() public defaultMode?: LightPickerMode; + @property({ attribute: false }) public stateObj!: LightEntity; @state() private _cwSliderValue?: number; @@ -65,16 +60,6 @@ class LightColorPicker extends LitElement { @state() private _hsPickerValue?: [number, number]; - @state() private _ctPickerValue?: number; - - @state() private _mode?: LightPickerMode; - - @state() private _modes: LightPickerMode[] = []; - - get stateObj() { - return this.hass.states[this.entityId] as LightEntity | undefined; - } - protected render() { if (!this.stateObj) { return nothing; @@ -100,135 +85,89 @@ class LightColorPicker extends LitElement { : ""; return html` - ${this._modes.length > 1 +
+ + + + +
+ ${supportsRgbw || supportsRgbww + ? html`` + : nothing} + ${supportsRgbw ? html` - - ${this._modes.map( - (value) => - html`` - )} - + + ` + : nothing} + ${supportsRgbww + ? html` + + ` : nothing} -
- ${this._mode === LightColorMode.COLOR_TEMP - ? html` -

- ${this._ctPickerValue ? `${this._ctPickerValue} K` : nothing} -

- - - ` - : nothing} - ${this._mode === "color" - ? html` -
- - - - -
- ${supportsRgbw || supportsRgbww - ? html`` - : nothing} - ${supportsRgbw - ? html` - - ` - : nothing} - ${supportsRgbww - ? html` - - - ` - : nothing} - ` - : nothing} -
`; } public _updateSliderValues() { const stateObj = this.stateObj; - if (stateObj?.state === "on") { + if (stateObj.state === "on") { this._brightnessAdjusted = undefined; if ( stateObj.attributes.color_mode === LightColorMode.RGB && @@ -242,10 +181,6 @@ class LightColorPicker extends LitElement { this._brightnessAdjusted = maxVal; } } - this._ctPickerValue = - stateObj.attributes.color_mode === LightColorMode.COLOR_TEMP - ? stateObj.attributes.color_temp_kelvin - : undefined; this._wvSliderValue = stateObj.attributes.color_mode === LightColorMode.RGBW && @@ -273,8 +208,7 @@ class LightColorPicker extends LitElement { ? rgb2hs(currentRgbColor.slice(0, 3) as [number, number, number]) : undefined; } else { - this._hsPickerValue = [0, 0]; - this._ctPickerValue = undefined; + this._hsPickerValue = undefined; this._wvSliderValue = undefined; this._cwSliderValue = undefined; this._wwSliderValue = undefined; @@ -288,43 +222,9 @@ class LightColorPicker extends LitElement { return; } - if (changedProps.has("entityId")) { - const supportsTemp = lightSupportsColorMode( - this.stateObj!, - LightColorMode.COLOR_TEMP - ); - - const supportsColor = lightSupportsColor(this.stateObj!); - - const modes: LightPickerMode[] = []; - if (supportsColor) { - modes.push("color"); - } - if (supportsTemp) { - modes.push("color_temp"); - } - - this._modes = modes; - this._mode = - this.defaultMode ?? - (this.stateObj!.attributes.color_mode - ? this.stateObj!.attributes.color_mode === LightColorMode.COLOR_TEMP - ? LightColorMode.COLOR_TEMP - : "color" - : this._modes[0]); - } - this._updateSliderValues(); } - private _handleTabChanged(ev: CustomEvent): void { - const newMode = this._modes[ev.detail.index]; - if (newMode === this._mode) { - return; - } - this._mode = newMode; - } - private _hsColorCursorMoved(ev: CustomEvent) { if (!ev.detail.value) { return; @@ -404,40 +304,6 @@ class LightColorPicker extends LitElement { this._updateColor(); } - private _ctColorCursorMoved(ev: CustomEvent) { - const ct = ev.detail.value; - - if (isNaN(ct) || this._ctPickerValue === ct) { - return; - } - - this._ctPickerValue = ct; - - this._throttleUpdateColorTemp(); - } - - private _throttleUpdateColorTemp = throttle(() => { - this._updateColorTemp(); - }, 500); - - private _ctColorChanged(ev: CustomEvent) { - const ct = ev.detail.value; - - if (isNaN(ct) || this._ctPickerValue === ct) { - return; - } - - this._ctPickerValue = ct; - - this._updateColorTemp(); - } - - private _updateColorTemp() { - const color_temp_kelvin = this._ctPickerValue!; - - this._applyColor({ color_temp_kelvin }); - } - private _wvSliderChanged(ev: CustomEvent) { const target = ev.target as any; let wv = Number(target.value); @@ -574,19 +440,12 @@ class LightColorPicker extends LitElement { display: flex; flex-direction: column; } - .content { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 24px; - flex: 1; - } .native-color-picker { position: absolute; top: 0; right: 0; + z-index: 1; } .native-color-picker ha-svg-icon { @@ -639,37 +498,18 @@ class LightColorPicker extends LitElement { .color-container { position: relative; - max-width: 300px; - min-width: 200px; - margin: 0 0 44px 0; - padding-top: 44px; } ha-hs-color-picker { - width: 100%; - } - - ha-temp-color-picker { - max-width: 300px; - min-width: 200px; - margin: 20px 0 44px 0; + height: 45vh; + max-height: 320px; + min-height: 200px; } ha-labeled-slider { width: 100%; } - .color-temp-value { - font-style: normal; - font-weight: 500; - font-size: 16px; - height: 24px; - line-height: 24px; - letter-spacing: 0.1px; - margin: 0; - direction: ltr; - } - hr { border-color: var(--divider-color); border-bottom: none; @@ -682,6 +522,6 @@ class LightColorPicker extends LitElement { declare global { interface HTMLElementTagNameMap { - "light-color-picker": LightColorPicker; + "light-color-rgb-picker": LightRgbColorPicker; } } diff --git a/src/dialogs/more-info/components/lights/light-color-temp-picker.ts b/src/dialogs/more-info/components/lights/light-color-temp-picker.ts new file mode 100644 index 0000000000..4543c0dc88 --- /dev/null +++ b/src/dialogs/more-info/components/lights/light-color-temp-picker.ts @@ -0,0 +1,146 @@ +import { + css, + CSSResultGroup, + html, + LitElement, + nothing, + PropertyValues, +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { throttle } from "../../../../common/util/throttle"; +import "../../../../components/ha-temp-color-picker"; +import { + LightColor, + LightColorMode, + LightEntity, +} from "../../../../data/light"; +import { HomeAssistant } from "../../../../types"; + +declare global { + interface HASSDomEvents { + "color-changed": LightColor; + "color-hovered": LightColor | undefined; + } +} + +@customElement("light-color-temp-picker") +class LightColorTempPicker extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ attribute: false }) public stateObj!: LightEntity; + + @state() private _ctPickerValue?: number; + + protected render() { + if (!this.stateObj) { + return nothing; + } + + return html` + + + `; + } + + public _updateSliderValues() { + const stateObj = this.stateObj; + + if (stateObj.state === "on") { + this._ctPickerValue = + stateObj.attributes.color_mode === LightColorMode.COLOR_TEMP + ? stateObj.attributes.color_temp_kelvin + : undefined; + } else { + this._ctPickerValue = undefined; + } + } + + public willUpdate(changedProps: PropertyValues) { + super.willUpdate(changedProps); + + if (!changedProps.has("stateObj")) { + return; + } + + this._updateSliderValues(); + } + + private _ctColorCursorMoved(ev: CustomEvent) { + const ct = ev.detail.value; + + if (isNaN(ct) || this._ctPickerValue === ct) { + return; + } + + this._ctPickerValue = ct; + + fireEvent(this, "color-hovered", { + color_temp_kelvin: ct, + }); + + this._throttleUpdateColorTemp(); + } + + private _throttleUpdateColorTemp = throttle(() => { + this._updateColorTemp(); + }, 500); + + private _ctColorChanged(ev: CustomEvent) { + const ct = ev.detail.value; + + fireEvent(this, "color-hovered", undefined); + + if (isNaN(ct) || this._ctPickerValue === ct) { + return; + } + + this._ctPickerValue = ct; + + this._updateColorTemp(); + } + + private _updateColorTemp() { + const color_temp_kelvin = this._ctPickerValue!; + + this._applyColor({ color_temp_kelvin }); + } + + private _applyColor(color: LightColor, params?: Record) { + fireEvent(this, "color-changed", color); + this.hass.callService("light", "turn_on", { + entity_id: this.stateObj!.entity_id, + ...color, + ...params, + }); + } + + static get styles(): CSSResultGroup { + return [ + css` + :host { + display: flex; + flex-direction: column; + } + + ha-temp-color-picker { + height: 45vh; + max-height: 320px; + min-height: 200px; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "light-color-temp-picker": LightColorTempPicker; + } +} diff --git a/src/dialogs/more-info/components/lights/show-dialog-light-color-favorite.ts b/src/dialogs/more-info/components/lights/show-dialog-light-color-favorite.ts index 28f0af8622..d8bc865093 100644 --- a/src/dialogs/more-info/components/lights/show-dialog-light-color-favorite.ts +++ b/src/dialogs/more-info/components/lights/show-dialog-light-color-favorite.ts @@ -1,7 +1,7 @@ import { fireEvent } from "../../../../common/dom/fire_event"; import { ExtEntityRegistryEntry } from "../../../../data/entity_registry"; import { LightColor } from "../../../../data/light"; -import type { LightPickerMode } from "./light-color-picker"; +import type { LightPickerMode } from "./dialog-light-color-favorite"; export interface LightColorFavoriteDialogParams { entry: ExtEntityRegistryEntry; diff --git a/src/dialogs/more-info/components/lights/show-view-light-color-picker.ts b/src/dialogs/more-info/components/lights/show-view-light-color-picker.ts deleted file mode 100644 index 5a2bd40fa1..0000000000 --- a/src/dialogs/more-info/components/lights/show-view-light-color-picker.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { fireEvent } from "../../../../common/dom/fire_event"; -import type { LightPickerMode } from "./light-color-picker"; - -export interface LightColorPickerViewParams { - entityId: string; - defaultMode: LightPickerMode; -} - -export const loadLightColorPickerView = () => - import("./ha-more-info-view-light-color-picker"); - -export const showLightColorPickerView = ( - element: HTMLElement, - title: string, - params: LightColorPickerViewParams -): void => { - fireEvent(element, "show-child-view", { - viewTag: "ha-more-info-view-light-color-picker", - viewImport: loadLightColorPickerView, - viewTitle: title, - viewParams: params, - }); -}; diff --git a/src/dialogs/more-info/controls/more-info-light.ts b/src/dialogs/more-info/controls/more-info-light.ts index 45597b228d..730175c8dd 100644 --- a/src/dialogs/more-info/controls/more-info-light.ts +++ b/src/dialogs/more-info/controls/more-info-light.ts @@ -1,5 +1,6 @@ import "@material/mwc-list/mwc-list-item"; import { + mdiBrightness6, mdiCreation, mdiFileWordBox, mdiLightbulb, @@ -24,6 +25,8 @@ import { supportsFeature } from "../../../common/entity/supports-feature"; import { blankBeforePercent } from "../../../common/translations/blank_before_percent"; import "../../../components/ha-attributes"; import "../../../components/ha-button-menu"; +import "../../../components/ha-icon-button-group"; +import "../../../components/ha-icon-button-toggle"; import "../../../components/ha-outlined-button"; import "../../../components/ha-outlined-icon-button"; import "../../../components/ha-select"; @@ -31,6 +34,7 @@ import { UNAVAILABLE } from "../../../data/entity"; import { ExtEntityRegistryEntry } from "../../../data/entity_registry"; import { forwardHaptic } from "../../../data/haptics"; import { + formatTempColor, LightColorMode, LightEntity, LightEntityFeature, @@ -46,7 +50,10 @@ import "../components/ha-more-info-toggle"; import "../components/lights/ha-favorite-color-button"; import "../components/lights/ha-more-info-light-brightness"; import "../components/lights/ha-more-info-light-favorite-colors"; -import { showLightColorPickerView } from "../components/lights/show-view-light-color-picker"; +import "../components/lights/light-color-rgb-picker"; +import "../components/lights/light-color-temp-picker"; + +type MainControl = "brightness" | "color_temp" | "color"; @customElement("more-info-light") class MoreInfoLight extends LitElement { @@ -62,12 +69,24 @@ class MoreInfoLight extends LitElement { @state() private _selectedBrightness?: number; + @state() private _colorTempPreview?: number; + + @state() private _mainControl: MainControl = "brightness"; + private _brightnessChanged(ev) { const value = (ev.detail as any).value; if (isNaN(value)) return; this._selectedBrightness = value; } + private _tempColorHovered(ev: CustomEvent) { + if (ev.detail && "color_temp_kelvin" in ev.detail) { + this._colorTempPreview = ev.detail.color_temp_kelvin; + } else { + this._colorTempPreview = undefined; + } + } + protected updated(changedProps: PropertyValues): void { if (changedProps.has("stateObj")) { this._selectedBrightness = this.stateObj?.attributes.brightness @@ -77,6 +96,28 @@ class MoreInfoLight extends LitElement { } } + private _setMainControl(ev: any) { + ev.stopPropagation(); + this._mainControl = ev.currentTarget.control; + } + + private _resetMainControl(ev: any) { + ev.stopPropagation(); + this._mainControl = "brightness"; + } + + private get _stateOverride() { + if (this._colorTempPreview) { + return formatTempColor(this._colorTempPreview); + } + if (this._selectedBrightness) { + return `${Math.round(this._selectedBrightness)}${blankBeforePercent( + this.hass!.locale + )}%`; + } + return undefined; + } + protected render() { if (!this.hass || !this.stateObj) { return nothing; @@ -106,47 +147,60 @@ class MoreInfoLight extends LitElement { (this.entry.options?.light?.favorite_colors == null || this.entry.options.light.favorite_colors.length > 0); - const stateOverride = this._selectedBrightness - ? `${Math.round(this._selectedBrightness)}${blankBeforePercent( - this.hass!.locale - )}%` - : undefined; - return html`
- ${supportsBrightness + ${!supportsBrightness ? html` - - - ` - : html` - `} + ` + : nothing} ${supportsColorTemp || supportsColor || supportsBrightness ? html` -
+ ${supportsBrightness && this._mainControl === "brightness" + ? html` + + + ` + : nothing} + ${supportsColor && this._mainControl === "color" + ? html` + + + ` + : nothing} + ${supportsColorTemp && this._mainControl === "color_temp" + ? html` + + + ` + : nothing} + ${supportsBrightness ? html` ` : nothing} + ${supportsColor || supportsColorTemp + ? html` +
+ + + + ` + : nothing} ${supportsColor ? html` - - + ` : nothing} ${supportsColorTemp ? html` - - + ` : nothing} ${supportsWhite ? html` +
` : nothing} -
+ ${this.entry && lightSupportsFavoriteColors(this.stateObj) && (this.editMode || hasFavoriteColors) @@ -216,6 +281,7 @@ class MoreInfoLight extends LitElement { .stateObj=${this.stateObj} .entry=${this.entry} .editMode=${this.editMode} + @favorite-color-edit-started=${this._resetMainControl} > ` @@ -291,19 +357,6 @@ class MoreInfoLight extends LitElement { }); }; - private _showLightColorPickerView = (ev) => { - showLightColorPickerView( - this, - this.hass.localize( - "ui.dialogs.more_info_control.light.color_picker.title" - ), - { - entityId: this.stateObj!.entity_id, - defaultMode: ev.currentTarget.mode, - } - ); - }; - private _setWhite = () => { this.hass.callService("light", "turn_on", { entity_id: this.stateObj!.entity_id, @@ -347,9 +400,6 @@ class MoreInfoLight extends LitElement { flex: none; border-radius: 15px; } - ha-icon-button[disabled] .wheel { - filter: grayscale(1) opacity(0.5); - } .wheel.color { background-image: url("/static/images/color_wheel.png"); background-size: cover; @@ -362,6 +412,9 @@ class MoreInfoLight extends LitElement { rgb(255, 160, 0) 100% ); } + *[disabled] .wheel { + filter: grayscale(1) opacity(0.5); + } .buttons { flex-wrap: wrap; max-width: 250px; diff --git a/src/translations/en.json b/src/translations/en.json index 2b46e38cca..125ac84814 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -929,8 +929,8 @@ "light": { "edit_mode": "Edit favorite colors", "toggle": "Toggle", - "change_color": "Change color", - "change_color_temp": "Change color temperature", + "color": "Color", + "color_temp": "Temperature", "set_white": "Set white", "select_effect": "Select effect", "brightness": "Brightness",