Replace clickable list item (#25165)

This commit is contained in:
Bram Kragten 2025-04-25 09:01:19 +02:00 committed by GitHub
parent 3a0c367f76
commit 0229f67751
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 58 additions and 144 deletions

View File

@ -1,61 +0,0 @@
import type { CSSResultGroup } from "lit";
import { css, html } from "lit";
import { customElement, property, query } from "lit/decorators";
import { HaListItem } from "./ha-list-item";
@customElement("ha-clickable-list-item")
export class HaClickableListItem extends HaListItem {
@property() public href?: string;
@property({ attribute: "disable-href", type: Boolean })
public disableHref = false;
@property({ attribute: "open-new-tab", type: Boolean, reflect: true })
public openNewTab = false;
@query("a") private _anchor!: HTMLAnchorElement;
public render() {
const r = super.render();
const href = this.href || "";
return html`${this.disableHref
? html`<a href="#" class="disabled">${r}</a>`
: html`<a target=${this.openNewTab ? "_blank" : ""} href=${href}
>${r}</a
>`}`;
}
firstUpdated() {
super.firstUpdated();
this.addEventListener("keydown", (ev) => {
if (ev.key === "Enter" || ev.key === " ") {
this._anchor.click();
}
});
}
static get styles(): CSSResultGroup {
return [
super.styles,
css`
a {
width: 100%;
height: 100%;
display: flex;
align-items: center;
overflow: hidden;
}
.disabled {
pointer-events: none;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-clickable-list-item": HaClickableListItem;
}
}

View File

@ -12,8 +12,7 @@ import "../../../components/buttons/ha-progress-button";
import "../../../components/chart/ha-chart-base"; import "../../../components/chart/ha-chart-base";
import "../../../components/ha-alert"; import "../../../components/ha-alert";
import "../../../components/ha-card"; import "../../../components/ha-card";
import "../../../components/ha-list"; import "../../../components/ha-md-list-item";
import "../../../components/ha-clickable-list-item";
import "../../../components/ha-icon-button"; import "../../../components/ha-icon-button";
import "../../../components/ha-icon-next"; import "../../../components/ha-icon-next";
import "../../../components/ha-settings-row"; import "../../../components/ha-settings-row";
@ -287,26 +286,24 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
</div> </div>
${documentationURL ${documentationURL
? html` ? html`
<ha-list> <ha-md-list-item
<ha-clickable-list-item .href=${documentationURL}
.href=${documentationURL} type="link"
open-new-tab target="_blank"
twoline rel="noopener noreferrer"
hasMeta >
<span
>${this.hass.localize(
"ui.panel.config.hardware.documentation"
)}</span
> >
<span <span slot="supporting-text"
>${this.hass.localize( >${this.hass.localize(
"ui.panel.config.hardware.documentation" "ui.panel.config.hardware.documentation_description"
)}</span )}</span
> >
<span slot="secondary" <ha-icon-next slot="end"></ha-icon-next>
>${this.hass.localize( </ha-md-list-item>
"ui.panel.config.hardware.documentation_description"
)}</span
>
<ha-icon-next slot="meta"></ha-icon-next>
</ha-clickable-list-item>
</ha-list>
` `
: ""} : ""}
${boardConfigEntries.length || ${boardConfigEntries.length ||

View File

@ -13,11 +13,12 @@ import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import "../../../components/ha-card"; import "../../../components/ha-card";
import "../../../components/ha-clickable-list-item";
import "../../../components/ha-icon-next"; import "../../../components/ha-icon-next";
import "../../../components/ha-list"; import "../../../components/ha-list";
import "../../../components/ha-list-item"; import "../../../components/ha-list-item";
import "../../../components/ha-logo-svg"; import "../../../components/ha-logo-svg";
import "../../../components/ha-md-list";
import "../../../components/ha-md-list-item";
import type { HassioHassOSInfo } from "../../../data/hassio/host"; import type { HassioHassOSInfo } from "../../../data/hassio/host";
import { fetchHassioHassOsInfo } from "../../../data/hassio/host"; import { fetchHassioHassOsInfo } from "../../../data/hassio/host";
import type { HassioInfo } from "../../../data/hassio/supervisor"; import type { HassioInfo } from "../../../data/hassio/supervisor";
@ -174,10 +175,10 @@ class HaConfigInfo extends LitElement {
</ha-card> </ha-card>
<ha-card outlined class="pages"> <ha-card outlined class="pages">
<ha-list> <ha-md-list>
<ha-list-item graphic="avatar" @click=${this._showShortcuts}> <ha-md-list-item type="button" @click=${this._showShortcuts}>
<div <div
slot="graphic" slot="start"
class="icon-background" class="icon-background"
style="background-color: #9e4dd1;" style="background-color: #9e4dd1;"
> >
@ -186,18 +187,18 @@ class HaConfigInfo extends LitElement {
<span <span
>${this.hass.localize("ui.panel.config.info.shortcuts")}</span >${this.hass.localize("ui.panel.config.info.shortcuts")}</span
> >
</ha-list-item> </ha-md-list-item>
${PAGES.map( ${PAGES.map(
(page) => html` (page) => html`
<ha-clickable-list-item <ha-md-list-item
graphic="avatar" type="link"
open-new-tab .href=${documentationUrl(this.hass, page.path)}
href=${documentationUrl(this.hass, page.path)} target="_blank"
hasMeta rel="noopener noreferrer"
> >
<div <div
slot="graphic" slot="start"
class="icon-background" class="icon-background"
.style="background-color: ${page.iconColor}" .style="background-color: ${page.iconColor}"
> >
@ -208,14 +209,11 @@ class HaConfigInfo extends LitElement {
`ui.panel.config.info.items.${page.name}` `ui.panel.config.info.items.${page.name}`
)} )}
</span> </span>
<ha-svg-icon <ha-svg-icon slot="end" .path=${mdiOpenInNew}></ha-svg-icon>
slot="meta" </ha-md-list-item>
.path=${mdiOpenInNew}
></ha-svg-icon>
</ha-clickable-list-item>
` `
)} )}
</ha-list> </ha-md-list>
${customUiList.length ${customUiList.length
? html` ? html`
<div class="custom-ui"> <div class="custom-ui">
@ -354,16 +352,6 @@ class HaConfigInfo extends LitElement {
padding: 4px 0; padding: 4px 0;
} }
ha-list {
--mdc-list-side-padding: 16px;
--mdc-list-vertical-padding: 0;
}
ha-clickable-list-item,
ha-list-item {
height: 64px;
}
.icon-background ha-svg-icon { .icon-background ha-svg-icon {
height: 24px; height: 24px;
width: 24px; width: 24px;

View File

@ -1,10 +1,10 @@
import { mdiDotsVertical } from "@mdi/js"; import { mdiDotsVertical } from "@mdi/js";
import { html, LitElement } from "lit"; import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import "../../../components/ha-button-menu";
import "../../../components/ha-clickable-list-item";
import "../../../components/ha-icon-button"; import "../../../components/ha-icon-button";
import type { HomeAssistant } from "../../../types"; import type { HomeAssistant } from "../../../types";
import "../../../components/ha-md-list-item";
import "../../../components/ha-md-button-menu";
@customElement("ha-integration-overflow-menu") @customElement("ha-integration-overflow-menu")
export class HaIntegrationOverflowMenu extends LitElement { export class HaIntegrationOverflowMenu extends LitElement {
@ -12,18 +12,18 @@ export class HaIntegrationOverflowMenu extends LitElement {
protected render() { protected render() {
return html` return html`
<ha-button-menu activatable> <ha-md-button-menu>
<ha-icon-button <ha-icon-button
slot="trigger" slot="trigger"
.label=${this.hass.localize("ui.common.menu")} .label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical} .path=${mdiDotsVertical}
></ha-icon-button> ></ha-icon-button>
<ha-clickable-list-item href="/config/application_credentials"> <ha-md-list-item type="link" href="/config/application_credentials">
${this.hass.localize( ${this.hass.localize(
"ui.panel.config.application_credentials.caption" "ui.panel.config.application_credentials.caption"
)} )}
</ha-clickable-list-item> </ha-md-list-item>
</ha-button-menu> </ha-md-button-menu>
`; `;
} }
} }

View File

@ -11,17 +11,20 @@ import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined"; import { ifDefined } from "lit/directives/if-defined";
import memoize from "memoize-one"; import memoize from "memoize-one";
import { isComponentLoaded } from "../../../../common/config/is_component_loaded"; import { isComponentLoaded } from "../../../../common/config/is_component_loaded";
import { storage } from "../../../../common/decorators/storage";
import { navigate } from "../../../../common/navigate"; import { navigate } from "../../../../common/navigate";
import { stringCompare } from "../../../../common/string/compare"; import { stringCompare } from "../../../../common/string/compare";
import type { LocalizeFunc } from "../../../../common/translations/localize";
import type { import type {
DataTableColumnContainer, DataTableColumnContainer,
RowClickedEvent, RowClickedEvent,
SortingChangedEvent, SortingChangedEvent,
} from "../../../../components/data-table/ha-data-table"; } from "../../../../components/data-table/ha-data-table";
import "../../../../components/ha-clickable-list-item";
import "../../../../components/ha-fab"; import "../../../../components/ha-fab";
import "../../../../components/ha-icon"; import "../../../../components/ha-icon";
import "../../../../components/ha-icon-button"; import "../../../../components/ha-icon-button";
import "../../../../components/ha-md-button-menu";
import "../../../../components/ha-md-list-item";
import "../../../../components/ha-svg-icon"; import "../../../../components/ha-svg-icon";
import "../../../../components/ha-tooltip"; import "../../../../components/ha-tooltip";
import type { LovelacePanelConfig } from "../../../../data/lovelace"; import type { LovelacePanelConfig } from "../../../../data/lovelace";
@ -44,13 +47,11 @@ import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-
import "../../../../layouts/hass-loading-screen"; import "../../../../layouts/hass-loading-screen";
import "../../../../layouts/hass-tabs-subpage-data-table"; import "../../../../layouts/hass-tabs-subpage-data-table";
import type { HomeAssistant, Route } from "../../../../types"; import type { HomeAssistant, Route } from "../../../../types";
import type { LocalizeFunc } from "../../../../common/translations/localize";
import { getLovelaceStrategy } from "../../../lovelace/strategies/get-strategy"; import { getLovelaceStrategy } from "../../../lovelace/strategies/get-strategy";
import { showNewDashboardDialog } from "../../dashboard/show-dialog-new-dashboard"; import { showNewDashboardDialog } from "../../dashboard/show-dialog-new-dashboard";
import { lovelaceTabs } from "../ha-config-lovelace"; import { lovelaceTabs } from "../ha-config-lovelace";
import { showDashboardConfigureStrategyDialog } from "./show-dialog-lovelace-dashboard-configure-strategy"; import { showDashboardConfigureStrategyDialog } from "./show-dialog-lovelace-dashboard-configure-strategy";
import { showDashboardDetailDialog } from "./show-dialog-lovelace-dashboard-detail"; import { showDashboardDetailDialog } from "./show-dialog-lovelace-dashboard-detail";
import { storage } from "../../../../common/decorators/storage";
type DataTableItem = Pick< type DataTableItem = Pick<
LovelaceDashboard, LovelaceDashboard,
@ -327,16 +328,16 @@ export class HaConfigLovelaceDashboards extends LitElement {
has-fab has-fab
clickable clickable
> >
<ha-button-menu slot="toolbar-icon" activatable> <ha-md-button-menu slot="toolbar-icon">
<ha-icon-button <ha-icon-button
slot="trigger" slot="trigger"
.label=${this.hass.localize("ui.common.menu")} .label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical} .path=${mdiDotsVertical}
></ha-icon-button> ></ha-icon-button>
<ha-clickable-list-item href="/config/lovelace/resources"> <ha-md-list-item type="link" href="/config/lovelace/resources">
${this.hass.localize("ui.panel.config.lovelace.resources.caption")} ${this.hass.localize("ui.panel.config.lovelace.resources.caption")}
</ha-clickable-list-item> </ha-md-list-item>
</ha-button-menu> </ha-md-button-menu>
<ha-fab <ha-fab
slot="fab" slot="fab"
.label=${this.hass.localize( .label=${this.hass.localize(

View File

@ -2,8 +2,9 @@ import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit"; import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-card"; import "../../../components/ha-card";
import "../../../components/ha-clickable-list-item";
import "../../../components/ha-list"; import "../../../components/ha-list";
import "../../../components/ha-md-list";
import "../../../components/ha-md-list-item";
import type { import type {
IntegrationManifest, IntegrationManifest,
IntegrationSetup, IntegrationSetup,
@ -39,7 +40,7 @@ class IntegrationsStartupTime extends LitElement {
} }
return html` return html`
<ha-list> <ha-md-list>
${this._setups?.map((setup) => { ${this._setups?.map((setup) => {
const manifest = this._manifests && this._manifests[setup.domain]; const manifest = this._manifests && this._manifests[setup.domain];
const docLink = manifest const docLink = manifest
@ -50,13 +51,7 @@ class IntegrationsStartupTime extends LitElement {
const setupSeconds = setup.seconds?.toFixed(2); const setupSeconds = setup.seconds?.toFixed(2);
return html` return html`
<ha-clickable-list-item <ha-md-list-item .href=${docLink} type="link" target="_blank">
graphic="avatar"
twoline
hasMeta
open-new-tab
href=${docLink}
>
<img <img
alt="" alt=""
loading="lazy" loading="lazy"
@ -68,19 +63,19 @@ class IntegrationsStartupTime extends LitElement {
})} })}
crossorigin="anonymous" crossorigin="anonymous"
referrerpolicy="no-referrer" referrerpolicy="no-referrer"
slot="graphic" slot="start"
/> />
<span> <span>
${domainToName(this.hass.localize, setup.domain, manifest)} ${domainToName(this.hass.localize, setup.domain, manifest)}
</span> </span>
<span slot="secondary">${setup.domain}</span> <span slot="supporting-text">${setup.domain}</span>
<div slot="meta"> <div slot="end">
${setupSeconds ? html`${setupSeconds} s` : ""} ${setupSeconds ? html`${setupSeconds} s` : ""}
</div> </div>
</ha-clickable-list-item> </ha-md-list-item>
`; `;
})} })}
</ha-list> </ha-md-list>
`; `;
} }
@ -109,20 +104,14 @@ class IntegrationsStartupTime extends LitElement {
} }
static styles = css` static styles = css`
ha-clickable-list-item {
--mdc-list-item-meta-size: 64px;
--mdc-typography-caption-font-size: 12px;
}
img { img {
display: block; display: block;
max-height: 40px; max-height: 40px;
max-width: 40px; max-width: 40px;
border-radius: 0; border-radius: 0;
} }
div[slot="meta"] { div[slot="end"] {
display: flex; font-size: 12px;
justify-content: center;
align-items: center;
} }
`; `;
} }