Add themes variables to tile card to change border radius (#26999)

This commit is contained in:
Paul Bottein
2025-09-11 14:55:07 +02:00
committed by GitHub
parent 1abedcd5f0
commit dcea227f4a
5 changed files with 67 additions and 37 deletions

View File

@@ -528,6 +528,10 @@ export class HaControlSlider extends LitElement {
background-color: white; background-color: white;
} }
.slider .slider-track-bar { .slider .slider-track-bar {
--slider-track-bar-border-radius: min(
var(--control-slider-border-radius),
var(--ha-border-radius-md)
);
top: 0; top: 0;
left: 0; left: 0;
transform: translate3d( transform: translate3d(
@@ -535,7 +539,7 @@ export class HaControlSlider extends LitElement {
0, 0,
0 0
); );
border-radius: 0 8px 8px 0; border-radius: var(--slider-track-bar-border-radius);
} }
.slider .slider-track-bar:after { .slider .slider-track-bar:after {
top: 0; top: 0;
@@ -548,7 +552,6 @@ export class HaControlSlider extends LitElement {
right: 0; right: 0;
left: initial; left: initial;
transform: translate3d(calc(var(--value, 0) * var(--slider-size)), 0, 0); transform: translate3d(calc(var(--value, 0) * var(--slider-size)), 0, 0);
border-radius: 8px 0 0 8px;
} }
.slider .slider-track-bar.end::after { .slider .slider-track-bar.end::after {
right: initial; right: initial;
@@ -563,7 +566,6 @@ export class HaControlSlider extends LitElement {
calc((1 - var(--value, 0)) * var(--slider-size)), calc((1 - var(--value, 0)) * var(--slider-size)),
0 0
); );
border-radius: 8px 8px 0 0;
} }
:host([vertical]) .slider .slider-track-bar:after { :host([vertical]) .slider .slider-track-bar:after {
top: var(--handle-margin); top: var(--handle-margin);
@@ -581,7 +583,6 @@ export class HaControlSlider extends LitElement {
calc((0 - var(--value, 0)) * var(--slider-size)), calc((0 - var(--value, 0)) * var(--slider-size)),
0 0
); );
border-radius: 0 0 8px 8px;
} }
:host([vertical]) .slider .slider-track-bar.end::after { :host([vertical]) .slider .slider-track-bar.end::after {
top: initial; top: initial;
@@ -605,7 +606,10 @@ export class HaControlSlider extends LitElement {
--cursor-size: calc(var(--control-slider-thickness) / 4); --cursor-size: calc(var(--control-slider-thickness) / 4);
position: absolute; position: absolute;
background-color: white; background-color: white;
border-radius: var(--handle-size); border-radius: min(
var(--handle-size),
var(--control-slider-border-radius)
);
transition: transition:
left 180ms ease-in-out, left 180ms ease-in-out,
bottom 180ms ease-in-out; bottom 180ms ease-in-out;

View File

@@ -3,28 +3,35 @@ import { LitElement, css, html } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import "../ha-icon"; import "../ha-icon";
import "../ha-svg-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") @customElement("ha-tile-icon")
export class HaTileIcon extends LitElement { export class HaTileIcon extends LitElement {
@property({ type: Boolean, reflect: true }) @property({ type: Boolean, reflect: true })
public interactive = false; public interactive = false;
@property({ attribute: "border-style", type: String }) @property({ attribute: "image-url", type: String })
public imageStyle?: TileIconImageStyle;
@property({ attribute: false })
public imageUrl?: string; public imageUrl?: string;
protected render(): TemplateResult { protected render(): TemplateResult {
if (this.imageUrl) { if (this.imageUrl) {
const imageStyle = this.imageStyle || DEFAULT_TILE_ICON_BORDER_STYLE;
return html` return html`
<div class="container ${classMap({ [imageStyle]: this.imageUrl })}"> <div class="container">
<img alt="" src=${this.imageUrl} /> <img alt="" src=${this.imageUrl} />
</div> </div>
<slot></slot> <slot></slot>
@@ -44,6 +51,11 @@ export class HaTileIcon extends LitElement {
--tile-icon-color: var(--disabled-color); --tile-icon-color: var(--disabled-color);
--tile-icon-opacity: 0.2; --tile-icon-opacity: 0.2;
--tile-icon-hover-opacity: 0.35; --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; --mdc-icon-size: 24px;
position: relative; position: relative;
user-select: none; user-select: none;
@@ -60,21 +72,15 @@ export class HaTileIcon extends LitElement {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 36px; width: var(--tile-icon-size);
height: 36px; height: var(--tile-icon-size);
border-radius: 18px; border-radius: var(--tile-icon-border-radius);
overflow: hidden; overflow: hidden;
transition: box-shadow 180ms ease-in-out; transition: box-shadow 180ms ease-in-out;
} }
:host([interactive]:focus-visible) .container { :host([interactive]:focus-visible) .container {
box-shadow: 0 0 0 2px var(--tile-icon-color); box-shadow: 0 0 0 2px var(--tile-icon-color);
} }
.container.rounded-square {
border-radius: 8px;
}
.container.square {
border-radius: 0;
}
.container.background::before { .container.background::before {
content: ""; content: "";
position: absolute; position: absolute;

View File

@@ -26,8 +26,12 @@ export const cardFeatureStyles = css`
--control-button-padding: 0px; --control-button-padding: 0px;
} }
ha-control-button { ha-control-button {
--control-button-border-radius: var(--feature-border-radius);
--control-button-focus-color: var(--feature-color); --control-button-focus-color: var(--feature-color);
} }
ha-control-number-buttons {
--control-number-buttons-border-radius: var(--feature-border-radius);
}
ha-control-slider { ha-control-slider {
--control-slider-color: var(--feature-color); --control-slider-color: var(--feature-color);
--control-slider-background: var(--feature-color); --control-slider-background: var(--feature-color);

View File

@@ -8,6 +8,17 @@ import type {
LovelaceCardFeaturePosition, LovelaceCardFeaturePosition,
} from "./types"; } 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") @customElement("hui-card-features")
export class HuiCardFeatures extends LitElement { export class HuiCardFeatures extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@@ -44,7 +55,10 @@ export class HuiCardFeatures extends LitElement {
:host { :host {
--feature-color: var(--state-icon-color); --feature-color: var(--state-icon-color);
--feature-height: 42px; --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; --feature-button-spacing: 12px;
pointer-events: none; pointer-events: none;
position: relative; position: relative;

View File

@@ -18,17 +18,18 @@ import "../../../components/ha-state-icon";
import "../../../components/ha-svg-icon"; import "../../../components/ha-svg-icon";
import "../../../components/tile/ha-tile-badge"; import "../../../components/tile/ha-tile-badge";
import "../../../components/tile/ha-tile-icon"; import "../../../components/tile/ha-tile-icon";
import type { TileIconImageStyle } from "../../../components/tile/ha-tile-icon";
import "../../../components/tile/ha-tile-info"; import "../../../components/tile/ha-tile-info";
import { cameraUrlWithWidthHeight } from "../../../data/camera"; import { cameraUrlWithWidthHeight } from "../../../data/camera";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler"; import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import "../../../state-display/state-display"; import "../../../state-display/state-display";
import type { HomeAssistant } from "../../../types"; import type { HomeAssistant } from "../../../types";
import "../card-features/hui-card-features"; import "../card-features/hui-card-features";
import type { LovelaceCardFeatureContext } from "../card-features/types";
import { actionHandler } from "../common/directives/action-handler-directive"; import { actionHandler } from "../common/directives/action-handler-directive";
import { findEntities } from "../common/find-entities"; import { findEntities } from "../common/find-entities";
import { handleAction } from "../common/handle-action"; import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action"; import { hasAction } from "../common/has-action";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import type { import type {
LovelaceCard, LovelaceCard,
LovelaceCardEditor, LovelaceCardEditor,
@@ -36,8 +37,6 @@ import type {
} from "../types"; } from "../types";
import { renderTileBadge } from "./tile/badges/tile-badge"; import { renderTileBadge } from "./tile/badges/tile-badge";
import type { TileCardConfig } from "./types"; import type { TileCardConfig } from "./types";
import type { LovelaceCardFeatureContext } from "../card-features/types";
import { createEntityNotFoundWarning } from "../components/hui-warning";
export const getEntityDefaultTileIconAction = (entityId: string) => { export const getEntityDefaultTileIconAction = (entityId: string) => {
const domain = computeDomain(entityId); const domain = computeDomain(entityId);
@@ -48,11 +47,6 @@ export const getEntityDefaultTileIconAction = (entityId: string) => {
return supportsIconAction ? "toggle" : "none"; return supportsIconAction ? "toggle" : "none";
}; };
const DOMAIN_IMAGE_SHAPE: Record<string, TileIconImageStyle> = {
update: "square",
media_player: "rounded-square",
};
@customElement("hui-tile-card") @customElement("hui-tile-card")
export class HuiTileCard extends LitElement implements LovelaceCard { export class HuiTileCard extends LitElement implements LovelaceCard {
public static async getConfigElement(): Promise<LovelaceCardEditor> { public static async getConfigElement(): Promise<LovelaceCardEditor> {
@@ -318,10 +312,10 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
hasDoubleClick: hasAction(this._config!.icon_double_tap_action), hasDoubleClick: hasAction(this._config!.icon_double_tap_action),
})} })}
.interactive=${this._hasIconAction} .interactive=${this._hasIconAction}
.imageStyle=${DOMAIN_IMAGE_SHAPE[domain]}
.imageUrl=${imageUrl} .imageUrl=${imageUrl}
data-domain=${ifDefined(domain)} data-domain=${ifDefined(domain)}
data-state=${ifDefined(stateObj?.state)} data-state=${ifDefined(stateObj?.state)}
class=${classMap({ image: Boolean(imageUrl) })}
> >
<ha-state-icon <ha-state-icon
slot="icon" slot="icon"
@@ -465,8 +459,16 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
animation: pulse 1s infinite; animation: pulse 1s infinite;
} }
ha-tile-badge.not-found { /* Make sure we display the whole image */
--tile-badge-background-color: var(--red-color); ha-tile-icon.image[data-domain="update"] {
--tile-icon-border-radius: 0;
}
/* Make sure we display the almost the whole image but it often use text */
ha-tile-icon.image[data-domain="media_player"] {
--tile-icon-border-radius: min(
var(--ha-tile-icon-border-radius, var(--ha-border-radius-sm)),
var(--ha-border-radius-sm)
);
} }
@keyframes pulse { @keyframes pulse {