diff --git a/gallery/src/pages/components/ha-bar-button.markdown b/gallery/src/pages/components/ha-bar-button.markdown
new file mode 100644
index 0000000000..eb265b8f1f
--- /dev/null
+++ b/gallery/src/pages/components/ha-bar-button.markdown
@@ -0,0 +1,3 @@
+---
+title: Bar Button
+---
diff --git a/gallery/src/pages/components/ha-bar-button.ts b/gallery/src/pages/components/ha-bar-button.ts
new file mode 100644
index 0000000000..fcdd0f4176
--- /dev/null
+++ b/gallery/src/pages/components/ha-bar-button.ts
@@ -0,0 +1,189 @@
+import {
+ mdiFanSpeed1,
+ mdiFanSpeed2,
+ mdiFanSpeed3,
+ mdiLightbulb,
+} from "@mdi/js";
+import { css, html, LitElement, TemplateResult } from "lit";
+import { customElement } from "lit/decorators";
+import { ifDefined } from "lit/directives/if-defined";
+import { repeat } from "lit/directives/repeat";
+import "../../../../src/components/ha-bar-button";
+import "../../../../src/components/ha-card";
+import "../../../../src/components/ha-svg-icon";
+import "../../../../src/components/ha-bar-button-group";
+
+type Button = {
+ label: string;
+ icon?: string;
+ class?: string;
+ disabled?: boolean;
+};
+
+const buttons: Button[] = [
+ {
+ label: "Button",
+ },
+ {
+ label: "Button and custom style",
+ class: "custom",
+ },
+ {
+ label: "Disabled Button",
+ disabled: true,
+ },
+];
+
+type ButtonGroup = {
+ vertical?: boolean;
+ class?: string;
+};
+
+const buttonGroups: ButtonGroup[] = [
+ {},
+ {
+ class: "custom-group",
+ },
+];
+
+@customElement("demo-components-ha-bar-button")
+export class DemoHaBarButton extends LitElement {
+ protected render(): TemplateResult {
+ return html`
+
+ ${repeat(
+ buttons,
+ (btn) => html`
+
+
Config: ${JSON.stringify(btn)}
+
+
+
+
+ `
+ )}
+
+
+
+ ${repeat(
+ buttonGroups,
+ (group) => html`
+
+
Config: ${JSON.stringify(group)}
+
+
+
+
+
+
+
+
+
+
+
+
+ `
+ )}
+
+
+
+
Vertical
+
+ ${repeat(
+ buttonGroups,
+ (group) => html`
+
+
+
+
+
+
+
+
+
+
+
+ `
+ )}
+
+
+
+ `;
+ }
+
+ static get styles() {
+ return css`
+ ha-card {
+ max-width: 600px;
+ margin: 24px auto;
+ }
+ pre {
+ margin-top: 0;
+ margin-bottom: 8px;
+ }
+ p {
+ margin: 0;
+ }
+ label {
+ font-weight: 600;
+ }
+ .custom {
+ --button-bar-icon-color: var(--primary-color);
+ --button-bar-background-color: var(--primary-color);
+ --button-bar-background-opacity: 0.2;
+ --button-bar-border-radius: 18px;
+ height: 100px;
+ width: 100px;
+ }
+ .custom-group {
+ --button-bar-group-thickness: 100px;
+ --button-bar-group-border-radius: 18px;
+ --button-bar-group-spacing: 20px;
+ }
+ .custom-group ha-bar-button {
+ --button-bar-border-radius: 18px;
+ --mdc-icon-size: 32px;
+ }
+ .vertical-buttons {
+ height: 300px;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ }
+ p.title {
+ margin-bottom: 12px;
+ }
+ .vertical-switches > *:not(:last-child) {
+ margin-right: 4px;
+ }
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "demo-components-ha-bar-button": DemoHaBarButton;
+ }
+}
diff --git a/src/components/ha-bar-button-group.ts b/src/components/ha-bar-button-group.ts
new file mode 100644
index 0000000000..030e4a9e3c
--- /dev/null
+++ b/src/components/ha-bar-button-group.ts
@@ -0,0 +1,63 @@
+import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
+import { customElement, property } from "lit/decorators";
+
+@customElement("ha-bar-button-group")
+export class HaBarButtonGroup extends LitElement {
+ @property({ type: Boolean, reflect: true })
+ public vertical = false;
+
+ protected render(): TemplateResult {
+ return html`
+
+
+
+ `;
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ :host {
+ --button-bar-group-spacing: 12px;
+ --button-bar-group-thickness: 40px;
+ height: var(--button-bar-group-thickness);
+ width: auto;
+ display: block;
+ }
+ .container {
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+ height: 100%;
+ }
+ ::slotted(*) {
+ flex: 1;
+ height: 100%;
+ width: 100%;
+ }
+ ::slotted(*:not(:last-child)) {
+ margin-right: var(--button-bar-group-spacing);
+ margin-inline-end: var(--button-bar-group-spacing);
+ margin-inline-start: initial;
+ direction: var(--direction);
+ }
+ :host([vertical]) {
+ width: var(--button-bar-group-thickness);
+ height: auto;
+ }
+ :host([vertical]) .container {
+ flex-direction: column;
+ }
+ :host([vertical]) ::slotted(ha-bar-button:not(:last-child)) {
+ margin-right: initial;
+ margin-inline-end: initial;
+ margin-bottom: var(--button-bar-group-spacing);
+ }
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-bar-button-group": HaBarButtonGroup;
+ }
+}
diff --git a/src/components/tile/ha-tile-button.ts b/src/components/ha-bar-button.ts
similarity index 78%
rename from src/components/tile/ha-tile-button.ts
rename to src/components/ha-bar-button.ts
index 321536d8eb..e8a8f6f47e 100644
--- a/src/components/tile/ha-tile-button.ts
+++ b/src/components/ha-bar-button.ts
@@ -9,11 +9,9 @@ import {
state,
} from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
-import "../ha-icon";
-import "../ha-svg-icon";
-@customElement("ha-tile-button")
-export class HaTileButton extends LitElement {
+@customElement("ha-bar-button")
+export class HaBarButton extends LitElement {
@property({ type: Boolean, reflect: true }) disabled = false;
@property() public label?: string;
@@ -28,7 +26,7 @@ export class HaTileButton extends LitElement {
type="button"
class="button"
aria-label=${ifDefined(this.label)}
- .title=${this.label}
+ title=${ifDefined(this.label)}
.disabled=${Boolean(this.disabled)}
@focus=${this.handleRippleFocus}
@blur=${this.handleRippleBlur}
@@ -81,9 +79,11 @@ export class HaTileButton extends LitElement {
static get styles(): CSSResultGroup {
return css`
:host {
- --tile-button-icon-color: var(--primary-text-color);
- --tile-button-background-color: var(--disabled-color);
- --tile-button-background-opacity: 0.2;
+ display: block;
+ --button-bar-icon-color: var(--primary-text-color);
+ --button-bar-background-color: var(--disabled-color);
+ --button-bar-background-opacity: 0.2;
+ --button-bar-border-radius: 10px;
width: 40px;
height: 40px;
-webkit-tap-highlight-color: transparent;
@@ -97,7 +97,7 @@ export class HaTileButton extends LitElement {
justify-content: center;
width: 100%;
height: 100%;
- border-radius: 10px;
+ border-radius: var(--button-bar-border-radius);
border: none;
margin: 0;
padding: 0;
@@ -106,7 +106,8 @@ export class HaTileButton extends LitElement {
outline: none;
overflow: hidden;
background: none;
- --mdc-ripple-color: var(--tile-button-background-color);
+ z-index: 1;
+ --mdc-ripple-color: var(--button-bar-background-color);
}
.button::before {
content: "";
@@ -115,22 +116,21 @@ export class HaTileButton extends LitElement {
left: 0;
height: 100%;
width: 100%;
- background-color: var(--tile-button-background-color);
+ background-color: var(--button-bar-background-color);
transition: background-color 180ms ease-in-out,
opacity 180ms ease-in-out;
- opacity: var(--tile-button-background-opacity);
+ opacity: var(--button-bar-background-opacity);
}
.button ::slotted(*) {
- --mdc-icon-size: 20px;
transition: color 180ms ease-in-out;
- color: var(--tile-button-icon-color);
+ color: var(--button-bar-icon-color);
pointer-events: none;
}
.button:disabled {
cursor: not-allowed;
- --tile-button-background-color: var(--disabled-color);
- --tile-button-icon-color: var(--disabled-text-color);
- --tile-button-background-opacity: 0.2;
+ --button-bar-background-color: var(--disabled-color);
+ --button-bar-icon-color: var(--disabled-text-color);
+ --button-bar-background-opacity: 0.2;
}
`;
}
@@ -138,6 +138,6 @@ export class HaTileButton extends LitElement {
declare global {
interface HTMLElementTagNameMap {
- "ha-tile-button": HaTileButton;
+ "ha-bar-button": HaBarButton;
}
}
diff --git a/src/panels/lovelace/tile-features/hui-cover-open-close-tile-feature.ts b/src/panels/lovelace/tile-features/hui-cover-open-close-tile-feature.ts
index 05d4e6dce7..6f75c8c4cf 100644
--- a/src/panels/lovelace/tile-features/hui-cover-open-close-tile-feature.ts
+++ b/src/panels/lovelace/tile-features/hui-cover-open-close-tile-feature.ts
@@ -7,7 +7,8 @@ import {
computeOpenIcon,
} from "../../../common/entity/cover_icon";
import { supportsFeature } from "../../../common/entity/supports-feature";
-import "../../../components/tile/ha-tile-button";
+import "../../../components/ha-bar-button";
+import "../../../components/ha-bar-button-group";
import {
canClose,
canOpen,
@@ -69,10 +70,10 @@ class HuiCoverOpenCloseTileFeature
}
return html`
-
+
${supportsFeature(this.stateObj, CoverEntityFeature.OPEN)
? html`
-
-
+
`
: null}
${supportsFeature(this.stateObj, CoverEntityFeature.STOP)
? html`
-
-
+
`
: null}
${supportsFeature(this.stateObj, CoverEntityFeature.CLOSE)
? html`
-
-
+
`
: undefined}
-
+
`;
}
static get styles() {
return css`
- .container {
- display: flex;
- flex-direction: row;
- padding: 0 12px 12px 12px;
- width: auto;
- }
- ha-tile-button {
- flex: 1;
- }
- ha-tile-button:not(:last-child) {
- margin-right: 12px;
- margin-inline-end: 12px;
- margin-inline-start: initial;
- direction: var(--direction);
+ ha-bar-button-group {
+ margin: 0 12px 12px 12px;
+ --button-bar-group-spacing: 12px;
}
`;
}
diff --git a/src/panels/lovelace/tile-features/hui-cover-tilt-tile-feature.ts b/src/panels/lovelace/tile-features/hui-cover-tilt-tile-feature.ts
index 018a0fb307..ca22b29fc1 100644
--- a/src/panels/lovelace/tile-features/hui-cover-tilt-tile-feature.ts
+++ b/src/panels/lovelace/tile-features/hui-cover-tilt-tile-feature.ts
@@ -3,7 +3,8 @@ import { HassEntity } from "home-assistant-js-websocket";
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { supportsFeature } from "../../../common/entity/supports-feature";
-import "../../../components/tile/ha-tile-button";
+import "../../../components/ha-bar-button";
+import "../../../components/ha-bar-button-group";
import {
canCloseTilt,
canOpenTilt,
@@ -65,10 +66,10 @@ class HuiCoverTiltTileFeature
}
return html`
-
+
${supportsFeature(this.stateObj, CoverEntityFeature.OPEN_TILT)
? html`
-
-
+
`
: null}
${supportsFeature(this.stateObj, CoverEntityFeature.STOP_TILT)
? html`
-
-
+
`
: null}
${supportsFeature(this.stateObj, CoverEntityFeature.CLOSE_TILT)
? html`
-
-
+
`
: undefined}
-
+
`;
}
static get styles() {
return css`
- .container {
- display: flex;
- flex-direction: row;
- padding: 0 12px 12px 12px;
- width: auto;
- }
- ha-tile-button {
- flex: 1;
- }
- ha-tile-button:not(:last-child) {
- margin-right: 12px;
- margin-inline-end: 12px;
- margin-inline-start: initial;
- direction: var(--direction);
+ ha-bar-button-group {
+ margin: 0 12px 12px 12px;
+ --button-bar-group-spacing: 12px;
}
`;
}
diff --git a/src/panels/lovelace/tile-features/hui-vacuum-commands-tile-feature.ts b/src/panels/lovelace/tile-features/hui-vacuum-commands-tile-feature.ts
index 6c19958a77..b99671770e 100644
--- a/src/panels/lovelace/tile-features/hui-vacuum-commands-tile-feature.ts
+++ b/src/panels/lovelace/tile-features/hui-vacuum-commands-tile-feature.ts
@@ -11,7 +11,8 @@ import { HassEntity } from "home-assistant-js-websocket";
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { supportsFeature } from "../../../common/entity/supports-feature";
-import "../../../components/tile/ha-tile-button";
+import "../../../components/ha-bar-button";
+import "../../../components/ha-bar-button-group";
import { UNAVAILABLE } from "../../../data/entity";
import {
canReturnHome,
@@ -167,7 +168,7 @@ class HuiVacuumCommandTileFeature
const stateObj = this.stateObj as VacuumEntity;
return html`
-
+
${VACUUM_COMMANDS.filter(
(command) =>
supportsVacuumCommand(stateObj, command) &&
@@ -175,7 +176,7 @@ class HuiVacuumCommandTileFeature
).map((command) => {
const button = VACUUM_COMMANDS_BUTTONS[command](stateObj);
return html`
-
-
+
`;
})}
-
+
`;
}
static get styles() {
return css`
- .container {
- display: flex;
- flex-direction: row;
- padding: 0 12px 12px 12px;
- width: auto;
- }
- ha-tile-button {
- flex: 1;
- }
- ha-tile-button:not(:last-child) {
- margin-right: 12px;
- margin-inline-end: 12px;
- margin-inline-start: initial;
- direction: var(--direction);
+ ha-bar-button-group {
+ margin: 0 12px 12px 12px;
+ --button-bar-group-spacing: 12px;
}
`;
}