mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 09:16:38 +00:00
Add inline features position for tile card (#24199)
* Add side features position for tile card * Add translations * Rename to inline * Simplify editor with 2 dropdowns * Use 50% width * Update src/translations/en.json Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com> --------- Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>
This commit is contained in:
parent
94a5e737cc
commit
0b64861297
@ -20,40 +20,31 @@ export class HuiCardFeatures extends LitElement {
|
||||
return nothing;
|
||||
}
|
||||
return html`
|
||||
<div class="container">
|
||||
${this.features.map(
|
||||
(feature) => html`
|
||||
<hui-card-feature
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
.color=${this.color}
|
||||
.feature=${feature}
|
||||
></hui-card-feature>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
${this.features.map(
|
||||
(feature) => html`
|
||||
<hui-card-feature
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
.color=${this.color}
|
||||
.feature=${feature}
|
||||
></hui-card-feature>
|
||||
`
|
||||
)}
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
--feature-color: var(--state-icon-color);
|
||||
--feature-padding: 12px;
|
||||
--feature-height: 42px;
|
||||
--feature-border-radius: 12px;
|
||||
--feature-button-spacing: 12px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: var(--feature-padding);
|
||||
padding-top: 0px;
|
||||
gap: var(--feature-padding);
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
@ -256,6 +256,7 @@ export class HuiHumidifierCard extends LitElement implements LovelaceCard {
|
||||
hui-card-features {
|
||||
width: 100%;
|
||||
flex: none;
|
||||
padding: 0 12px 12px 12px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@ -248,6 +248,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
||||
hui-card-features {
|
||||
width: 100%;
|
||||
flex: none;
|
||||
padding: 0 12px 12px 12px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@ -100,10 +100,13 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
public getCardSize(): number {
|
||||
const featuresPosition =
|
||||
this._config && this._featurePosition(this._config);
|
||||
const featuresCount = this._config?.features?.length || 0;
|
||||
return (
|
||||
1 +
|
||||
(this._config?.vertical ? 1 : 0) +
|
||||
(this._config?.features?.length || 0)
|
||||
(featuresPosition === "inline" ? 0 : featuresCount)
|
||||
);
|
||||
}
|
||||
|
||||
@ -111,9 +114,16 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
const columns = 6;
|
||||
let min_columns = 6;
|
||||
let rows = 1;
|
||||
if (this._config?.features?.length) {
|
||||
rows += this._config.features.length;
|
||||
const featurePosition = this._config && this._featurePosition(this._config);
|
||||
const featuresCount = this._config?.features?.length || 0;
|
||||
if (featuresCount) {
|
||||
if (featurePosition === "inline") {
|
||||
min_columns = 12;
|
||||
} else {
|
||||
rows += featuresCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._config?.vertical) {
|
||||
rows++;
|
||||
min_columns = 3;
|
||||
@ -210,6 +220,23 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
);
|
||||
}
|
||||
|
||||
private _featurePosition = memoizeOne((config: TileCardConfig) => {
|
||||
if (config.vertical) {
|
||||
return "bottom";
|
||||
}
|
||||
return config.features_position || "bottom";
|
||||
});
|
||||
|
||||
private _displayedFeatures = memoizeOne((config: TileCardConfig) => {
|
||||
const features = config.features || [];
|
||||
const featurePosition = this._featurePosition(config);
|
||||
|
||||
if (featurePosition === "inline") {
|
||||
return features.slice(0, 1);
|
||||
}
|
||||
return features;
|
||||
});
|
||||
|
||||
protected render() {
|
||||
if (!this._config || !this.hass) {
|
||||
return nothing;
|
||||
@ -263,6 +290,12 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
? this._getImageUrl(stateObj)
|
||||
: undefined;
|
||||
|
||||
const featurePosition = this._featurePosition(this._config);
|
||||
const features = this._displayedFeatures(this._config);
|
||||
|
||||
const containerOrientationClass =
|
||||
featurePosition === "inline" ? "horizontal" : "";
|
||||
|
||||
return html`
|
||||
<ha-card style=${styleMap(style)} class=${classMap({ active })}>
|
||||
<div
|
||||
@ -278,7 +311,7 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
>
|
||||
<ha-ripple .disabled=${!this._hasCardAction}></ha-ripple>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="container ${containerOrientationClass}">
|
||||
<div class="content ${classMap(contentClasses)}">
|
||||
<ha-tile-icon
|
||||
role=${ifDefined(this._hasIconAction ? "button" : undefined)}
|
||||
@ -308,13 +341,13 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
.secondary=${stateDisplay}
|
||||
></ha-tile-info>
|
||||
</div>
|
||||
${this._config.features
|
||||
${features.length > 0
|
||||
? html`
|
||||
<hui-card-features
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
.color=${this._config.color}
|
||||
.features=${this._config.features}
|
||||
.features=${features}
|
||||
></hui-card-features>
|
||||
`
|
||||
: nothing}
|
||||
@ -372,6 +405,10 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
.container.horizontal {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
display: flex;
|
||||
@ -383,6 +420,11 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
pointer-events: none;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.container.horizontal .content {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.vertical {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
@ -413,6 +455,13 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
hui-card-features {
|
||||
--feature-color: var(--tile-color);
|
||||
padding: 0 12px 12px 12px;
|
||||
}
|
||||
.container.horizontal hui-card-features {
|
||||
width: 50%;
|
||||
--feature-height: 36px;
|
||||
padding: 10px;
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
|
||||
ha-tile-icon[data-domain="alarm_control_panel"][data-state="pending"],
|
||||
|
@ -533,6 +533,7 @@ export interface TileCardConfig extends LovelaceCardConfig {
|
||||
icon_hold_action?: ActionConfig;
|
||||
icon_double_tap_action?: ActionConfig;
|
||||
features?: LovelaceCardFeatureConfig[];
|
||||
features_position?: "bottom" | "inline";
|
||||
}
|
||||
|
||||
export interface HeadingCardConfig extends LovelaceCardConfig {
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
assert,
|
||||
assign,
|
||||
boolean,
|
||||
enums,
|
||||
object,
|
||||
optional,
|
||||
string,
|
||||
@ -15,6 +16,7 @@ import {
|
||||
} from "superstruct";
|
||||
import type { HASSDomEvent } from "../../../../common/dom/fire_event";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { LocalizeFunc } from "../../../../common/translations/localize";
|
||||
import "../../../../components/ha-expansion-panel";
|
||||
import "../../../../components/ha-form/ha-form";
|
||||
import type {
|
||||
@ -54,6 +56,7 @@ const cardConfigStruct = assign(
|
||||
icon_hold_action: optional(actionConfigStruct),
|
||||
icon_double_tap_action: optional(actionConfigStruct),
|
||||
features: optional(array(any())),
|
||||
features_position: optional(enums(["bottom", "inline"])),
|
||||
})
|
||||
);
|
||||
|
||||
@ -109,8 +112,10 @@ export class HuiTileCardEditor
|
||||
|
||||
private _schema = memoizeOne(
|
||||
(
|
||||
localize: LocalizeFunc,
|
||||
entityId: string | undefined,
|
||||
hideState: boolean,
|
||||
vertical: boolean,
|
||||
displayActions: AdvancedActions[] = []
|
||||
) =>
|
||||
[
|
||||
@ -148,12 +153,6 @@ export class HuiTileCardEditor
|
||||
boolean: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vertical",
|
||||
selector: {
|
||||
boolean: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "hide_state",
|
||||
selector: {
|
||||
@ -175,6 +174,43 @@ export class HuiTileCardEditor
|
||||
},
|
||||
] as const satisfies readonly HaFormSchema[])
|
||||
: []),
|
||||
{
|
||||
name: "",
|
||||
type: "grid",
|
||||
schema: [
|
||||
{
|
||||
name: "content_layout",
|
||||
required: true,
|
||||
selector: {
|
||||
select: {
|
||||
mode: "dropdown",
|
||||
options: ["horizontal", "vertical"].map((value) => ({
|
||||
label: localize(
|
||||
`ui.panel.lovelace.editor.card.tile.content_layout_options.${value}`
|
||||
),
|
||||
value,
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "features_position",
|
||||
required: true,
|
||||
selector: {
|
||||
select: {
|
||||
mode: "dropdown",
|
||||
options: ["bottom", "inline"].map((value) => ({
|
||||
label: localize(
|
||||
`ui.panel.lovelace.editor.card.tile.features_position_options.${value}`
|
||||
),
|
||||
value,
|
||||
disabled: vertical && value === "inline",
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -223,12 +259,22 @@ export class HuiTileCardEditor
|
||||
const stateObj = entityId ? this.hass!.states[entityId] : undefined;
|
||||
|
||||
const schema = this._schema(
|
||||
this.hass.localize,
|
||||
entityId,
|
||||
this._config!.hide_state ?? false,
|
||||
this._config.hide_state ?? false,
|
||||
this._config.vertical ?? false,
|
||||
this._displayActions
|
||||
);
|
||||
|
||||
const data = this._config;
|
||||
const data = {
|
||||
...this._config,
|
||||
content_layout: this._config.vertical ? "vertical" : "horizontal",
|
||||
};
|
||||
|
||||
// Default features position to bottom and force it to bottom in vertical mode
|
||||
if (!data.features_position || data.vertical) {
|
||||
data.features_position = "bottom";
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-form
|
||||
@ -280,6 +326,12 @@ export class HuiTileCardEditor
|
||||
delete config.state_content;
|
||||
}
|
||||
|
||||
// Convert content_layout to vertical
|
||||
if (config.content_layout) {
|
||||
config.vertical = config.content_layout === "vertical";
|
||||
delete config.content_layout;
|
||||
}
|
||||
|
||||
fireEvent(this, "config-changed", { config });
|
||||
}
|
||||
|
||||
@ -337,11 +389,11 @@ export class HuiTileCardEditor
|
||||
case "icon_hold_action":
|
||||
case "icon_double_tap_action":
|
||||
case "show_entity_picture":
|
||||
case "vertical":
|
||||
case "hide_state":
|
||||
case "state_content":
|
||||
case "content_layout":
|
||||
case "appearance":
|
||||
case "interactions":
|
||||
case "features_position":
|
||||
return this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.tile.${schema.name}`
|
||||
);
|
||||
@ -377,6 +429,14 @@ export class HuiTileCardEditor
|
||||
display: block;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.info {
|
||||
color: var(--secondary-text-color);
|
||||
margin-top: 0;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.features-form {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -7119,12 +7119,20 @@
|
||||
"icon_tap_action": "Icon tap behavior",
|
||||
"icon_hold_action": "Icon hold behavior",
|
||||
"icon_double_tap_action": "Icon double tap behavior",
|
||||
"interactions": "Interactions",
|
||||
"appearance": "Appearance",
|
||||
"show_entity_picture": "Show entity picture",
|
||||
"vertical": "Vertical",
|
||||
"hide_state": "Hide state",
|
||||
"state_content": "State content"
|
||||
"state_content": "State content",
|
||||
"features_position": "Features position",
|
||||
"features_position_options": {
|
||||
"bottom": "Bottom",
|
||||
"inline": "Inline"
|
||||
},
|
||||
"content_layout": "Content layout",
|
||||
"content_layout_options": {
|
||||
"horizontal": "Horizontal",
|
||||
"vertical": "Vertical"
|
||||
}
|
||||
},
|
||||
"vertical-stack": {
|
||||
"name": "Vertical stack",
|
||||
|
Loading…
x
Reference in New Issue
Block a user