mirror of
https://github.com/home-assistant/frontend.git
synced 2025-09-04 19:05:22 +00:00
Compare commits
8 Commits
20250401.0
...
column_bre
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1d007a5aaf | ||
![]() |
94c1af7729 | ||
![]() |
d7aaf9bc41 | ||
![]() |
c0aed4325d | ||
![]() |
79a56fabdf | ||
![]() |
14c2b60538 | ||
![]() |
79f3dfdfce | ||
![]() |
3de4dffa02 |
@@ -25,6 +25,8 @@ export interface LovelaceBaseViewConfig {
|
|||||||
// Only used for section view, it should move to a section view config type when the views will have dedicated editor.
|
// Only used for section view, it should move to a section view config type when the views will have dedicated editor.
|
||||||
max_columns?: number;
|
max_columns?: number;
|
||||||
dense_section_placement?: boolean;
|
dense_section_placement?: boolean;
|
||||||
|
column_breakpoints?: Record<string, number>;
|
||||||
|
experimental_breakpoints?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LovelaceViewConfig extends LovelaceBaseViewConfig {
|
export interface LovelaceViewConfig extends LovelaceBaseViewConfig {
|
||||||
|
@@ -12,6 +12,7 @@ import { customElement, property, state } from "lit/decorators";
|
|||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { repeat } from "lit/directives/repeat";
|
import { repeat } from "lit/directives/repeat";
|
||||||
import { styleMap } from "lit/directives/style-map";
|
import { styleMap } from "lit/directives/style-map";
|
||||||
|
import { listenMediaQuery } from "../../../common/dom/media_query";
|
||||||
import "../../../components/ha-icon-button";
|
import "../../../components/ha-icon-button";
|
||||||
import "../../../components/ha-sortable";
|
import "../../../components/ha-sortable";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
@@ -28,8 +29,29 @@ import { showEditSectionDialog } from "../editor/section-editor/show-edit-sectio
|
|||||||
import { HuiSection } from "../sections/hui-section";
|
import { HuiSection } from "../sections/hui-section";
|
||||||
import type { Lovelace } from "../types";
|
import type { Lovelace } from "../types";
|
||||||
|
|
||||||
|
type Breakpoints = Record<string, number>;
|
||||||
|
|
||||||
export const DEFAULT_MAX_COLUMNS = 4;
|
export const DEFAULT_MAX_COLUMNS = 4;
|
||||||
|
|
||||||
|
export const DEFAULT_BREAKPOINTS: Breakpoints = {
|
||||||
|
"0": 1,
|
||||||
|
"768": 2,
|
||||||
|
"1280": 3,
|
||||||
|
"1600": 4,
|
||||||
|
"1920": 5,
|
||||||
|
"2560": 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildMediaQueries = (breakpoints: Breakpoints) =>
|
||||||
|
Object.keys(breakpoints).map((breakpoint, index, array) => {
|
||||||
|
const nextBreakpoint = array[index + 1] as string | undefined;
|
||||||
|
let mediaQuery = `(min-width: ${breakpoint}px)`;
|
||||||
|
if (nextBreakpoint) {
|
||||||
|
mediaQuery += ` and (max-width: ${parseInt(nextBreakpoint) - 1}px)`;
|
||||||
|
}
|
||||||
|
return mediaQuery;
|
||||||
|
});
|
||||||
|
|
||||||
const parsePx = (value: string) => parseInt(value.replace("px", ""));
|
const parsePx = (value: string) => parseInt(value.replace("px", ""));
|
||||||
|
|
||||||
@customElement("hui-sections-view")
|
@customElement("hui-sections-view")
|
||||||
@@ -52,8 +74,15 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
|||||||
|
|
||||||
@state() _dragging = false;
|
@state() _dragging = false;
|
||||||
|
|
||||||
|
private _listeners: Array<() => void> = [];
|
||||||
|
|
||||||
|
@state() private _breakpointsColumns: number = 1;
|
||||||
|
|
||||||
private _columnsController = new ResizeController(this, {
|
private _columnsController = new ResizeController(this, {
|
||||||
callback: (entries) => {
|
callback: (entries) => {
|
||||||
|
// Don't do anything if we are using breakpoints
|
||||||
|
if (this._config?.experimental_breakpoints) return 1;
|
||||||
|
|
||||||
const totalWidth = entries[0]?.contentRect.width;
|
const totalWidth = entries[0]?.contentRect.width;
|
||||||
|
|
||||||
const style = getComputedStyle(this);
|
const style = getComputedStyle(this);
|
||||||
@@ -76,8 +105,13 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private get _sizeColumns() {
|
||||||
|
return this._columnsController.value ?? 1;
|
||||||
|
}
|
||||||
|
|
||||||
public setConfig(config: LovelaceViewConfig): void {
|
public setConfig(config: LovelaceViewConfig): void {
|
||||||
this._config = config;
|
this._config = config;
|
||||||
|
this._attachMediaQueriesListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _sectionConfigKeys = new WeakMap<HuiSection, string>();
|
private _sectionConfigKeys = new WeakMap<HuiSection, string>();
|
||||||
@@ -100,12 +134,35 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
|||||||
this._computeSectionsCount();
|
this._computeSectionsCount();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private _attachMediaQueriesListeners() {
|
||||||
|
this._detachMediaQueriesListeners();
|
||||||
|
if (!this._config?.experimental_breakpoints) return;
|
||||||
|
const breakpoints = this._config?.column_breakpoints ?? DEFAULT_BREAKPOINTS;
|
||||||
|
const maxColumns = this._config?.max_columns ?? DEFAULT_MAX_COLUMNS;
|
||||||
|
const mediaQueries = buildMediaQueries(breakpoints);
|
||||||
|
this._listeners = mediaQueries.map((mediaQuery, index) =>
|
||||||
|
listenMediaQuery(mediaQuery, (matches) => {
|
||||||
|
if (matches) {
|
||||||
|
const columns = Object.values(breakpoints)[index];
|
||||||
|
this._breakpointsColumns = Math.min(maxColumns, columns);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _detachMediaQueriesListeners() {
|
||||||
|
while (this._listeners.length) {
|
||||||
|
this._listeners.pop()!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
this.addEventListener(
|
this.addEventListener(
|
||||||
"section-visibility-changed",
|
"section-visibility-changed",
|
||||||
this._sectionVisibilityChanged
|
this._sectionVisibilityChanged
|
||||||
);
|
);
|
||||||
|
this._attachMediaQueriesListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
@@ -114,6 +171,7 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
|||||||
"section-visibility-changed",
|
"section-visibility-changed",
|
||||||
this._sectionVisibilityChanged
|
this._sectionVisibilityChanged
|
||||||
);
|
);
|
||||||
|
this._detachMediaQueriesListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
willUpdate(changedProperties: PropertyValues<typeof this>): void {
|
willUpdate(changedProperties: PropertyValues<typeof this>): void {
|
||||||
@@ -130,7 +188,9 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
|||||||
this._sectionColumnCount + (this.lovelace?.editMode ? 1 : 0);
|
this._sectionColumnCount + (this.lovelace?.editMode ? 1 : 0);
|
||||||
const editMode = this.lovelace.editMode;
|
const editMode = this.lovelace.editMode;
|
||||||
|
|
||||||
const maxColumnCount = this._columnsController.value ?? 1;
|
const maxColumnCount = this._config?.experimental_breakpoints
|
||||||
|
? this._breakpointsColumns
|
||||||
|
: this._sizeColumns;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<hui-view-badges
|
<hui-view-badges
|
||||||
@@ -321,9 +381,9 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
|||||||
:host {
|
:host {
|
||||||
--row-height: var(--ha-view-sections-row-height, 56px);
|
--row-height: var(--ha-view-sections-row-height, 56px);
|
||||||
--row-gap: var(--ha-view-sections-row-gap, 8px);
|
--row-gap: var(--ha-view-sections-row-gap, 8px);
|
||||||
--column-gap: var(--ha-view-sections-column-gap, 32px);
|
--column-gap: var(--ha-view-sections-column-gap, 24px);
|
||||||
--column-max-width: var(--ha-view-sections-column-max-width, 500px);
|
|
||||||
--column-min-width: var(--ha-view-sections-column-min-width, 320px);
|
--column-min-width: var(--ha-view-sections-column-min-width, 320px);
|
||||||
|
--column-max-width: var(--ha-view-sections-column-max-width, 500px);
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user