From 3838d760945a5657f37d14b0e45c151901ba8156 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Wed, 10 May 2023 14:34:19 +0200 Subject: [PATCH] Ha dialog header (#16485) --- src/components/ha-dialog-header.ts | 81 ++++++ src/components/ha-dialog.ts | 16 +- src/components/ha-textfield.ts | 14 +- .../media-player/dialog-media-manage.ts | 33 +-- .../dialog-media-player-browse.ts | 24 +- src/dialogs/more-info/ha-more-info-dialog.ts | 247 ++++++++---------- .../ha-voice-command-dialog.ts | 138 +++++----- .../zha/dialog-zha-manage-zigbee-device.ts | 79 ++---- .../config/logs/dialog-system-log-detail.ts | 18 +- .../voice-assistants/dialog-expose-entity.ts | 138 ++++------ .../dialog-voice-assistant-pipeline-detail.ts | 17 +- .../voice-assistants/dialog-voice-settings.ts | 16 +- .../card-editor/hui-dialog-create-card.ts | 35 +-- .../card-editor/hui-dialog-edit-card.ts | 58 ++-- .../view-editor/hui-dialog-edit-view.ts | 83 ++---- 15 files changed, 450 insertions(+), 547 deletions(-) create mode 100644 src/components/ha-dialog-header.ts diff --git a/src/components/ha-dialog-header.ts b/src/components/ha-dialog-header.ts new file mode 100644 index 0000000000..659a2124b1 --- /dev/null +++ b/src/components/ha-dialog-header.ts @@ -0,0 +1,81 @@ +import { css, html, LitElement } from "lit"; +import { customElement } from "lit/decorators"; + +@customElement("ha-dialog-header") +export class HaDialogHeader extends LitElement { + protected render() { + return html` +
+
+
+ +
+
+ +
+
+ +
+
+ +
+ `; + } + + static get styles() { + return [ + css` + :host { + display: block; + } + :host([show-border]) { + border-bottom: 1px solid + var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12)); + } + .header-bar { + display: flex; + flex-direction: row; + align-items: flex-start; + padding: 4px; + box-sizing: border-box; + } + .header-title { + flex: 1; + font-size: 22px; + line-height: 28px; + font-weight: 400; + padding: 10px 4px; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + @media all and (min-width: 450px) and (min-height: 500px) { + .header-bar { + padding: 12px; + } + } + .header-navigation-icon { + flex: none; + min-width: 8px; + height: 100%; + display: flex; + flex-direction: row; + } + .header-action-items { + flex: none; + min-width: 8px; + height: 100%; + display: flex; + flex-direction: row; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-dialog-header": HaDialogHeader; + } +} diff --git a/src/components/ha-dialog.ts b/src/components/ha-dialog.ts index 3175d393ba..b6ce255eeb 100644 --- a/src/components/ha-dialog.ts +++ b/src/components/ha-dialog.ts @@ -63,6 +63,10 @@ export class HaDialog extends DialogBase { static override styles = [ styles, css` + :host([scrolled]) ::slotted(ha-dialog-header) { + border-bottom: 1px solid + var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12)); + } .mdc-dialog { --mdc-dialog-scroll-divider-color: var( --dialog-scroll-divider-color, @@ -119,13 +123,6 @@ export class HaDialog extends DialogBase { display: flex; flex-direction: column; } - .header_button { - position: absolute; - right: 16px; - top: 14px; - text-decoration: none; - color: inherit; - } .header_title { margin-right: 32px; margin-inline-end: 32px; @@ -133,6 +130,11 @@ export class HaDialog extends DialogBase { direction: var(--direction); } .header_button { + position: absolute; + right: 16px; + top: 14px; + text-decoration: none; + color: inherit; inset-inline-start: initial; inset-inline-end: 16px; direction: var(--direction); diff --git a/src/components/ha-textfield.ts b/src/components/ha-textfield.ts index 6264784e81..e411469252 100644 --- a/src/components/ha-textfield.ts +++ b/src/components/ha-textfield.ts @@ -78,6 +78,12 @@ export class HaTextField extends TextFieldBase { direction: var(--direction); } + .mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon { + padding-left: var(--text-field-suffix-padding-left, 0px); + padding-right: var(--text-field-suffix-padding-right, 0px); + padding-inline-start: var(--text-field-suffix-padding-left, 0px); + padding-inline-end: var(--text-field-suffix-padding-right, 0px); + } .mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__affix--suffix { color: var(--secondary-text-color); @@ -137,8 +143,12 @@ export class HaTextField extends TextFieldBase { .mdc-text-field--with-leading-icon.mdc-text-field--filled .mdc-floating-label { - max-width: calc(100% - 48px); - inset-inline-start: 48px !important; + max-width: calc( + 100% - 48px - var(--text-field-suffix-padding-left, 0px) + ); + inset-inline-start: calc( + 48px + var(--text-field-suffix-padding-left, 0px) + ) !important; inset-inline-end: initial !important; direction: var(--direction); } diff --git a/src/components/media-player/dialog-media-manage.ts b/src/components/media-player/dialog-media-manage.ts index 100cc89ccc..684187dfa5 100644 --- a/src/components/media-player/dialog-media-manage.ts +++ b/src/components/media-player/dialog-media-manage.ts @@ -18,10 +18,11 @@ import { import { showConfirmationDialog } from "../../dialogs/generic/show-dialog-box"; import { haStyleDialog } from "../../resources/styles"; import type { HomeAssistant } from "../../types"; +import "../ha-button"; import "../ha-check-list-item"; import "../ha-circular-progress"; import "../ha-dialog"; -import "../ha-header-bar"; +import "../ha-dialog-header"; import "../ha-svg-icon"; import "./ha-media-player-browse"; import "./ha-media-upload-button"; @@ -80,7 +81,7 @@ class DialogMediaManage extends LitElement { .heading=${this._params.currentItem.title} @closed=${this.closeDialog} > - + ${this._selected.size === 0 ? html` @@ -104,14 +105,13 @@ class DialogMediaManage extends LitElement { .label=${this.hass.localize("ui.dialogs.generic.close")} .path=${mdiClose} dialogAction="close" - slot="actionItems" - class="header_button" + slot="navigationIcon" dir=${computeRTLDirection(this.hass)} > `} ` : html` - - + ${this._deleting ? "" : html` - - + `} `} - + ${!this._currentItem ? html`
@@ -290,16 +290,11 @@ class DialogMediaManage extends LitElement { } } - ha-header-bar { - --mdc-theme-on-primary: var(--primary-text-color); - --mdc-theme-primary: var(--mdc-theme-surface); - flex-shrink: 0; - border-bottom: 1px solid var(--divider-color, rgba(0, 0, 0, 0.12)); - } - - ha-media-upload-button, - mwc-button { - --mdc-theme-primary: var(--mdc-theme-on-primary); + ha-dialog-header ha-media-upload-button, + ha-dialog-header ha-button { + --mdc-theme-primary: var(--primary-text-color); + margin: 6px; + display: block; } mwc-list { diff --git a/src/components/media-player/dialog-media-player-browse.ts b/src/components/media-player/dialog-media-player-browse.ts index 3d8e3fd508..dd51190b43 100644 --- a/src/components/media-player/dialog-media-player-browse.ts +++ b/src/components/media-player/dialog-media-player-browse.ts @@ -2,7 +2,6 @@ import { mdiArrowLeft, mdiClose } from "@mdi/js"; import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; import { customElement, property, query, state } from "lit/decorators"; import { fireEvent, HASSDomEvent } from "../../common/dom/fire_event"; -import { computeRTLDirection } from "../../common/util/compute_rtl"; import type { MediaPickedEvent, MediaPlayerBrowseAction, @@ -11,7 +10,7 @@ import type { import { haStyleDialog } from "../../resources/styles"; import type { HomeAssistant } from "../../types"; import "../ha-dialog"; -import "../ha-header-bar"; +import "../ha-dialog-header"; import "./ha-media-manage-button"; import "./ha-media-player-browse"; import type { @@ -68,7 +67,7 @@ class DialogMediaPlayerBrowse extends LitElement { : this._currentItem.title} @closed=${this.closeDialog} > - + ${this._navigateIds.length > 1 ? html` ` - : ""} + : nothing} ${!this._currentItem ? this.hass.localize( @@ -97,10 +96,8 @@ class DialogMediaPlayerBrowse extends LitElement { .path=${mdiClose} dialogAction="close" slot="actionItems" - class="header_button" - dir=${computeRTLDirection(this.hass)} > - + -
- - ${isInfoView - ? html` - - ` - : html` - - `} - ${!isInfoView || !isNewMoreInfo - ? html`
+ + ${isInfoView + ? html` + + ` + : html` + + `} + ${!isInfoView || !isNewMoreInfo + ? html` + ${title} -
` - : nothing} - ${isInfoView - ? html` - ${this.shouldShowHistory(domain) - ? html` + + ` + : nothing} + ${isInfoView + ? html` + ${this.shouldShowHistory(domain) + ? html` + + ` + : nothing} + ${isAdmin + ? html` + + - ` - : nothing} - ${isAdmin - ? html` - - - - ${deviceId - ? html` - - ${this.hass.localize( - "ui.dialogs.more_info_control.device_info" - )} - - - ` - : nothing} - ${this.shouldShowEditIcon(domain, stateObj) - ? html` - - ${this.hass.localize( - "ui.dialogs.more_info_control.edit" - )} - - - ` - : nothing} - - ${this.hass.localize( - "ui.dialogs.more_info_control.related" - )} - - - - ` - : nothing} - ` - : nothing} -
-
+ ${deviceId + ? html` + + ${this.hass.localize( + "ui.dialogs.more_info_control.device_info" + )} + + + ` + : nothing} + ${this.shouldShowEditIcon(domain, stateObj) + ? html` + + ${this.hass.localize( + "ui.dialogs.more_info_control.edit" + )} + + + ` + : nothing} + + ${this.hass.localize( + "ui.dialogs.more_info_control.related" + )} + + + + ` + : nothing} + ` + : nothing} +
-
- - -
- ${this.hass.localize("ui.dialogs.voice_command.title")} - - - ${this._pipeline?.name} - - - ${this._pipelines?.map( - (pipeline) => html` - ${pipeline.name}${pipeline.id === this._preferredPipeline - ? html` - - ` - : nothing} - ` - )} - ${this.hass.user?.is_admin - ? html`
  • - ${this.hass.localize( - "ui.dialogs.voice_command.manage_assistants" - )}` - : nothing} -
    -
    - + + + + ${this._pipeline?.name} + + + ${this._pipelines?.map( + (pipeline) => html` + ${pipeline.name}${pipeline.id === this._preferredPipeline + ? html` + + ` + : nothing} + ` + )} + ${this.hass.user?.is_admin + ? html`
  • + ${this.hass.localize( + "ui.dialogs.voice_command.manage_assistants" + )}` + : nothing} + +
    + + + +
    ${this._conversation!.map( @@ -645,18 +640,13 @@ export class HaVoiceCommandDialog extends LitElement { --mdc-dialog-max-height: 500px; --dialog-content-padding: 0; } - ha-header-bar { - --mdc-theme-on-primary: var(--primary-text-color); - --mdc-theme-primary: var(--mdc-theme-surface); - --header-height: 64px; - } - ha-header-bar a { + ha-dialog-header a { color: var(--primary-text-color); } div[slot="title"] { display: flex; flex-direction: column; - margin-top: 8px; + margin: -4px 0; } ha-button-menu { --mdc-theme-on-primary: var(--text-primary-color); diff --git a/src/panels/config/integrations/integration-panels/zha/dialog-zha-manage-zigbee-device.ts b/src/panels/config/integrations/integration-panels/zha/dialog-zha-manage-zigbee-device.ts index a2e7c083b4..b9686c75c0 100644 --- a/src/panels/config/integrations/integration-panels/zha/dialog-zha-manage-zigbee-device.ts +++ b/src/panels/config/integrations/integration-panels/zha/dialog-zha-manage-zigbee-device.ts @@ -6,16 +6,16 @@ import { CSSResultGroup, html, LitElement, - PropertyValues, nothing, + PropertyValues, } from "lit"; import { customElement, property, state } from "lit/decorators"; import { cache } from "lit/directives/cache"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/ha-code-editor"; -import { createCloseHeading } from "../../../../../components/ha-dialog"; -import "../../../../../components/ha-header-bar"; +import "../../../../../components/ha-dialog"; +import "../../../../../components/ha-dialog-header"; import { fetchBindableDevices, fetchGroups, @@ -99,32 +99,22 @@ class DialogZHAManageZigbeeDevice extends LitElement { open hideActions @closed=${this.closeDialog} - .heading=${createCloseHeading( - this.hass, - this.hass.localize("ui.dialogs.zha_manage_device.heading") - )} + .heading=${this.hass.localize("ui.dialogs.zha_manage_device.heading")} > -
    - - -
    - ${this.hass.localize("ui.dialogs.zha_manage_device.heading")} -
    -
    + + + + ${this.hass.localize("ui.dialogs.zha_manage_device.heading")} + -
    - +
    ${cache( this._currTab === "clusters" @@ -238,27 +227,9 @@ class DialogZHAManageZigbeeDevice extends LitElement { --vertical-align-dialog: flex-start; } - ha-header-bar { - --mdc-theme-on-primary: var(--primary-text-color); - --mdc-theme-primary: var(--mdc-theme-surface); - flex-shrink: 0; - display: block; - } .content { outline: none; } - @media all and (max-width: 450px), all and (max-height: 500px) { - ha-header-bar { - --mdc-theme-primary: var(--app-header-background-color); - --mdc-theme-on-primary: var(--app-header-text-color, white); - border-bottom: none; - } - } - - .heading { - border-bottom: 1px solid - var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12)); - } @media all and (min-width: 600px) and (min-height: 501px) { ha-dialog { @@ -267,18 +238,6 @@ class DialogZHAManageZigbeeDevice extends LitElement { --dialog-surface-margin-top: 40px; --mdc-dialog-max-height: calc(100% - 72px); } - - .main-title { - overflow: hidden; - text-overflow: ellipsis; - cursor: default; - } - - :host([large]) ha-dialog, - ha-dialog[data-domain="camera"] { - --mdc-dialog-min-width: 90vw; - --mdc-dialog-max-width: 90vw; - } } `, ]; diff --git a/src/panels/config/logs/dialog-system-log-detail.ts b/src/panels/config/logs/dialog-system-log-detail.ts index 65e54e7e4b..49891035ef 100644 --- a/src/panels/config/logs/dialog-system-log-detail.ts +++ b/src/panels/config/logs/dialog-system-log-detail.ts @@ -1,12 +1,12 @@ -import { mdiClose, mdiContentCopy } from "@mdi/js"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip"; +import { mdiClose, mdiContentCopy } from "@mdi/js"; import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; import { property, state } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; import { copyToClipboard } from "../../../common/util/copy-clipboard"; import "../../../components/ha-alert"; import "../../../components/ha-dialog"; -import "../../../components/ha-header-bar"; +import "../../../components/ha-dialog-header"; import "../../../components/ha-icon-button"; import "../../../components/ha-svg-icon"; import { @@ -79,14 +79,14 @@ class DialogSystemLogDetail extends LitElement { return html` - + - ${title} + ${title} - + ${this.isCustomIntegration ? html` ${this.hass.localize( @@ -235,14 +235,6 @@ class DialogSystemLogDetail extends LitElement { color: var(--warning-color); } - ha-header-bar { - --mdc-theme-on-primary: var(--primary-text-color); - --mdc-theme-primary: var(--mdc-theme-surface); - flex-shrink: 0; - border-bottom: 1px solid - var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12)); - } - @media all and (min-width: 451px) and (min-height: 501px) { ha-dialog { --mdc-dialog-max-width: 90vw; diff --git a/src/panels/config/voice-assistants/dialog-expose-entity.ts b/src/panels/config/voice-assistants/dialog-expose-entity.ts index 17c56b2b85..97f94d90ae 100644 --- a/src/panels/config/voice-assistants/dialog-expose-entity.ts +++ b/src/panels/config/voice-assistants/dialog-expose-entity.ts @@ -53,31 +53,32 @@ class DialogExposeEntity extends LitElement { return html` -
    -

    - ${header}${this.hass.localize( + +

    + ${header} + + ${this.hass.localize( "ui.panel.config.voice_assistants.expose.expose_dialog.expose_to", { assistants: this._params.filterAssistants .map((ass) => voiceAssistants[ass].name) .join(", "), } - )} + )} +

    -

    + - + -
    ${title}
    + ${title} ${this._params.pipeline?.id ? html` ` : nothing} -
    +
    ${this._error ? html`${this._error}` @@ -298,15 +298,6 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement { return [ haStyleDialog, css` - ha-header-bar { - --mdc-theme-on-primary: var(--primary-text-color); - --mdc-theme-primary: var(--mdc-theme-surface); - display: block; - } - .main-title { - overflow: hidden; - text-overflow: ellipsis; - } assist-pipeline-detail-config, assist-pipeline-detail-conversation, assist-pipeline-detail-stt { diff --git a/src/panels/config/voice-assistants/dialog-voice-settings.ts b/src/panels/config/voice-assistants/dialog-voice-settings.ts index 361b595390..f8c85ab95e 100644 --- a/src/panels/config/voice-assistants/dialog-voice-settings.ts +++ b/src/panels/config/voice-assistants/dialog-voice-settings.ts @@ -4,6 +4,7 @@ import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; import { computeStateName } from "../../../common/entity/compute_state_name"; +import "../../../components/ha-dialog-header"; import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog"; import { haStyle, haStyleDialog } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; @@ -43,14 +44,14 @@ class DialogVoiceSettings extends LitElement { return html` - + -
    ${title}
    + ${title} -
    +
    -
    - - ${title} - + + + ${title} -
    + ${cache( this._currTabIndex === 0 ? html` @@ -171,14 +176,6 @@ export class HuiCreateDialogCard --dialog-content-padding: 0; } - ha-header-bar { - --mdc-theme-on-primary: var(--primary-text-color); - --mdc-theme-primary: var(--mdc-theme-surface); - flex-shrink: 0; - border-bottom: 1px solid - var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12)); - } - @media (min-width: 1200px) { ha-dialog { --mdc-dialog-max-width: calc(100% - 32px); @@ -186,16 +183,6 @@ export class HuiCreateDialogCard } } - .header_button { - color: inherit; - text-decoration: none; - } - - mwc-tab-bar { - border-bottom: 1px solid - var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12)); - } - hui-card-picker { --card-picker-search-shape: 0; --card-picker-search-margin: -2px -24px 0; diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts index c654dc3358..f881cb6f57 100644 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts @@ -1,12 +1,12 @@ -import { mdiHelpCircle } from "@mdi/js"; +import { mdiClose, mdiHelpCircle } from "@mdi/js"; import deepFreeze from "deep-freeze"; import { css, CSSResultGroup, html, LitElement, - PropertyValues, nothing, + PropertyValues, } from "lit"; import { customElement, property, query, state } from "lit/decorators"; import type { HASSDomEvent } from "../../../../common/dom/fire_event"; @@ -14,7 +14,7 @@ import { fireEvent } from "../../../../common/dom/fire_event"; import { computeRTLDirection } from "../../../../common/util/compute_rtl"; import "../../../../components/ha-circular-progress"; import "../../../../components/ha-dialog"; -import "../../../../components/ha-header-bar"; +import "../../../../components/ha-dialog-header"; import "../../../../components/ha-icon-button"; import type { LovelaceCardConfig, @@ -178,26 +178,30 @@ export class HuiDialogEditCard @opened=${this._opened} .heading=${heading} > -
    - -
    ${heading}
    - ${this._documentationURL !== undefined - ? html` - - - - ` - : ""} -
    -
    + + + ${heading} + ${this._documentationURL !== undefined + ? html` + + + + ` + : nothing} +
    -
    -

    ${this._viewConfigTitle}

    + + +

    ${this._viewConfigTitle}

    ` : ""} -
    + ${content} ${this._params.viewIndex !== undefined ? html` @@ -473,53 +480,30 @@ export class HuiDialogEditView extends LitElement { return [ haStyleDialog, css` + ha-dialog { + /* Set the top top of the dialog to a fixed position, so it doesnt jump when the content changes size */ + --vertical-align-dialog: flex-start; + --dialog-surface-margin-top: 40px; + } + + @media all and (max-width: 450px), all and (max-height: 500px) { + /* When in fullscreen dialog should be attached to top */ + ha-dialog { + --dialog-surface-margin-top: 0px; + } + } ha-dialog.yaml-mode { --dialog-content-padding: 0; } h2 { - display: block; - color: var(--primary-text-color); - line-height: normal; - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - font-family: Roboto, sans-serif; - font-family: var( - --mdc-typography-headline6-font-family, - var(--mdc-typography-font-family, Roboto, sans-serif) - ); - font-size: 1.25rem; - font-size: var(--mdc-typography-headline6-font-size, 1.25rem); - line-height: 2rem; - line-height: var(--mdc-typography-headline6-line-height, 2rem); - font-weight: 500; - font-weight: var(--mdc-typography-headline6-font-weight, 500); - letter-spacing: 0.0125em; - letter-spacing: var( - --mdc-typography-headline6-letter-spacing, - 0.0125em - ); - text-decoration: inherit; - text-decoration: var( - --mdc-typography-headline6-text-decoration, - inherit - ); - text-transform: inherit; - text-transform: var( - --mdc-typography-headline6-text-transform, - inherit - ); - position: relative; - flex-shrink: 0; - box-sizing: border-box; margin: 0; - padding: 20px 24px 9px; - border-bottom: 1px solid transparent; + font-size: inherit; + font-weight: inherit; } paper-tabs { --paper-tabs-selection-bar-color: var(--primary-color); color: var(--primary-text-color); text-transform: uppercase; - border-bottom: 1px solid rgba(0, 0, 0, 0.1); padding: 0 20px; } mwc-button.warning { @@ -531,19 +515,6 @@ export class HuiDialogEditView extends LitElement { ha-circular-progress[active] { display: block; } - ha-button-menu { - color: var(--secondary-text-color); - position: absolute; - right: 16px; - top: 14px; - inset-inline-end: 16px; - inset-inline-start: initial; - direction: var(--direction); - } - ha-button-menu, - ha-icon-button { - --mdc-theme-text-primary-on-background: var(--primary-text-color); - } .selected_menu_item { color: var(--primary-color); }