mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-26 18:56:39 +00:00
Column span better editor (#21820)
* Add label, unit and max for column span option * Display the right number of columns in the layout editor * improve translations
This commit is contained in:
parent
8b5f731d0c
commit
c556742ff4
@ -213,7 +213,7 @@ export class HaGridSizeEditor extends LitElement {
|
|||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"reset column-slider"
|
"reset column-slider"
|
||||||
"row-slider preview";
|
"row-slider preview";
|
||||||
grid-template-rows: auto 1fr;
|
grid-template-rows: auto auto;
|
||||||
grid-template-columns: auto 1fr;
|
grid-template-columns: auto 1fr;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
@ -229,17 +229,12 @@ export class HaGridSizeEditor extends LitElement {
|
|||||||
.preview {
|
.preview {
|
||||||
position: relative;
|
position: relative;
|
||||||
grid-area: preview;
|
grid-area: preview;
|
||||||
aspect-ratio: 1 / 1.2;
|
|
||||||
}
|
}
|
||||||
.preview > div {
|
.preview > div {
|
||||||
position: absolute;
|
position: relative;
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(var(--total-columns), 1fr);
|
grid-template-columns: repeat(var(--total-columns), 1fr);
|
||||||
grid-template-rows: repeat(var(--total-rows), 1fr);
|
grid-template-rows: repeat(var(--total-rows), 25px);
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
.preview .cell {
|
.preview .cell {
|
||||||
@ -250,8 +245,13 @@ export class HaGridSizeEditor extends LitElement {
|
|||||||
opacity: 0.2;
|
opacity: 0.2;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.selected {
|
.preview .selected {
|
||||||
|
position: absolute;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
.selected .cell {
|
.selected .cell {
|
||||||
background-color: var(--primary-color);
|
background-color: var(--primary-color);
|
||||||
|
@ -8,6 +8,7 @@ import type { LovelaceCardEditor, LovelaceConfigForm } from "../../types";
|
|||||||
import { HuiElementEditor } from "../hui-element-editor";
|
import { HuiElementEditor } from "../hui-element-editor";
|
||||||
import "./hui-card-layout-editor";
|
import "./hui-card-layout-editor";
|
||||||
import "./hui-card-visibility-editor";
|
import "./hui-card-visibility-editor";
|
||||||
|
import { LovelaceSectionConfig } from "../../../../data/lovelace/config/section";
|
||||||
|
|
||||||
const tabs = ["config", "visibility", "layout"] as const;
|
const tabs = ["config", "visibility", "layout"] as const;
|
||||||
|
|
||||||
@ -16,8 +17,7 @@ export class HuiCardElementEditor extends HuiElementEditor<LovelaceCardConfig> {
|
|||||||
@property({ type: Boolean, attribute: "show-visibility-tab" })
|
@property({ type: Boolean, attribute: "show-visibility-tab" })
|
||||||
public showVisibilityTab = false;
|
public showVisibilityTab = false;
|
||||||
|
|
||||||
@property({ type: Boolean, attribute: "show-layout-tab" })
|
@property({ attribute: false }) public sectionConfig?: LovelaceSectionConfig;
|
||||||
public showLayoutTab = false;
|
|
||||||
|
|
||||||
@state() private _currTab: (typeof tabs)[number] = tabs[0];
|
@state() private _currTab: (typeof tabs)[number] = tabs[0];
|
||||||
|
|
||||||
@ -48,10 +48,18 @@ export class HuiCardElementEditor extends HuiElementEditor<LovelaceCardConfig> {
|
|||||||
this.value = ev.detail.value;
|
this.value = ev.detail.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get _showLayoutTab(): boolean {
|
||||||
|
return (
|
||||||
|
!!this.sectionConfig &&
|
||||||
|
(this.sectionConfig.type === undefined ||
|
||||||
|
this.sectionConfig.type === "grid")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
protected renderConfigElement(): TemplateResult {
|
protected renderConfigElement(): TemplateResult {
|
||||||
const displayedTabs: string[] = ["config"];
|
const displayedTabs: string[] = ["config"];
|
||||||
if (this.showVisibilityTab) displayedTabs.push("visibility");
|
if (this.showVisibilityTab) displayedTabs.push("visibility");
|
||||||
if (this.showLayoutTab) displayedTabs.push("layout");
|
if (this._showLayoutTab) displayedTabs.push("layout");
|
||||||
|
|
||||||
if (displayedTabs.length === 1) return super.renderConfigElement();
|
if (displayedTabs.length === 1) return super.renderConfigElement();
|
||||||
|
|
||||||
@ -75,6 +83,7 @@ export class HuiCardElementEditor extends HuiElementEditor<LovelaceCardConfig> {
|
|||||||
<hui-card-layout-editor
|
<hui-card-layout-editor
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.config=${this.value}
|
.config=${this.value}
|
||||||
|
.sectionConfig=${this.sectionConfig!}
|
||||||
@value-changed=${this._configChanged}
|
@value-changed=${this._configChanged}
|
||||||
>
|
>
|
||||||
</hui-card-layout-editor>
|
</hui-card-layout-editor>
|
||||||
|
@ -2,13 +2,13 @@ import type { ActionDetail } from "@material/mwc-list";
|
|||||||
import { mdiCheck, mdiDotsVertical } from "@mdi/js";
|
import { mdiCheck, mdiDotsVertical } from "@mdi/js";
|
||||||
import { css, html, LitElement, nothing, PropertyValues } from "lit";
|
import { css, html, LitElement, nothing, PropertyValues } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
|
import { styleMap } from "lit/directives/style-map";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import { preventDefault } from "../../../../common/dom/prevent_default";
|
import { preventDefault } from "../../../../common/dom/prevent_default";
|
||||||
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
||||||
import "../../../../components/ha-button";
|
import "../../../../components/ha-button";
|
||||||
import "../../../../components/ha-button-menu";
|
import "../../../../components/ha-button-menu";
|
||||||
import "../../../../components/ha-formfield";
|
|
||||||
import "../../../../components/ha-grid-size-picker";
|
import "../../../../components/ha-grid-size-picker";
|
||||||
import "../../../../components/ha-icon-button";
|
import "../../../../components/ha-icon-button";
|
||||||
import "../../../../components/ha-list-item";
|
import "../../../../components/ha-list-item";
|
||||||
@ -19,6 +19,7 @@ import "../../../../components/ha-switch";
|
|||||||
import "../../../../components/ha-yaml-editor";
|
import "../../../../components/ha-yaml-editor";
|
||||||
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||||
import { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
|
import { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
|
||||||
|
import { LovelaceSectionConfig } from "../../../../data/lovelace/config/section";
|
||||||
import { haStyle } from "../../../../resources/styles";
|
import { haStyle } from "../../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../../types";
|
import { HomeAssistant } from "../../../../types";
|
||||||
import { HuiCard } from "../../cards/hui-card";
|
import { HuiCard } from "../../cards/hui-card";
|
||||||
@ -34,6 +35,8 @@ export class HuiCardLayoutEditor extends LitElement {
|
|||||||
|
|
||||||
@property({ attribute: false }) public config!: LovelaceCardConfig;
|
@property({ attribute: false }) public config!: LovelaceCardConfig;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public sectionConfig!: LovelaceSectionConfig;
|
||||||
|
|
||||||
@state() _defaultLayoutOptions?: LovelaceLayoutOptions;
|
@state() _defaultLayoutOptions?: LovelaceLayoutOptions;
|
||||||
|
|
||||||
@state() public _yamlMode = false;
|
@state() public _yamlMode = false;
|
||||||
@ -69,6 +72,8 @@ export class HuiCardLayoutEditor extends LitElement {
|
|||||||
|
|
||||||
const value = this._computeCardGridSize(options);
|
const value = this._computeCardGridSize(options);
|
||||||
|
|
||||||
|
const totalColumns = (this.sectionConfig.column_span ?? 1) * 4;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<p class="intro">
|
<p class="intro">
|
||||||
@ -131,6 +136,10 @@ export class HuiCardLayoutEditor extends LitElement {
|
|||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<ha-grid-size-picker
|
<ha-grid-size-picker
|
||||||
|
style=${styleMap({
|
||||||
|
"max-width": `${totalColumns * 45 + 50}px`,
|
||||||
|
})}
|
||||||
|
.columns=${totalColumns}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.value=${value}
|
.value=${value}
|
||||||
.isDefault=${this._isDefault(this.config.layout_options)}
|
.isDefault=${this._isDefault(this.config.layout_options)}
|
||||||
@ -292,20 +301,12 @@ export class HuiCardLayoutEditor extends LitElement {
|
|||||||
}
|
}
|
||||||
ha-grid-size-picker {
|
ha-grid-size-picker {
|
||||||
display: block;
|
display: block;
|
||||||
max-width: 250px;
|
|
||||||
margin: 16px auto;
|
margin: 16px auto;
|
||||||
}
|
}
|
||||||
ha-yaml-editor {
|
ha-yaml-editor {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 16px 0;
|
margin: 16px 0;
|
||||||
}
|
}
|
||||||
ha-formfield {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
--mdc-typography-body2-font-size: 1em;
|
|
||||||
max-width: 250px;
|
|
||||||
margin: 16px auto;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -236,8 +236,10 @@ export class HuiDialogEditCard
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="element-editor">
|
<div class="element-editor">
|
||||||
<hui-card-element-editor
|
<hui-card-element-editor
|
||||||
.showLayoutTab=${this._shouldShowLayoutTab()}
|
|
||||||
.showVisibilityTab=${this._cardConfig?.type !== "conditional"}
|
.showVisibilityTab=${this._cardConfig?.type !== "conditional"}
|
||||||
|
.sectionConfig=${this._isInSection
|
||||||
|
? this._containerConfig
|
||||||
|
: undefined}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.lovelace=${this._params.lovelaceConfig}
|
.lovelace=${this._params.lovelaceConfig}
|
||||||
.value=${this._cardConfig}
|
.value=${this._cardConfig}
|
||||||
@ -353,18 +355,6 @@ export class HuiDialogEditCard
|
|||||||
return this._params!.path.length === 2;
|
return this._params!.path.length === 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _shouldShowLayoutTab(): boolean {
|
|
||||||
/**
|
|
||||||
* Only show layout tab for cards in a grid section
|
|
||||||
* In the future, every section and view should be able to bring their own editor for layout.
|
|
||||||
* For now, we limit it to grid sections as it's the only section type
|
|
||||||
* */
|
|
||||||
return (
|
|
||||||
this._isInSection &&
|
|
||||||
(!this._containerConfig.type || this._containerConfig.type === "grid")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _cardConfigInSection = memoizeOne(
|
private _cardConfigInSection = memoizeOne(
|
||||||
(cardConfig?: LovelaceCardConfig) => {
|
(cardConfig?: LovelaceCardConfig) => {
|
||||||
const { cards, title, ...containerConfig } = this
|
const { cards, title, ...containerConfig } = this
|
||||||
|
@ -35,6 +35,7 @@ import "./hui-section-visibility-editor";
|
|||||||
import type { EditSectionDialogParams } from "./show-edit-section-dialog";
|
import type { EditSectionDialogParams } from "./show-edit-section-dialog";
|
||||||
import "@material/mwc-tab-bar/mwc-tab-bar";
|
import "@material/mwc-tab-bar/mwc-tab-bar";
|
||||||
import "@material/mwc-tab/mwc-tab";
|
import "@material/mwc-tab/mwc-tab";
|
||||||
|
import { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
|
||||||
|
|
||||||
const TABS = ["tab-settings", "tab-visibility"] as const;
|
const TABS = ["tab-settings", "tab-visibility"] as const;
|
||||||
|
|
||||||
@ -49,6 +50,8 @@ export class HuiDialogEditSection
|
|||||||
|
|
||||||
@state() private _config?: LovelaceSectionRawConfig;
|
@state() private _config?: LovelaceSectionRawConfig;
|
||||||
|
|
||||||
|
@state() private _viewConfig?: LovelaceViewConfig;
|
||||||
|
|
||||||
@state() private _yamlMode = false;
|
@state() private _yamlMode = false;
|
||||||
|
|
||||||
@state() private _currTab: (typeof TABS)[number] = TABS[0];
|
@state() private _currTab: (typeof TABS)[number] = TABS[0];
|
||||||
@ -57,10 +60,10 @@ export class HuiDialogEditSection
|
|||||||
|
|
||||||
protected updated(changedProperties: PropertyValues) {
|
protected updated(changedProperties: PropertyValues) {
|
||||||
if (this._yamlMode && changedProperties.has("_yamlMode")) {
|
if (this._yamlMode && changedProperties.has("_yamlMode")) {
|
||||||
const viewConfig = {
|
const sectionConfig = {
|
||||||
...this._config,
|
...this._config,
|
||||||
};
|
};
|
||||||
this._editor?.setValue(viewConfig);
|
this._editor?.setValue(sectionConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,6 +74,9 @@ export class HuiDialogEditSection
|
|||||||
this._params.viewIndex,
|
this._params.viewIndex,
|
||||||
this._params.sectionIndex,
|
this._params.sectionIndex,
|
||||||
]);
|
]);
|
||||||
|
this._viewConfig = findLovelaceContainer(this._params.lovelaceConfig, [
|
||||||
|
this._params.viewIndex,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeDialog() {
|
public closeDialog() {
|
||||||
@ -107,6 +113,7 @@ export class HuiDialogEditSection
|
|||||||
<hui-section-settings-editor
|
<hui-section-settings-editor
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.config=${this._config}
|
.config=${this._config}
|
||||||
|
.viewConfig=${this._viewConfig}
|
||||||
@value-changed=${this._configChanged}
|
@value-changed=${this._configChanged}
|
||||||
>
|
>
|
||||||
</hui-section-settings-editor>
|
</hui-section-settings-editor>
|
||||||
|
@ -1,23 +1,15 @@
|
|||||||
import { LitElement, html } from "lit";
|
import { LitElement, html } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { LovelaceSectionRawConfig } from "../../../../data/lovelace/config/section";
|
import memoizeOne from "memoize-one";
|
||||||
import { HomeAssistant } from "../../../../types";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import { LocalizeFunc } from "../../../../common/translations/localize";
|
||||||
import {
|
import {
|
||||||
HaFormSchema,
|
HaFormSchema,
|
||||||
SchemaUnion,
|
SchemaUnion,
|
||||||
} from "../../../../components/ha-form/types";
|
} from "../../../../components/ha-form/types";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { LovelaceSectionRawConfig } from "../../../../data/lovelace/config/section";
|
||||||
|
import { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
|
||||||
const SCHEMA = [
|
import { HomeAssistant } from "../../../../types";
|
||||||
{
|
|
||||||
name: "title",
|
|
||||||
selector: { text: {} },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "column_span",
|
|
||||||
selector: { number: { min: 1, max: 3 } },
|
|
||||||
},
|
|
||||||
] as const satisfies HaFormSchema[];
|
|
||||||
|
|
||||||
type SettingsData = {
|
type SettingsData = {
|
||||||
title: string;
|
title: string;
|
||||||
@ -30,17 +22,46 @@ export class HuiDialogEditSection extends LitElement {
|
|||||||
|
|
||||||
@property({ attribute: false }) public config!: LovelaceSectionRawConfig;
|
@property({ attribute: false }) public config!: LovelaceSectionRawConfig;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public viewConfig!: LovelaceViewConfig;
|
||||||
|
|
||||||
|
private _schema = memoizeOne(
|
||||||
|
(localize: LocalizeFunc, maxColumns: number) =>
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: "title",
|
||||||
|
selector: { text: {} },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "column_span",
|
||||||
|
selector: {
|
||||||
|
number: {
|
||||||
|
min: 1,
|
||||||
|
max: maxColumns,
|
||||||
|
unit_of_measurement: localize(
|
||||||
|
`ui.panel.lovelace.editor.edit_section.settings.column_span_unit`
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
] as const satisfies HaFormSchema[]
|
||||||
|
);
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const data: SettingsData = {
|
const data: SettingsData = {
|
||||||
title: this.config.title || "",
|
title: this.config.title || "",
|
||||||
column_span: this.config.column_span || 1,
|
column_span: this.config.column_span || 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const schema = this._schema(
|
||||||
|
this.hass.localize,
|
||||||
|
this.viewConfig.max_columns || 4
|
||||||
|
);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-form
|
<ha-form
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.data=${data}
|
.data=${data}
|
||||||
.schema=${SCHEMA}
|
.schema=${schema}
|
||||||
.computeLabel=${this._computeLabel}
|
.computeLabel=${this._computeLabel}
|
||||||
.computeHelper=${this._computeHelper}
|
.computeHelper=${this._computeHelper}
|
||||||
@value-changed=${this._valueChanged}
|
@value-changed=${this._valueChanged}
|
||||||
@ -48,12 +69,16 @@ export class HuiDialogEditSection extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeLabel = (schema: SchemaUnion<typeof SCHEMA>) =>
|
private _computeLabel = (
|
||||||
|
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||||
|
) =>
|
||||||
this.hass.localize(
|
this.hass.localize(
|
||||||
`ui.panel.lovelace.editor.edit_section.settings.${schema.name}`
|
`ui.panel.lovelace.editor.edit_section.settings.${schema.name}`
|
||||||
);
|
);
|
||||||
|
|
||||||
private _computeHelper = (schema: SchemaUnion<typeof SCHEMA>) =>
|
private _computeHelper = (
|
||||||
|
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||||
|
) =>
|
||||||
this.hass.localize(
|
this.hass.localize(
|
||||||
`ui.panel.lovelace.editor.edit_section.settings.${schema.name}_helper`
|
`ui.panel.lovelace.editor.edit_section.settings.${schema.name}_helper`
|
||||||
) || "";
|
) || "";
|
||||||
|
@ -5661,7 +5661,10 @@
|
|||||||
"edit_yaml": "[%key:ui::panel::lovelace::editor::edit_view::edit_yaml%]",
|
"edit_yaml": "[%key:ui::panel::lovelace::editor::edit_view::edit_yaml%]",
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Title",
|
"title": "Title",
|
||||||
"title_helper": "The title will appear at the top of section. Leave empty to hide the title."
|
"title_helper": "The title will appear at the top of section. Leave empty to hide the title.",
|
||||||
|
"column_span": "Size",
|
||||||
|
"column_span_unit": "columns",
|
||||||
|
"column_span_helper": "The size may be smaller if less columns are displayed (e.g. on mobile devices)."
|
||||||
},
|
},
|
||||||
"visibility": {
|
"visibility": {
|
||||||
"explanation": "The section will be shown when ALL conditions below are fulfilled. If no conditions are set, the section will always be shown."
|
"explanation": "The section will be shown when ALL conditions below are fulfilled. If no conditions are set, the section will always be shown."
|
||||||
|
Loading…
x
Reference in New Issue
Block a user