Compare commits

..
2 changed files with 105 additions and 9 deletions

No files matched your search

@@ -3,6 +3,8 @@ import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { consumeLocalize } from "../../../../common/decorators/consume-context-entry";
import { fireEvent } from "../../../../common/dom/fire_event";
import { listenMediaQuery } from "../../../../common/dom/media_query";
import { clamp } from "../../../../common/number/clamp";
import { slugify } from "../../../../common/string/slugify";
import type { LocalizeFunc } from "../../../../common/translations/localize";
import "../../../../components/ha-form/ha-form";
@@ -32,6 +34,37 @@ declare global {
const VALID_PATH_REGEX = /^[a-zA-Z0-9_-]+$/;
const INTEGER_REGEX = /^[0-9]+$/;
const MAX_COLUMNS_PRESETS = [1, 2, 3, 4] as const;
const MAX_COLUMNS_MORE = "more";
const MIN_CUSTOM_MAX_COLUMNS = MAX_COLUMNS_PRESETS.length + 1;
const MAX_CUSTOM_MAX_COLUMNS = 10;
interface MaxColumnsFormData {
max_columns: string;
max_columns_custom?: number;
}
const maxColumnsToFormData = (maxColumns: number): MaxColumnsFormData => {
if (maxColumns <= MAX_COLUMNS_PRESETS.length) {
return {
max_columns: String(maxColumns),
max_columns_custom: MIN_CUSTOM_MAX_COLUMNS,
};
}
return { max_columns: MAX_COLUMNS_MORE, max_columns_custom: maxColumns };
};
const maxColumnsFromFormData = (data: MaxColumnsFormData): number => {
if (data.max_columns !== MAX_COLUMNS_MORE) {
return Number(data.max_columns);
}
return clamp(
data.max_columns_custom ?? MIN_CUSTOM_MAX_COLUMNS,
MIN_CUSTOM_MAX_COLUMNS,
MAX_CUSTOM_MAX_COLUMNS
);
};
@customElement("hui-view-editor")
export class HuiViewEditor extends LitElement {
@consumeLocalize()
@@ -43,10 +76,27 @@ export class HuiViewEditor extends LitElement {
@state() private _error: Record<string, string> | undefined;
@state() private _narrow = false;
private _unsubMql?: () => void;
private _suggestedPath = false;
connectedCallback(): void {
super.connectedCallback();
this._unsubMql = listenMediaQuery("(max-width: 600px)", (matches) => {
this._narrow = matches;
});
}
public disconnectedCallback() {
super.disconnectedCallback();
this._unsubMql?.();
this._unsubMql = undefined;
}
private _schema = memoizeOne(
(localize: LocalizeFunc) =>
(localize: LocalizeFunc, narrow: boolean) =>
[
{
name: "type",
@@ -101,13 +151,33 @@ export class HuiViewEditor extends LitElement {
schema: [
{
name: "max_columns",
default: DEFAULT_MAX_COLUMNS,
selector: {
select: {
mode: "box",
box_max_columns: narrow ? 3 : 5,
options: [
...MAX_COLUMNS_PRESETS.map((count) => ({
value: String(count),
label: String(count),
})),
{
value: MAX_COLUMNS_MORE,
label: localize(
"ui.panel.lovelace.editor.edit_view.max_columns_more"
),
},
],
},
},
},
{
name: "max_columns_custom",
visible: { field: "max_columns", value: MAX_COLUMNS_MORE },
selector: {
number: {
min: 1,
max: 10,
mode: "slider",
slider_ticks: true,
min: MIN_CUSTOM_MAX_COLUMNS,
max: MAX_CUSTOM_MAX_COLUMNS,
mode: "box",
},
},
},
@@ -132,6 +202,10 @@ export class HuiViewEditor extends LitElement {
this._config = config;
}
private get _maxColumns(): number {
return this._config.max_columns ?? DEFAULT_MAX_COLUMNS;
}
get _type(): string {
return getViewType(this._config);
}
@@ -139,6 +213,7 @@ export class HuiViewEditor extends LitElement {
protected render() {
const data = {
...this._config,
...maxColumnsToFormData(this._maxColumns),
type: this._type,
theme:
this._config.theme?.toLowerCase() === "backend-selected"
@@ -149,7 +224,7 @@ export class HuiViewEditor extends LitElement {
return html`
<ha-form
.data=${data}
.schema=${this._schema(this._localize)}
.schema=${this._schema(this._localize, this._narrow)}
.computeLabel=${this._computeLabel}
.computeHelper=${this._computeHelper}
.computeError=${this._computeError}
@@ -160,7 +235,23 @@ export class HuiViewEditor extends LitElement {
}
private _valueChanged(ev: CustomEvent): void {
const config = ev.detail.value as LovelaceViewConfig;
const {
max_columns: maxColumnsChoice,
max_columns_custom: maxColumnsCustom,
...rest
} = ev.detail.value as Omit<LovelaceViewConfig, "max_columns"> &
MaxColumnsFormData;
const config: LovelaceViewConfig = rest;
const maxColumns = maxColumnsFromFormData({
max_columns: maxColumnsChoice,
max_columns_custom: maxColumnsCustom,
});
if (maxColumns !== this._maxColumns) {
config.max_columns = maxColumns;
} else if (this._config.max_columns !== undefined) {
config.max_columns = this._config.max_columns;
}
if (config.type !== SECTIONS_VIEW_LAYOUT) {
delete config.max_columns;
@@ -211,6 +302,7 @@ export class HuiViewEditor extends LitElement {
case "show_icon_and_title":
case "subview":
case "max_columns":
case "max_columns_custom":
case "dense_section_placement":
case "top_margin":
case "section_specifics":
@@ -231,6 +323,7 @@ export class HuiViewEditor extends LitElement {
case "path":
case "show_icon_and_title":
case "subview":
case "max_columns":
case "dense_section_placement":
case "top_margin":
return this._localize(
+4 -1
View File
@@ -9972,7 +9972,10 @@
},
"show_icon_and_title": "Show icon and title",
"subview": "Subview",
"max_columns": "Max number of sections wide",
"max_columns": "Max sections side by side",
"max_columns_helper": "Smaller screens fit fewer side by side, and phones stack them one under the other.",
"max_columns_more": "More",
"max_columns_custom": "Number of sections",
"section_specifics": "Sections view specific settings",
"dense_section_placement": "Dense section placement",
"dense_section_placement_helper": "Will try to fill gaps with sections that fit the gap. This may make section placement less predictable.",