diff --git a/src/panels/config/integrations/ha-integration-card.ts b/src/panels/config/integrations/ha-integration-card.ts index 274fc92ed4..7866cd8343 100644 --- a/src/panels/config/integrations/ha-integration-card.ts +++ b/src/panels/config/integrations/ha-integration-card.ts @@ -1,19 +1,29 @@ import "@lrnwebcomponents/simple-tooltip/simple-tooltip"; import "@material/mwc-button"; import "@material/mwc-list"; +import "@material/mwc-ripple"; +import type { Ripple } from "@material/mwc-ripple"; +import { RippleHandlers } from "@material/mwc-ripple/ripple-handlers"; +import { mdiCloud, mdiPackageVariant } from "@mdi/js"; import { - mdiCogOutline, - mdiDevices, - mdiHandExtendedOutline, - mdiPuzzleOutline, - mdiShapeOutline, -} from "@mdi/js"; -import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; -import { customElement, property } from "lit/decorators"; + CSSResultGroup, + LitElement, + TemplateResult, + css, + html, + nothing, +} from "lit"; +import { + customElement, + eventOptions, + property, + queryAsync, + state, +} from "lit/decorators"; import { classMap } from "lit/directives/class-map"; import memoizeOne from "memoize-one"; +import { computeRTL } from "../../../common/util/compute_rtl"; import "../../../components/ha-card"; -import "../../../components/ha-icon-button"; import "../../../components/ha-icon-next"; import "../../../components/ha-list-item"; import "../../../components/ha-svg-icon"; @@ -47,8 +57,12 @@ export class HaIntegrationCard extends LitElement { @property() public logInfo?: IntegrationLogInfo; + @queryAsync("mwc-ripple") private _ripple!: Promise; + + @state() private _shouldRenderRipple = false; + protected render(): TemplateResult { - const state = this._getState(this.items); + const entryState = this._getState(this.items); const debugLoggingEnabled = this.logInfo && this.logInfo.level === LogSeverity.DEBUG; @@ -57,22 +71,35 @@ export class HaIntegrationCard extends LitElement { - + + ${this._shouldRenderRipple ? html`` : ""} - + > @@ -105,18 +131,14 @@ export class HaIntegrationCard extends LitElement { const services = !devices.some((device) => device.entry_type !== "service"); return html` -
+
${devices.length > 0 ? html` - - + ${this.hass.localize( `ui.panel.config.integrations.config_entry.${ services ? "services" : "devices" @@ -124,40 +146,57 @@ export class HaIntegrationCard extends LitElement { "count", devices.length )} - - + ` : entities.length > 0 ? html` - - + ${this.hass.localize( `ui.panel.config.integrations.config_entry.entities`, "count", entities.length )} - - + ` : html` - - + ${this.hass.localize( `ui.panel.config.integrations.config_entry.entries`, "count", this.items.length )} - - + `} +
+ ${this.manifest && !this.manifest.is_built_in + ? html` + + ${this.hass.localize( + "ui.panel.config.integrations.config_entry.custom_integration" + )} + ` + : nothing} + ${this.manifest && this.manifest.iot_class?.startsWith("cloud_") + ? html`
+ + ${this.hass.localize( + "ui.panel.config.integrations.config_entry.depends_on_cloud" + )} +
` + : nothing} +
`; } @@ -167,14 +206,14 @@ export class HaIntegrationCard extends LitElement { if (configEntry.length === 1) { return configEntry[0].state; } - let state: ConfigEntry["state"]; + let entryState: ConfigEntry["state"]; for (const entry of configEntry) { if (ERROR_STATES.includes(entry.state)) { return entry.state; } - state = entry.state; + entryState = entry.state; } - return state!; + return entryState!; } ); @@ -209,6 +248,36 @@ export class HaIntegrationCard extends LitElement { } ); + private _rippleHandlers: RippleHandlers = new RippleHandlers(() => { + this._shouldRenderRipple = true; + return this._ripple; + }); + + @eventOptions({ passive: true }) + private handleRippleActivate(evt?: Event) { + this._rippleHandlers.startPress(evt); + } + + private handleRippleDeactivate() { + this._rippleHandlers.endPress(); + } + + private handleRippleFocus() { + this._rippleHandlers.startFocus(); + } + + private handleRippleBlur() { + this._rippleHandlers.endFocus(); + } + + protected handleRippleMouseEnter() { + this._rippleHandlers.startHover(); + } + + protected handleRippleMouseLeave() { + this._rippleHandlers.endHover(); + } + static get styles(): CSSResultGroup { return [ haStyle, @@ -216,12 +285,25 @@ export class HaIntegrationCard extends LitElement { ha-card { display: flex; flex-direction: column; + justify-content: space-between; height: 100%; overflow: hidden; --state-color: var(--divider-color, #e0e0e0); --ha-card-border-color: var(--state-color); --state-message-color: var(--state-color); } + .ripple-anchor { + flex-grow: 1; + position: relative; + } + ha-integration-header { + height: 100%; + } + .card-actions { + display: flex; + align-items: center; + justify-content: space-between; + } .debug-logging { --state-color: var(--warning-color); --text-on-state-color: var(--primary-text-color); @@ -254,9 +336,32 @@ export class HaIntegrationCard extends LitElement { text-decoration: none; color: var(--primary-text-color); } - a ha-icon-button { + a ha-icon-next { color: var(--secondary-text-color); } + .icons { + display: flex; + } + .icon { + border-radius: 50%; + color: var(--text-primary-color); + padding: 4px; + margin-left: 8px; + } + .icon.cloud { + background: var(--info-color); + } + .icon.custom { + background: var(--warning-color); + } + .icon ha-svg-icon { + width: 16px; + height: 16px; + display: block; + } + simple-tooltip { + white-space: nowrap; + } `, ]; } diff --git a/src/panels/config/integrations/ha-integration-header.ts b/src/panels/config/integrations/ha-integration-header.ts index b151114c61..16085d5ead 100644 --- a/src/panels/config/integrations/ha-integration-header.ts +++ b/src/panels/config/integrations/ha-integration-header.ts @@ -1,11 +1,7 @@ -import "@lrnwebcomponents/simple-tooltip/simple-tooltip"; -import { mdiCloud, mdiPackageVariant } from "@mdi/js"; -import { css, html, LitElement, TemplateResult } from "lit"; +import { LitElement, TemplateResult, css, html } from "lit"; import { customElement, property } from "lit/decorators"; -import { classMap } from "lit/directives/class-map"; -import { computeRTL } from "../../../common/util/compute_rtl"; import "../../../components/ha-svg-icon"; -import { domainToName, IntegrationManifest } from "../../../data/integration"; +import { IntegrationManifest, domainToName } from "../../../data/integration"; import { HomeAssistant } from "../../../types"; import { brandsUrl } from "../../../util/brands-url"; @@ -23,8 +19,6 @@ export class HaIntegrationHeader extends LitElement { @property({ attribute: false }) public manifest?: IntegrationManifest; - @property({ attribute: false }) public debugLoggingEnabled?: boolean; - protected render(): TemplateResult { let primary: string; let secondary: string | undefined; @@ -43,31 +37,8 @@ export class HaIntegrationHeader extends LitElement { primary = domainName; } - const icons: [string, string][] = []; - - if (this.manifest) { - if (!this.manifest.is_built_in) { - icons.push([ - mdiPackageVariant, - this.hass.localize( - "ui.panel.config.integrations.config_entry.custom_integration" - ), - ]); - } - - if (this.manifest.iot_class?.startsWith("cloud_")) { - icons.push([ - mdiCloud, - this.hass.localize( - "ui.panel.config.integrations.config_entry.depends_on_cloud" - ), - ]); - } - } - return html` ${!this.banner ? "" : html``} -
- ${icons.length === 0 - ? "" - : html` -
- ${icons.map( - ([icon, description]) => html` - - - ${description} - - ` - )} -
- `}
${primary}
${secondary}
@@ -139,14 +84,13 @@ export class HaIntegrationHeader extends LitElement { .header { display: flex; position: relative; - padding-top: 0px; - padding-bottom: 8px; + padding-top: 16px; + padding-bottom: 16px; padding-inline-start: 16px; padding-inline-end: 8px; direction: var(--direction); } .header img { - margin-top: 16px; margin-inline-start: initial; margin-inline-end: 16px; width: 40px; @@ -166,11 +110,13 @@ export class HaIntegrationHeader extends LitElement { text-overflow: ellipsis; } .header-button { - margin-top: 8px; + display: flex; + align-items: center; + justify-content: center; + width: 36px; } .primary { font-size: 16px; - margin-top: 16px; font-weight: 400; word-break: break-word; color: var(--primary-text-color); @@ -179,41 +125,6 @@ export class HaIntegrationHeader extends LitElement { font-size: 14px; color: var(--secondary-text-color); } - .icons { - background: var(--warning-color); - border: 1px solid var(--card-background-color); - border-radius: 14px; - color: var(--text-primary-color); - position: absolute; - left: 40px; - top: 40px; - display: flex; - padding: 4px; - inset-inline-start: 40px; - inset-inline-end: initial; - } - .icons.cloud { - background: var(--info-color); - } - .icons.double { - background: var(--warning-color); - left: 28px; - inset-inline-start: 28px; - inset-inline-end: initial; - } - .icons ha-svg-icon { - width: 16px; - height: 16px; - display: block; - } - .icons span:not(:first-child) ha-svg-icon { - margin-left: 4px; - margin-inline-start: 4px; - margin-inline-end: inherit; - } - simple-tooltip { - white-space: nowrap; - } `; }