From dcea227f4a65a6e86746064ae8ae6d0f59cce70b Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Thu, 11 Sep 2025 14:55:07 +0200 Subject: [PATCH] Add themes variables to tile card to change border radius (#26999) --- src/components/ha-control-slider.ts | 14 ++++-- src/components/tile/ha-tile-icon.ts | 46 +++++++++++-------- .../common/card-feature-styles.ts | 4 ++ .../card-features/hui-card-features.ts | 16 ++++++- src/panels/lovelace/cards/hui-tile-card.ts | 24 +++++----- 5 files changed, 67 insertions(+), 37 deletions(-) diff --git a/src/components/ha-control-slider.ts b/src/components/ha-control-slider.ts index c158f68b7b..bcf4b4a31e 100644 --- a/src/components/ha-control-slider.ts +++ b/src/components/ha-control-slider.ts @@ -528,6 +528,10 @@ export class HaControlSlider extends LitElement { background-color: white; } .slider .slider-track-bar { + --slider-track-bar-border-radius: min( + var(--control-slider-border-radius), + var(--ha-border-radius-md) + ); top: 0; left: 0; transform: translate3d( @@ -535,7 +539,7 @@ export class HaControlSlider extends LitElement { 0, 0 ); - border-radius: 0 8px 8px 0; + border-radius: var(--slider-track-bar-border-radius); } .slider .slider-track-bar:after { top: 0; @@ -548,7 +552,6 @@ export class HaControlSlider extends LitElement { right: 0; left: initial; transform: translate3d(calc(var(--value, 0) * var(--slider-size)), 0, 0); - border-radius: 8px 0 0 8px; } .slider .slider-track-bar.end::after { right: initial; @@ -563,7 +566,6 @@ export class HaControlSlider extends LitElement { calc((1 - var(--value, 0)) * var(--slider-size)), 0 ); - border-radius: 8px 8px 0 0; } :host([vertical]) .slider .slider-track-bar:after { top: var(--handle-margin); @@ -581,7 +583,6 @@ export class HaControlSlider extends LitElement { calc((0 - var(--value, 0)) * var(--slider-size)), 0 ); - border-radius: 0 0 8px 8px; } :host([vertical]) .slider .slider-track-bar.end::after { top: initial; @@ -605,7 +606,10 @@ export class HaControlSlider extends LitElement { --cursor-size: calc(var(--control-slider-thickness) / 4); position: absolute; background-color: white; - border-radius: var(--handle-size); + border-radius: min( + var(--handle-size), + var(--control-slider-border-radius) + ); transition: left 180ms ease-in-out, bottom 180ms ease-in-out; diff --git a/src/components/tile/ha-tile-icon.ts b/src/components/tile/ha-tile-icon.ts index 5c9f29f0f2..72b8175db4 100644 --- a/src/components/tile/ha-tile-icon.ts +++ b/src/components/tile/ha-tile-icon.ts @@ -3,28 +3,35 @@ import { LitElement, css, html } from "lit"; import { customElement, property } from "lit/decorators"; import "../ha-icon"; import "../ha-svg-icon"; -import { classMap } from "lit/directives/class-map"; - -export type TileIconImageStyle = "square" | "rounded-square" | "circle"; - -export const DEFAULT_TILE_ICON_BORDER_STYLE = "circle"; +/** + * Home Assistant tile icon component + * + * @element ha-tile-icon + * + * @summary + * A tile icon component, used in tile card in Home Assistant to display an icon or image. + * + * @slot - Additional content (for example, a badge). + * @slot icon - The icon container (usually for icons). + * + * @cssprop --ha-tile-icon-border-radius - The border radius of the tile icon. defaults to `var(--ha-border-radius-pill)`. + * + * @attr {boolean} interactive - Whether the icon is interactive (hover and focus styles). + * @attr {string} image-url - The URL of the image to display instead of an icon. + */ @customElement("ha-tile-icon") export class HaTileIcon extends LitElement { @property({ type: Boolean, reflect: true }) public interactive = false; - @property({ attribute: "border-style", type: String }) - public imageStyle?: TileIconImageStyle; - - @property({ attribute: false }) + @property({ attribute: "image-url", type: String }) public imageUrl?: string; protected render(): TemplateResult { if (this.imageUrl) { - const imageStyle = this.imageStyle || DEFAULT_TILE_ICON_BORDER_STYLE; return html` -
+
@@ -44,6 +51,11 @@ export class HaTileIcon extends LitElement { --tile-icon-color: var(--disabled-color); --tile-icon-opacity: 0.2; --tile-icon-hover-opacity: 0.35; + --tile-icon-border-radius: var( + --ha-tile-icon-border-radius, + var(--ha-border-radius-pill) + ); + --tile-icon-size: 36px; --mdc-icon-size: 24px; position: relative; user-select: none; @@ -60,21 +72,15 @@ export class HaTileIcon extends LitElement { display: flex; align-items: center; justify-content: center; - width: 36px; - height: 36px; - border-radius: 18px; + width: var(--tile-icon-size); + height: var(--tile-icon-size); + border-radius: var(--tile-icon-border-radius); overflow: hidden; transition: box-shadow 180ms ease-in-out; } :host([interactive]:focus-visible) .container { box-shadow: 0 0 0 2px var(--tile-icon-color); } - .container.rounded-square { - border-radius: 8px; - } - .container.square { - border-radius: 0; - } .container.background::before { content: ""; position: absolute; diff --git a/src/panels/lovelace/card-features/common/card-feature-styles.ts b/src/panels/lovelace/card-features/common/card-feature-styles.ts index 799570cc99..60388a984d 100644 --- a/src/panels/lovelace/card-features/common/card-feature-styles.ts +++ b/src/panels/lovelace/card-features/common/card-feature-styles.ts @@ -26,8 +26,12 @@ export const cardFeatureStyles = css` --control-button-padding: 0px; } ha-control-button { + --control-button-border-radius: var(--feature-border-radius); --control-button-focus-color: var(--feature-color); } + ha-control-number-buttons { + --control-number-buttons-border-radius: var(--feature-border-radius); + } ha-control-slider { --control-slider-color: var(--feature-color); --control-slider-background: var(--feature-color); diff --git a/src/panels/lovelace/card-features/hui-card-features.ts b/src/panels/lovelace/card-features/hui-card-features.ts index 21227fe0fa..f4381d395b 100644 --- a/src/panels/lovelace/card-features/hui-card-features.ts +++ b/src/panels/lovelace/card-features/hui-card-features.ts @@ -8,6 +8,17 @@ import type { LovelaceCardFeaturePosition, } from "./types"; +/** + * Home Assistant tile icon component + * + * @element hui-card-features + * + * @summary + * A card features component, used in cards in Home Assistant to display extra features in card. + * + * @cssprop --ha-card-features-border-radius - The border radius of the card features. defaults to `var(--ha-border-radius-lg)`. + * + */ @customElement("hui-card-features") export class HuiCardFeatures extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -44,7 +55,10 @@ export class HuiCardFeatures extends LitElement { :host { --feature-color: var(--state-icon-color); --feature-height: 42px; - --feature-border-radius: 12px; + --feature-border-radius: var( + --ha-card-features-border-radius, + var(--ha-border-radius-lg) + ); --feature-button-spacing: 12px; pointer-events: none; position: relative; diff --git a/src/panels/lovelace/cards/hui-tile-card.ts b/src/panels/lovelace/cards/hui-tile-card.ts index 24b8a5d60a..5d3c33a019 100644 --- a/src/panels/lovelace/cards/hui-tile-card.ts +++ b/src/panels/lovelace/cards/hui-tile-card.ts @@ -18,17 +18,18 @@ import "../../../components/ha-state-icon"; import "../../../components/ha-svg-icon"; import "../../../components/tile/ha-tile-badge"; import "../../../components/tile/ha-tile-icon"; -import type { TileIconImageStyle } from "../../../components/tile/ha-tile-icon"; import "../../../components/tile/ha-tile-info"; import { cameraUrlWithWidthHeight } from "../../../data/camera"; import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler"; import "../../../state-display/state-display"; import type { HomeAssistant } from "../../../types"; import "../card-features/hui-card-features"; +import type { LovelaceCardFeatureContext } from "../card-features/types"; import { actionHandler } from "../common/directives/action-handler-directive"; import { findEntities } from "../common/find-entities"; import { handleAction } from "../common/handle-action"; import { hasAction } from "../common/has-action"; +import { createEntityNotFoundWarning } from "../components/hui-warning"; import type { LovelaceCard, LovelaceCardEditor, @@ -36,8 +37,6 @@ import type { } from "../types"; import { renderTileBadge } from "./tile/badges/tile-badge"; import type { TileCardConfig } from "./types"; -import type { LovelaceCardFeatureContext } from "../card-features/types"; -import { createEntityNotFoundWarning } from "../components/hui-warning"; export const getEntityDefaultTileIconAction = (entityId: string) => { const domain = computeDomain(entityId); @@ -48,11 +47,6 @@ export const getEntityDefaultTileIconAction = (entityId: string) => { return supportsIconAction ? "toggle" : "none"; }; -const DOMAIN_IMAGE_SHAPE: Record = { - update: "square", - media_player: "rounded-square", -}; - @customElement("hui-tile-card") export class HuiTileCard extends LitElement implements LovelaceCard { public static async getConfigElement(): Promise { @@ -318,10 +312,10 @@ export class HuiTileCard extends LitElement implements LovelaceCard { hasDoubleClick: hasAction(this._config!.icon_double_tap_action), })} .interactive=${this._hasIconAction} - .imageStyle=${DOMAIN_IMAGE_SHAPE[domain]} .imageUrl=${imageUrl} data-domain=${ifDefined(domain)} data-state=${ifDefined(stateObj?.state)} + class=${classMap({ image: Boolean(imageUrl) })} >