mirror of
https://github.com/home-assistant/frontend.git
synced 2026-08-13 01:50:44 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a78d8927fd | ||
|
|
88be7adafa |
@@ -0,0 +1,62 @@
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { css, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { HaListItemBase } from "./ha-list-item-base";
|
||||
|
||||
/**
|
||||
* @element ha-list-item-value
|
||||
* @extends {HaListItemBase}
|
||||
*
|
||||
* @summary
|
||||
* Non-interactive label/value row for grouped lists: label on the start
|
||||
* side, value content end-aligned. The value is the default slot so callers
|
||||
* can render rich content (links, secondary lines).
|
||||
*
|
||||
* @slot - The value content.
|
||||
*
|
||||
* @csspart label - The label column.
|
||||
* @csspart value - The value column.
|
||||
*
|
||||
* @cssprop --ha-list-item-value-max-width - Maximum width of the value column. Defaults to 60%.
|
||||
*
|
||||
* @attr {string} label - The row label.
|
||||
*/
|
||||
@customElement("ha-list-item-value")
|
||||
export class HaListItemValue extends HaListItemBase {
|
||||
@property({ type: String }) public label?: string;
|
||||
|
||||
protected override _renderInner(): TemplateResult {
|
||||
return html`
|
||||
<div part="label" class="label">${this.label}</div>
|
||||
<div part="value" class="value"><slot></slot></div>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles: CSSResultGroup = [
|
||||
HaListItemBase.styles,
|
||||
css`
|
||||
:host {
|
||||
--ha-row-item-padding-block: var(--ha-space-2);
|
||||
--ha-row-item-min-height: 40px;
|
||||
}
|
||||
|
||||
.label {
|
||||
flex: 1;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
.value {
|
||||
max-width: var(--ha-list-item-value-max-width, 60%);
|
||||
min-width: 0;
|
||||
text-align: end;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-list-item-value": HaListItemValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import type { TemplateResult } from "lit";
|
||||
import { css, html, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { HaListBase } from "./ha-list-base";
|
||||
|
||||
/**
|
||||
* @element ha-grouped-list
|
||||
* @extends {HaListBase}
|
||||
*
|
||||
* @summary
|
||||
* Grouped list: an optional header above a framed box of rows separated by
|
||||
* hairlines — the "grouped list" idiom of settings and detail views. Items
|
||||
* are `<ha-list-item-*>` rows; use `ha-list-item-value` for label/value
|
||||
* facts and `ha-list-item-button` for navigable rows.
|
||||
*
|
||||
* @slot - List items (`<ha-list-item-*>`).
|
||||
*
|
||||
* @csspart header - The header above the frame.
|
||||
* @csspart base - The framed `<div role="list">`.
|
||||
*
|
||||
* @cssprop --ha-row-item-padding-inline - Horizontal padding of the rows, which the header aligns to. Defaults to `--ha-space-3`.
|
||||
*
|
||||
* @attr {string} header - Header text rendered above the frame.
|
||||
*/
|
||||
@customElement("ha-grouped-list")
|
||||
export class HaGroupedList extends HaListBase {
|
||||
// The frame carries the list role so the header stays out of the list
|
||||
// semantics.
|
||||
protected override readonly hostRole = "";
|
||||
|
||||
@property({ type: String }) public header?: string;
|
||||
|
||||
protected override render(): TemplateResult {
|
||||
return html`
|
||||
${
|
||||
this.header
|
||||
? html`<div part="header" class="header" id="header">
|
||||
${this.header}
|
||||
</div>`
|
||||
: nothing
|
||||
}
|
||||
<div
|
||||
part="base"
|
||||
class="base"
|
||||
role="list"
|
||||
aria-labelledby=${ifDefined(this.header ? "header" : undefined)}
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
...HaListBase.styles,
|
||||
css`
|
||||
:host {
|
||||
--ha-row-item-padding-inline: var(--ha-space-3);
|
||||
}
|
||||
|
||||
.header {
|
||||
margin: 0 0 var(--ha-space-1);
|
||||
margin-inline-start: calc(
|
||||
var(--ha-row-item-padding-inline) + var(--ha-border-width-sm)
|
||||
);
|
||||
font-size: var(--ha-font-size-m);
|
||||
font-weight: var(--ha-font-weight-medium);
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
.base {
|
||||
border: var(--ha-border-width-sm) solid var(--divider-color);
|
||||
border-radius: var(--ha-card-border-radius, var(--ha-border-radius-lg));
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
::slotted(:not(:first-child)) {
|
||||
border-top: var(--ha-border-width-sm) solid var(--divider-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-grouped-list": HaGroupedList;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,8 @@ import { computeAttributeNameDisplay } from "../../common/entity/compute_attribu
|
||||
import checkValidDate from "../../common/datetime/check_valid_date";
|
||||
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
||||
import "../../components/ha-attribute-value";
|
||||
import "../../components/ha-card";
|
||||
import "../../components/item/ha-list-item-value";
|
||||
import "../../components/list/ha-grouped-list";
|
||||
import type { LocalizeKeys } from "../../common/translations/localize";
|
||||
import { computeShownAttributes } from "../../data/entity/entity_attributes";
|
||||
import type { ExtEntityRegistryEntry } from "../../data/entity/entity_registry";
|
||||
@@ -69,43 +70,28 @@ class HaMoreInfoDetails extends LitElement {
|
||||
in-dialog
|
||||
></ha-yaml-editor>`
|
||||
: html`
|
||||
<section class="section">
|
||||
<h2 class="section-title">
|
||||
${this.hass.localize(
|
||||
"ui.components.entity.entity-state-picker.state"
|
||||
)}
|
||||
</h2>
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="data-group">
|
||||
${stateEntries.map(
|
||||
(entry) =>
|
||||
html`<div class="data-entry">
|
||||
<div class="key">
|
||||
${this.hass.localize(entry.translationKey)}
|
||||
</div>
|
||||
<div class="value">${entry.value}</div>
|
||||
</div>`
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</ha-card>
|
||||
</section>
|
||||
<ha-grouped-list
|
||||
.header=${this.hass.localize(
|
||||
"ui.components.entity.entity-state-picker.state"
|
||||
)}
|
||||
>
|
||||
${stateEntries.map(
|
||||
(entry) =>
|
||||
html`<ha-list-item-value
|
||||
.label=${this.hass.localize(entry.translationKey)}
|
||||
>
|
||||
${entry.value}
|
||||
</ha-list-item-value>`
|
||||
)}
|
||||
</ha-grouped-list>
|
||||
|
||||
<section class="section">
|
||||
<h2 class="section-title">
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.attributes"
|
||||
)}
|
||||
</h2>
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="data-group">
|
||||
${this._renderAttributes(attributes)}
|
||||
</div>
|
||||
</div>
|
||||
</ha-card>
|
||||
</section>
|
||||
<ha-grouped-list
|
||||
.header=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.attributes"
|
||||
)}
|
||||
>
|
||||
${this._renderAttributes(attributes)}
|
||||
</ha-grouped-list>
|
||||
`
|
||||
}
|
||||
</div>
|
||||
@@ -192,28 +178,25 @@ class HaMoreInfoDetails extends LitElement {
|
||||
|
||||
return attributes.map(
|
||||
(attribute) => html`
|
||||
<div class="data-entry">
|
||||
<div class="key">
|
||||
${computeAttributeNameDisplay(
|
||||
this.hass.localize,
|
||||
this._stateObj!,
|
||||
this.hass.entities,
|
||||
attribute
|
||||
)}
|
||||
</div>
|
||||
<div class="value">
|
||||
${
|
||||
attribute === "supported_features" && featureEnum
|
||||
? this._renderFeatures(featureEnum, this._stateObj!)
|
||||
: html`
|
||||
<ha-attribute-value
|
||||
.attribute=${attribute}
|
||||
.stateObj=${this._stateObj}
|
||||
></ha-attribute-value>
|
||||
`
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<ha-list-item-value
|
||||
.label=${computeAttributeNameDisplay(
|
||||
this.hass.localize,
|
||||
this._stateObj!,
|
||||
this.hass.entities,
|
||||
attribute
|
||||
)}
|
||||
>
|
||||
${
|
||||
attribute === "supported_features" && featureEnum
|
||||
? this._renderFeatures(featureEnum, this._stateObj!)
|
||||
: html`
|
||||
<ha-attribute-value
|
||||
.attribute=${attribute}
|
||||
.stateObj=${this._stateObj}
|
||||
></ha-attribute-value>
|
||||
`
|
||||
}
|
||||
</ha-list-item-value>
|
||||
`
|
||||
);
|
||||
}
|
||||
@@ -247,47 +230,14 @@ class HaMoreInfoDetails extends LitElement {
|
||||
padding-bottom: max(var(--safe-area-inset-bottom), var(--ha-space-6));
|
||||
}
|
||||
|
||||
.section + .section {
|
||||
ha-grouped-list + ha-grouped-list {
|
||||
margin-top: var(--ha-space-4);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin: 0 0 var(--ha-space-2);
|
||||
font-size: var(--ha-font-size-m);
|
||||
font-weight: var(--ha-font-weight-medium);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: var(--ha-space-2) var(--ha-space-4);
|
||||
}
|
||||
|
||||
.data-entry {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: var(--ha-space-2) 0;
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
}
|
||||
|
||||
.data-group .data-entry:last-of-type {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.data-entry .value {
|
||||
max-width: 60%;
|
||||
overflow-wrap: break-word;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.key {
|
||||
flex-grow: 1;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
.empty {
|
||||
color: var(--secondary-text-color);
|
||||
text-align: center;
|
||||
padding: var(--ha-space-2) 0;
|
||||
padding: var(--ha-space-3) var(--ha-space-4);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ class HuiInputNumberEntityRow extends LitElement implements LovelaceRow {
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<div class="flex state">
|
||||
<div class="flex box">
|
||||
<ha-input
|
||||
.disabled=${stateObj.state === UNAVAILABLE}
|
||||
pattern="[0-9]+([\\.][0-9]+)?"
|
||||
@@ -128,6 +128,10 @@ class HuiInputNumberEntityRow extends LitElement implements LovelaceRow {
|
||||
min-width: 45px;
|
||||
text-align: end;
|
||||
}
|
||||
.box {
|
||||
flex-grow: 0;
|
||||
min-width: 45px;
|
||||
}
|
||||
ha-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ class HuiNumberEntityRow extends LitElement implements LovelaceRow {
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<div class="flex state">
|
||||
<div class="flex box">
|
||||
<ha-input
|
||||
auto-validate
|
||||
.disabled=${stateObj.state === UNAVAILABLE}
|
||||
@@ -136,6 +136,10 @@ class HuiNumberEntityRow extends LitElement implements LovelaceRow {
|
||||
min-width: 45px;
|
||||
text-align: end;
|
||||
}
|
||||
.box {
|
||||
flex-grow: 0;
|
||||
min-width: 45px;
|
||||
}
|
||||
ha-input::part(wa-input) {
|
||||
text-align: end;
|
||||
direction: ltr !important;
|
||||
|
||||
@@ -77,8 +77,8 @@ export const moreInfoViewElements: ViewElementSmokeCase<MoreInfoView>[] = [
|
||||
{
|
||||
view: "details",
|
||||
element: "ha-more-info-details",
|
||||
// The details view renders the state and attributes cards.
|
||||
content: [{ selector: "ha-card" }],
|
||||
// The details view renders the state and attributes grouped lists.
|
||||
content: [{ selector: "ha-grouped-list" }],
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user