diff --git a/src/panels/config/automation/ha-automation-editor.ts b/src/panels/config/automation/ha-automation-editor.ts
index ebd10a0cd4..a5b93a7d67 100644
--- a/src/panels/config/automation/ha-automation-editor.ts
+++ b/src/panels/config/automation/ha-automation-editor.ts
@@ -1154,6 +1154,12 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
return [
haStyle,
css`
+ :host {
+ --ha-automation-editor-max-width: var(
+ --ha-automation-editor-width,
+ 1540px
+ );
+ }
ha-fade-in {
display: flex;
justify-content: center;
@@ -1175,7 +1181,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
}
manual-automation-editor {
- max-width: 1540px;
+ max-width: var(--ha-automation-editor-max-width);
padding: 0 12px;
}
diff --git a/src/panels/config/automation/ha-automation-sidebar.ts b/src/panels/config/automation/ha-automation-sidebar.ts
index 4a51370660..bdb4e1ed50 100644
--- a/src/panels/config/automation/ha-automation-sidebar.ts
+++ b/src/panels/config/automation/ha-automation-sidebar.ts
@@ -1,5 +1,7 @@
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
+import { fireEvent } from "../../../common/dom/fire_event";
+import { computeRTL } from "../../../common/util/compute_rtl";
import "../../../components/ha-resizable-bottom-sheet";
import type { HaResizableBottomSheet } from "../../../components/ha-resizable-bottom-sheet";
import {
@@ -37,9 +39,18 @@ export default class HaAutomationSidebar extends LitElement {
@state() private _yamlMode = false;
+ @state() private _resizing = false;
+
@query("ha-resizable-bottom-sheet")
private _bottomSheetElement?: HaResizableBottomSheet;
+ private _resizeStartX = 0;
+
+ disconnectedCallback() {
+ super.disconnectedCallback();
+ this._unregisterResizeHandlers();
+ }
+
private _renderContent() {
// get config type
const type = this._getType();
@@ -154,7 +165,16 @@ export default class HaAutomationSidebar extends LitElement {
`;
}
- return this._renderContent();
+ return html`
+
+ ${this._resizing ? html`
` : nothing}
+
+ ${this._renderContent()}
+ `;
}
private _getType() {
@@ -207,6 +227,67 @@ export default class HaAutomationSidebar extends LitElement {
(this.config as ActionSidebarConfig)?.toggleYamlMode();
};
+ private _handleMouseDown = (ev: MouseEvent | TouchEvent) => {
+ // Prevent the browser from interpreting this as a scroll/PTR gesture.
+ ev.preventDefault();
+ this._startResizing(
+ (ev as TouchEvent).touches?.length
+ ? (ev as TouchEvent).touches[0].clientX
+ : (ev as MouseEvent).clientX
+ );
+ };
+
+ private _startResizing(clientX: number) {
+ // register event listeners for drag handling
+ document.addEventListener("mousemove", this._handleMouseMove);
+ document.addEventListener("mouseup", this._endResizing);
+ document.addEventListener("touchmove", this._handleMouseMove, {
+ passive: false,
+ });
+ document.addEventListener("touchend", this._endResizing);
+ document.addEventListener("touchcancel", this._endResizing);
+
+ this._resizing = true;
+ this._resizeStartX = clientX;
+ }
+
+ private _handleMouseMove = (ev: MouseEvent | TouchEvent) => {
+ this._updateSize(
+ (ev as TouchEvent).touches?.length
+ ? (ev as TouchEvent).touches[0].clientX
+ : (ev as MouseEvent).clientX
+ );
+ };
+
+ private _updateSize(clientX: number) {
+ let delta = this._resizeStartX - clientX;
+
+ if (computeRTL(this.hass)) {
+ delta = -delta;
+ }
+
+ requestAnimationFrame(() => {
+ fireEvent(this, "sidebar-resized", {
+ deltaInPx: delta,
+ });
+ });
+ }
+
+ private _endResizing = () => {
+ this._unregisterResizeHandlers();
+ this._resizing = false;
+ document.body.style.removeProperty("cursor");
+ fireEvent(this, "sidebar-resizing-stopped");
+ };
+
+ private _unregisterResizeHandlers() {
+ document.removeEventListener("mousemove", this._handleMouseMove);
+ document.removeEventListener("mouseup", this._endResizing);
+ document.removeEventListener("touchmove", this._handleMouseMove);
+ document.removeEventListener("touchend", this._endResizing);
+ document.removeEventListener("touchcancel", this._endResizing);
+ }
+
static styles = css`
:host {
z-index: 6;
@@ -231,6 +312,28 @@ export default class HaAutomationSidebar extends LitElement {
max-height: 100%;
}
}
+
+ .handle {
+ position: absolute;
+ margin-inline-start: -11px;
+ height: calc(100% - (2 * var(--ha-card-border-radius)));
+ width: 24px;
+ z-index: 7;
+ cursor: ew-resize;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: var(--ha-card-border-radius) 0;
+ }
+ .handle.resizing {
+ cursor: grabbing;
+ }
+ .handle .indicator {
+ background-color: var(--primary-color);
+ height: 100%;
+ width: 4px;
+ border-radius: var(--ha-border-radius-pill);
+ }
`;
}
@@ -244,5 +347,9 @@ declare global {
"yaml-changed": {
value: unknown;
};
+ "sidebar-resized": {
+ deltaInPx: number;
+ };
+ "sidebar-resizing-stopped": undefined;
}
}
diff --git a/src/panels/config/automation/manual-automation-editor.ts b/src/panels/config/automation/manual-automation-editor.ts
index 55b9a52cbf..724675da61 100644
--- a/src/panels/config/automation/manual-automation-editor.ts
+++ b/src/panels/config/automation/manual-automation-editor.ts
@@ -22,6 +22,7 @@ import {
union,
} from "superstruct";
import { ensureArray } from "../../../common/array/ensure-array";
+import { storage } from "../../../common/decorators/storage";
import { canOverrideAlphanumericInput } from "../../../common/dom/can-override-input";
import { fireEvent } from "../../../common/dom/fire_event";
import { constructUrlCurrentPath } from "../../../common/url/construct-url";
@@ -77,6 +78,8 @@ const automationConfigStruct = union([
assign(baseConfigStruct, object({ actions: array(any()) })),
]);
+export const SIDEBAR_DEFAULT_WIDTH = 500;
+
@customElement("manual-automation-editor")
export class HaManualAutomationEditor extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -101,6 +104,13 @@ export class HaManualAutomationEditor extends LitElement {
@state() private _sidebarKey?: string;
+ @storage({
+ key: "automation-sidebar-width",
+ state: false,
+ subscribe: false,
+ })
+ private _sidebarWidthPx = SIDEBAR_DEFAULT_WIDTH;
+
@query("ha-automation-sidebar") private _sidebarElement?: HaAutomationSidebar;
@queryAll("ha-automation-action, ha-automation-condition")
@@ -110,6 +120,8 @@ export class HaManualAutomationEditor extends LitElement {
private _previousConfig?: ManualAutomationConfig;
+ private _prevSidebarWidthPx?: number;
+
public connectedCallback() {
super.connectedCallback();
window.addEventListener("paste", this._handlePaste);
@@ -303,9 +315,11 @@ export class HaManualAutomationEditor extends LitElement {
.hass=${this.hass}
.narrow=${this.narrow}
.config=${this._sidebarConfig}
- @value-changed=${this._sidebarConfigChanged}
.disabled=${this.disabled}
.sidebarKey=${this._sidebarKey}
+ @value-changed=${this._sidebarConfigChanged}
+ @sidebar-resized=${this._resizeSidebar}
+ @sidebar-resizing-stopped=${this._stopResizeSidebar}
>
@@ -314,6 +328,12 @@ export class HaManualAutomationEditor extends LitElement {
protected firstUpdated(changedProps: PropertyValues): void {
super.firstUpdated(changedProps);
+
+ this.style.setProperty(
+ "--sidebar-dynamic-width",
+ `${this._sidebarWidthPx}px`
+ );
+
const expanded = extractSearchParam("expanded");
if (expanded === "1") {
this._clearParam("expanded");
@@ -642,6 +662,31 @@ export class HaManualAutomationEditor extends LitElement {
}
}
+ private _resizeSidebar(ev) {
+ ev.stopPropagation();
+ const delta = ev.detail.deltaInPx as number;
+
+ // set initial resize width to add / reduce delta from it
+ if (!this._prevSidebarWidthPx) {
+ this._prevSidebarWidthPx =
+ this._sidebarElement?.clientWidth || SIDEBAR_DEFAULT_WIDTH;
+ }
+
+ const widthPx = delta + this._prevSidebarWidthPx;
+
+ this._sidebarWidthPx = widthPx;
+
+ this.style.setProperty(
+ "--sidebar-dynamic-width",
+ `${this._sidebarWidthPx}px`
+ );
+ }
+
+ private _stopResizeSidebar(ev) {
+ ev.stopPropagation();
+ this._prevSidebarWidthPx = undefined;
+ }
+
static get styles(): CSSResultGroup {
return [
saveFabStyles,
diff --git a/src/panels/config/automation/styles.ts b/src/panels/config/automation/styles.ts
index b27050de79..56623282e4 100644
--- a/src/panels/config/automation/styles.ts
+++ b/src/panels/config/automation/styles.ts
@@ -1,5 +1,8 @@
import { css } from "lit";
+export const SIDEBAR_MIN_WIDTH = 375;
+export const CONTENT_MIN_WIDTH = 350;
+
export const rowStyles = css`
ha-icon-button {
--mdc-theme-text-primary-on-background: var(--primary-text-color);
@@ -109,7 +112,12 @@ export const manualEditorStyles = css`
}
.has-sidebar {
- --sidebar-width: min(35vw, 500px);
+ --sidebar-width: min(
+ max(var(--sidebar-dynamic-width), ${SIDEBAR_MIN_WIDTH}px),
+ 100vw - ${CONTENT_MIN_WIDTH}px - var(--mdc-drawer-width, 0px),
+ var(--ha-automation-editor-max-width) -
+ ${CONTENT_MIN_WIDTH}px - var(--mdc-drawer-width, 0px)
+ );
--sidebar-gap: 16px;
}
diff --git a/src/panels/config/script/ha-script-editor.ts b/src/panels/config/script/ha-script-editor.ts
index dda79b8e59..a742ff1afc 100644
--- a/src/panels/config/script/ha-script-editor.ts
+++ b/src/panels/config/script/ha-script-editor.ts
@@ -1062,6 +1062,12 @@ export class HaScriptEditor extends SubscribeMixin(
return [
haStyle,
css`
+ :host {
+ --ha-automation-editor-max-width: var(
+ --ha-automation-editor-width,
+ 1540px
+ );
+ }
.yaml-mode {
height: 100%;
display: flex;
@@ -1114,7 +1120,7 @@ export class HaScriptEditor extends SubscribeMixin(
}
manual-script-editor {
- max-width: 1540px;
+ max-width: var(--ha-automation-editor-max-width);
padding: 0 12px;
}
diff --git a/src/panels/config/script/manual-script-editor.ts b/src/panels/config/script/manual-script-editor.ts
index a6c805816e..086e48fd79 100644
--- a/src/panels/config/script/manual-script-editor.ts
+++ b/src/panels/config/script/manual-script-editor.ts
@@ -21,6 +21,7 @@ import {
string,
} from "superstruct";
import { ensureArray } from "../../../common/array/ensure-array";
+import { storage } from "../../../common/decorators/storage";
import { canOverrideAlphanumericInput } from "../../../common/dom/can-override-input";
import { fireEvent } from "../../../common/dom/fire_event";
import { constructUrlCurrentPath } from "../../../common/url/construct-url";
@@ -47,6 +48,7 @@ import "../automation/action/ha-automation-action";
import type HaAutomationAction from "../automation/action/ha-automation-action";
import "../automation/ha-automation-sidebar";
import type HaAutomationSidebar from "../automation/ha-automation-sidebar";
+import { SIDEBAR_DEFAULT_WIDTH } from "../automation/manual-automation-editor";
import { showPasteReplaceDialog } from "../automation/paste-replace-dialog/show-dialog-paste-replace";
import { manualEditorStyles, saveFabStyles } from "../automation/styles";
import "./ha-script-fields";
@@ -84,6 +86,13 @@ export class HaManualScriptEditor extends LitElement {
@state() private _sidebarKey?: string;
+ @storage({
+ key: "automation-sidebar-width",
+ state: false,
+ subscribe: false,
+ })
+ private _sidebarWidthPx = SIDEBAR_DEFAULT_WIDTH;
+
@query("ha-script-fields")
private _scriptFields?: HaScriptFields;
@@ -98,6 +107,8 @@ export class HaManualScriptEditor extends LitElement {
private _openFields = false;
+ private _prevSidebarWidthPx?: number;
+
public addFields() {
this._openFields = true;
fireEvent(this, "value-changed", {
@@ -252,8 +263,10 @@ export class HaManualScriptEditor extends LitElement {
.isWide=${this.isWide}
.hass=${this.hass}
.config=${this._sidebarConfig}
- @value-changed=${this._sidebarConfigChanged}
.disabled=${this.disabled}
+ @value-changed=${this._sidebarConfigChanged}
+ @sidebar-resized=${this._resizeSidebar}
+ @sidebar-resizing-stopped=${this._stopResizeSidebar}
>
@@ -262,6 +275,12 @@ export class HaManualScriptEditor extends LitElement {
protected firstUpdated(changedProps: PropertyValues): void {
super.firstUpdated(changedProps);
+
+ this.style.setProperty(
+ "--sidebar-dynamic-width",
+ `${this._sidebarWidthPx}px`
+ );
+
const expanded = extractSearchParam("expanded");
if (expanded === "1") {
this._clearParam("expanded");
@@ -557,6 +576,31 @@ export class HaManualScriptEditor extends LitElement {
}
}
+ private _resizeSidebar(ev) {
+ ev.stopPropagation();
+ const delta = ev.detail.deltaInPx as number;
+
+ // set initial resize width to add / reduce delta from it
+ if (!this._prevSidebarWidthPx) {
+ this._prevSidebarWidthPx =
+ this._sidebarElement?.clientWidth || SIDEBAR_DEFAULT_WIDTH;
+ }
+
+ const widthPx = delta + this._prevSidebarWidthPx;
+
+ this._sidebarWidthPx = widthPx;
+
+ this.style.setProperty(
+ "--sidebar-dynamic-width",
+ `${this._sidebarWidthPx}px`
+ );
+ }
+
+ private _stopResizeSidebar(ev) {
+ ev.stopPropagation();
+ this._prevSidebarWidthPx = undefined;
+ }
+
static get styles(): CSSResultGroup {
return [
saveFabStyles,