mirror of
https://github.com/home-assistant/frontend.git
synced 2025-11-12 12:30:47 +00:00
Compare commits
1 Commits
feature/ti
...
grid_secti
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b065799bf |
@@ -17,6 +17,10 @@ export interface LovelaceSectionConfig extends LovelaceBaseSectionConfig {
|
|||||||
cards?: LovelaceCardConfig[];
|
cards?: LovelaceCardConfig[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface LovelaceGridSectionConfig extends LovelaceSectionConfig {
|
||||||
|
grid_base?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface LovelaceStrategySectionConfig
|
export interface LovelaceStrategySectionConfig
|
||||||
extends LovelaceBaseSectionConfig {
|
extends LovelaceBaseSectionConfig {
|
||||||
strategy: LovelaceStrategyConfig;
|
strategy: LovelaceStrategyConfig;
|
||||||
|
|||||||
@@ -3,12 +3,15 @@ import "@material/mwc-tab/mwc-tab";
|
|||||||
import { CSSResultGroup, TemplateResult, css, html, nothing } from "lit";
|
import { CSSResultGroup, TemplateResult, css, html, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
|
import { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
|
||||||
|
import {
|
||||||
|
LovelaceGridSectionConfig,
|
||||||
|
LovelaceSectionConfig,
|
||||||
|
} from "../../../../data/lovelace/config/section";
|
||||||
import { getCardElementClass } from "../../create-element/create-card-element";
|
import { getCardElementClass } from "../../create-element/create-card-element";
|
||||||
import type { LovelaceCardEditor, LovelaceConfigForm } from "../../types";
|
import type { LovelaceCardEditor, LovelaceConfigForm } from "../../types";
|
||||||
import { HuiTypedElementEditor } from "../hui-typed-element-editor";
|
import { HuiTypedElementEditor } from "../hui-typed-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;
|
||||||
|
|
||||||
@@ -59,7 +62,7 @@ export class HuiCardElementEditor extends HuiTypedElementEditor<LovelaceCardConf
|
|||||||
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.sectionConfig?.type === "grid") displayedTabs.push("layout");
|
||||||
|
|
||||||
if (displayedTabs.length === 1) return super.renderConfigElement();
|
if (displayedTabs.length === 1) return super.renderConfigElement();
|
||||||
|
|
||||||
@@ -83,8 +86,8 @@ export class HuiCardElementEditor extends HuiTypedElementEditor<LovelaceCardConf
|
|||||||
<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}
|
||||||
|
.sectionConfig=${this.sectionConfig as LovelaceGridSectionConfig}
|
||||||
>
|
>
|
||||||
</hui-card-layout-editor>
|
</hui-card-layout-editor>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ 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 {
|
||||||
|
LovelaceGridSectionConfig,
|
||||||
|
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";
|
||||||
@@ -27,6 +30,7 @@ import {
|
|||||||
CardGridSize,
|
CardGridSize,
|
||||||
computeCardGridSize,
|
computeCardGridSize,
|
||||||
} from "../../common/compute-card-grid-size";
|
} from "../../common/compute-card-grid-size";
|
||||||
|
import { DEFAULT_GRID_BASE } from "../../sections/hui-grid-section";
|
||||||
import { LovelaceLayoutOptions } from "../../types";
|
import { LovelaceLayoutOptions } from "../../types";
|
||||||
|
|
||||||
@customElement("hui-card-layout-editor")
|
@customElement("hui-card-layout-editor")
|
||||||
@@ -72,7 +76,10 @@ export class HuiCardLayoutEditor extends LitElement {
|
|||||||
|
|
||||||
const value = this._computeCardGridSize(options);
|
const value = this._computeCardGridSize(options);
|
||||||
|
|
||||||
const totalColumns = (this.sectionConfig.column_span ?? 1) * 4;
|
const totalColumns =
|
||||||
|
(this.sectionConfig.column_span ?? 1) *
|
||||||
|
((this.sectionConfig as LovelaceGridSectionConfig).grid_base ||
|
||||||
|
DEFAULT_GRID_BASE);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="header">
|
<div class="header">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { LitElement, html } from "lit";
|
import { html, LitElement } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
@@ -6,12 +6,21 @@ import {
|
|||||||
HaFormSchema,
|
HaFormSchema,
|
||||||
SchemaUnion,
|
SchemaUnion,
|
||||||
} from "../../../../components/ha-form/types";
|
} from "../../../../components/ha-form/types";
|
||||||
import { LovelaceSectionRawConfig } from "../../../../data/lovelace/config/section";
|
import {
|
||||||
|
isStrategySection,
|
||||||
|
LovelaceGridSectionConfig,
|
||||||
|
LovelaceSectionRawConfig,
|
||||||
|
} from "../../../../data/lovelace/config/section";
|
||||||
import { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
|
import { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
|
||||||
import { HomeAssistant } from "../../../../types";
|
import { HomeAssistant } from "../../../../types";
|
||||||
|
import { LocalizeFunc } from "../../../../common/translations/localize";
|
||||||
|
import { DEFAULT_GRID_BASE } from "../../sections/hui-grid-section";
|
||||||
|
|
||||||
|
type GridDensity = "default" | "dense" | "custom";
|
||||||
|
|
||||||
type SettingsData = {
|
type SettingsData = {
|
||||||
column_span?: number;
|
column_span?: number;
|
||||||
|
grid_density?: GridDensity;
|
||||||
};
|
};
|
||||||
|
|
||||||
@customElement("hui-section-settings-editor")
|
@customElement("hui-section-settings-editor")
|
||||||
@@ -23,27 +32,89 @@ export class HuiDialogEditSection extends LitElement {
|
|||||||
@property({ attribute: false }) public viewConfig!: LovelaceViewConfig;
|
@property({ attribute: false }) public viewConfig!: LovelaceViewConfig;
|
||||||
|
|
||||||
private _schema = memoizeOne(
|
private _schema = memoizeOne(
|
||||||
(maxColumns: number) =>
|
(
|
||||||
|
maxColumns: number,
|
||||||
|
localize: LocalizeFunc,
|
||||||
|
type?: string | undefined,
|
||||||
|
columnDensity?: GridDensity,
|
||||||
|
columnBase?: number
|
||||||
|
) =>
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name: "column_span",
|
name: "title",
|
||||||
selector: {
|
selector: { text: {} },
|
||||||
number: {
|
|
||||||
min: 1,
|
|
||||||
max: maxColumns,
|
|
||||||
slider_ticks: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
...(type === "grid"
|
||||||
|
? ([
|
||||||
|
{
|
||||||
|
name: "grid_density",
|
||||||
|
default: "default",
|
||||||
|
selector: {
|
||||||
|
select: {
|
||||||
|
mode: "list",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: localize(
|
||||||
|
`ui.panel.lovelace.editor.edit_section.settings.grid_density_options.default`,
|
||||||
|
{ count: 4 }
|
||||||
|
),
|
||||||
|
value: "default",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: localize(
|
||||||
|
`ui.panel.lovelace.editor.edit_section.settings.grid_density_options.dense`,
|
||||||
|
{ count: 6 }
|
||||||
|
),
|
||||||
|
value: "dense",
|
||||||
|
},
|
||||||
|
...(columnDensity === "custom" && columnBase
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
label: localize(
|
||||||
|
`ui.panel.lovelace.editor.edit_section.settings.grid_density_options.custom`,
|
||||||
|
{ count: columnBase }
|
||||||
|
),
|
||||||
|
value: "custom",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
] as const satisfies readonly HaFormSchema[])
|
||||||
|
: []),
|
||||||
] as const satisfies HaFormSchema[]
|
] as const satisfies HaFormSchema[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private _isGridSectionConfig(
|
||||||
|
config: LovelaceSectionRawConfig
|
||||||
|
): config is LovelaceGridSectionConfig {
|
||||||
|
return !isStrategySection(config) && config.type === "grid";
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const gridBase = this._isGridSectionConfig(this.config)
|
||||||
|
? this.config.grid_base || DEFAULT_GRID_BASE
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const columnDensity =
|
||||||
|
gridBase === 6 ? "dense" : gridBase === 4 ? "default" : "custom";
|
||||||
|
|
||||||
const data: SettingsData = {
|
const data: SettingsData = {
|
||||||
column_span: this.config.column_span || 1,
|
column_span: this.config.column_span || 1,
|
||||||
|
grid_density: columnDensity,
|
||||||
};
|
};
|
||||||
|
|
||||||
const schema = this._schema(this.viewConfig.max_columns || 4);
|
const type = "type" in this.config ? this.config.type : undefined;
|
||||||
|
|
||||||
|
const schema = this._schema(
|
||||||
|
this.viewConfig.max_columns || 4,
|
||||||
|
this.hass.localize,
|
||||||
|
type,
|
||||||
|
columnDensity,
|
||||||
|
gridBase
|
||||||
|
);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-form
|
<ha-form
|
||||||
@@ -75,11 +146,26 @@ export class HuiDialogEditSection extends LitElement {
|
|||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
const newData = ev.detail.value as SettingsData;
|
const newData = ev.detail.value as SettingsData;
|
||||||
|
|
||||||
|
const { column_span, grid_density } = newData;
|
||||||
|
|
||||||
const newConfig: LovelaceSectionRawConfig = {
|
const newConfig: LovelaceSectionRawConfig = {
|
||||||
...this.config,
|
...this.config,
|
||||||
column_span: newData.column_span,
|
column_span: column_span,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (this._isGridSectionConfig(newConfig)) {
|
||||||
|
const gridBase =
|
||||||
|
grid_density === "default"
|
||||||
|
? 4
|
||||||
|
: grid_density === "dense"
|
||||||
|
? 6
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (gridBase) {
|
||||||
|
(newConfig as LovelaceGridSectionConfig).grid_base = gridBase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fireEvent(this, "value-changed", { value: newConfig });
|
fireEvent(this, "value-changed", { value: newConfig });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { fireEvent } from "../../../common/dom/fire_event";
|
|||||||
import type { HaSortableOptions } from "../../../components/ha-sortable";
|
import type { HaSortableOptions } from "../../../components/ha-sortable";
|
||||||
import { LovelaceSectionElement } from "../../../data/lovelace";
|
import { LovelaceSectionElement } from "../../../data/lovelace";
|
||||||
import { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
import { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||||
import type { LovelaceSectionConfig } from "../../../data/lovelace/config/section";
|
import type { LovelaceGridSectionConfig } from "../../../data/lovelace/config/section";
|
||||||
import { haStyle } from "../../../resources/styles";
|
import { haStyle } from "../../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
import { HuiCard } from "../cards/hui-card";
|
import { HuiCard } from "../cards/hui-card";
|
||||||
@@ -24,6 +24,8 @@ const CARD_SORTABLE_OPTIONS: HaSortableOptions = {
|
|||||||
invertedSwapThreshold: 0.7,
|
invertedSwapThreshold: 0.7,
|
||||||
} as HaSortableOptions;
|
} as HaSortableOptions;
|
||||||
|
|
||||||
|
export const DEFAULT_GRID_BASE = 4;
|
||||||
|
|
||||||
export class GridSection extends LitElement implements LovelaceSectionElement {
|
export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@@ -37,11 +39,11 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
|||||||
|
|
||||||
@property({ attribute: false }) public cards: HuiCard[] = [];
|
@property({ attribute: false }) public cards: HuiCard[] = [];
|
||||||
|
|
||||||
@state() _config?: LovelaceSectionConfig;
|
@state() _config?: LovelaceGridSectionConfig;
|
||||||
|
|
||||||
@state() _dragging = false;
|
@state() _dragging = false;
|
||||||
|
|
||||||
public setConfig(config: LovelaceSectionConfig): void {
|
public setConfig(config: LovelaceGridSectionConfig): void {
|
||||||
this._config = config;
|
this._config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +66,8 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
|||||||
|
|
||||||
const editMode = Boolean(this.lovelace?.editMode && !this.isStrategy);
|
const editMode = Boolean(this.lovelace?.editMode && !this.isStrategy);
|
||||||
|
|
||||||
|
const columnCount = this._config.grid_base ?? DEFAULT_GRID_BASE;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-sortable
|
<ha-sortable
|
||||||
.disabled=${!editMode}
|
.disabled=${!editMode}
|
||||||
@@ -77,7 +81,10 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
|||||||
.options=${CARD_SORTABLE_OPTIONS}
|
.options=${CARD_SORTABLE_OPTIONS}
|
||||||
invert-swap
|
invert-swap
|
||||||
>
|
>
|
||||||
<div class="container ${classMap({ "edit-mode": editMode })}">
|
<div
|
||||||
|
class="container ${classMap({ "edit-mode": editMode })}"
|
||||||
|
style=${styleMap({ "--column-count": columnCount })}
|
||||||
|
>
|
||||||
${repeat(
|
${repeat(
|
||||||
cardsConfig,
|
cardsConfig,
|
||||||
(cardConfig) => this._getKey(cardConfig),
|
(cardConfig) => this._getKey(cardConfig),
|
||||||
@@ -165,7 +172,6 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
|||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
--base-column-count: 4;
|
|
||||||
--row-gap: var(--ha-section-grid-row-gap, 8px);
|
--row-gap: var(--ha-section-grid-row-gap, 8px);
|
||||||
--column-gap: var(--ha-section-grid-column-gap, 8px);
|
--column-gap: var(--ha-section-grid-column-gap, 8px);
|
||||||
--row-height: var(--ha-section-grid-row-height, 56px);
|
--row-height: var(--ha-section-grid-row-height, 56px);
|
||||||
@@ -175,7 +181,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
|||||||
}
|
}
|
||||||
.container {
|
.container {
|
||||||
--grid-column-count: calc(
|
--grid-column-count: calc(
|
||||||
var(--base-column-count) * var(--column-span, 1)
|
var(--column-count, 4) * var(--column-span, 1)
|
||||||
);
|
);
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(
|
grid-template-columns: repeat(
|
||||||
|
|||||||
@@ -5714,7 +5714,13 @@
|
|||||||
"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": "Width",
|
"column_span": "Width",
|
||||||
"column_span_helper": "Larger sections will be made smaller to fit the display. (e.g. on mobile devices)"
|
"column_span_helper": "Larger sections will be made smaller to fit the display. (e.g. on mobile devices)",
|
||||||
|
"grid_density": "Grid density",
|
||||||
|
"grid_density_options": {
|
||||||
|
"default": "Default ({count} columns)",
|
||||||
|
"dense": "Dense ({count} columns)",
|
||||||
|
"custom": "Custom ({count} {count, plural,\n one {column}\n other {columns}\n})"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"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."
|
||||||
|
|||||||
Reference in New Issue
Block a user