From f95ae32958834e0040230c09f8a324304df4bc78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 22 May 2024 15:38:49 +0200 Subject: [PATCH] create before and after buttons --- .../block-grid-entry.element.ts | 105 ++++++++++++++++-- .../block-grid-scale-manager.controller.ts | 6 +- .../property-editor-ui-block-list.element.ts | 1 + .../block/context/block-entry.context.ts | 18 +-- 4 files changed, 112 insertions(+), 18 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-entry/block-grid-entry.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-entry/block-grid-entry.element.ts index c1b6eeb54c..eaf3493964 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-entry/block-grid-entry.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/components/block-grid-entry/block-grid-entry.element.ts @@ -1,6 +1,14 @@ import { UmbBlockGridEntryContext } from '../../context/block-grid-entry.context.js'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import { html, css, customElement, property, state, nothing } from '@umbraco-cms/backoffice/external/lit'; +import { + html, + css, + customElement, + property, + state, + nothing, + type PropertyValueMap, +} from '@umbraco-cms/backoffice/external/lit'; import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry'; import type { UmbBlockViewPropsType } from '@umbraco-cms/backoffice/block'; import type { UmbBlockGridLayoutModel } from '@umbraco-cms/backoffice/block-grid'; @@ -37,6 +45,7 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper // #context = new UmbBlockGridEntryContext(this); + #renderTimeout: number | undefined; @state() _columnSpan?: number; @@ -51,7 +60,9 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper // If _createPath is undefined, its because no blocks are allowed to be created here[NL] @state() - _createPath?: string; + _createBeforePath?: string; + @state() + _createAfterPath?: string; @state() _label = ''; @@ -68,6 +79,13 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper @state() _canScale?: boolean; + @state() + _showInlineCreateBefore?: boolean; + @state() + _showInlineCreateAfter?: boolean; + @state() + _inlineCreateAboveWidth?: string; + // TODO: use this type on the Element Interface for the Manifest. @state() _blockViewProps: UmbBlockViewPropsType = { contentUdi: undefined!, urls: {} }; // Set to undefined cause it will be set before we render. @@ -110,10 +128,15 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper }); // Paths: - this.observe(this.#context.createPath, (createPath) => { - const oldValue = this._createPath; - this._createPath = createPath; - this.requestUpdate('_createPath', oldValue); + this.observe(this.#context.createBeforePath, (createPath) => { + //const oldValue = this._createBeforePath; + this._createBeforePath = createPath; + //this.requestUpdate('_createPath', oldValue); + }); + this.observe(this.#context.createAfterPath, (createPath) => { + //const oldValue = this._createAfterPath; + this._createAfterPath = createPath; + //this.requestUpdate('_createPath', oldValue); }); this.observe(this.#context.workspaceEditContentPath, (path) => { this._workspaceEditContentPath = path; @@ -156,8 +179,52 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper this.setAttribute('data-content-element-type-alias', contentElementTypeAlias); } }); + + this.#callUpdateInlineCreateButtons(); } + protected updated(_changedProperties: PropertyValueMap | Map): void { + super.updated(_changedProperties); + if (_changedProperties.has('_blockViewProps') || _changedProperties.has('_columnSpan')) { + this.#callUpdateInlineCreateButtons(); + } + } + + #callUpdateInlineCreateButtons() { + clearTimeout(this.#renderTimeout); + this.#renderTimeout = setTimeout(this.#updateInlineCreateButtons, 100) as unknown as number; + } + + #updateInlineCreateButtons = () => { + // TODO: Could we optimize this, so it wont break?, cause currently we trust blindly that parentElement is '.umb-block-grid__layout-container' [NL] + const layoutContainer = this.parentElement; + if (!layoutContainer) return; + const layoutContainerRect = layoutContainer.getBoundingClientRect(); + + if (layoutContainerRect.width === 0) { + this._showInlineCreateBefore = false; + this._showInlineCreateAfter = false; + this._inlineCreateAboveWidth = undefined; + this.#renderTimeout = setTimeout(this.#updateInlineCreateButtons, 100) as unknown as number; + return; + } + + const layoutItemRect = this.getBoundingClientRect(); + if (layoutItemRect.right > layoutContainerRect.right - 5) { + this._showInlineCreateAfter = false; + } else { + this._showInlineCreateAfter = true; + } + + if (layoutItemRect.left > layoutContainerRect.left + 5) { + this._showInlineCreateBefore = false; + this._inlineCreateAboveWidth = undefined; + } else { + this._inlineCreateAboveWidth = getComputedStyle(layoutContainer).width; + this._showInlineCreateBefore = true; + } + }; + #renderInlineEditBlock() { return html`` + ${this._createBeforePath && this._showInlineCreateBefore + ? html`` : nothing}
` : nothing}
+ ${this._createAfterPath && this._showInlineCreateAfter + ? html`` + : nothing} ` : nothing; } @@ -223,6 +301,17 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper top: var(--uui-size-2); right: var(--uui-size-2); } + uui-button-inline-create { + top: 0px; + position: absolute; + + // Avoid showing inline-create in dragging-mode + --umb-block-grid__block--inline-create-button-display--condition: var(--umb-block-grid--dragging-mode) none; + display: var(--umb-block-grid__block--inline-create-button-display--condition); + } + uui-button-inline-create[vertical] { + right: calc(1px - (var(--umb-block-grid--column-gap, 0px) * 0.5)); + } :host([drag-placeholder]) { opacity: 0.2; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-scale-manager/block-grid-scale-manager.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-scale-manager/block-grid-scale-manager.controller.ts index 2fd4d9f9d7..6dc5a7ca07 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-scale-manager/block-grid-scale-manager.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/context/block-grid-scale-manager/block-grid-scale-manager.controller.ts @@ -128,11 +128,11 @@ export class UmbBlockGridScaleManager extends UmbControllerBase { let newColumnSpan = Math.max(blockEndCol - blockStartCol, 1); - const spanOptions = this._host.getRelevantColumnSpanOptions(); - if (!spanOptions) return; + const columnOptions = this._host.getRelevantColumnSpanOptions(); + if (!columnOptions) return; // Find nearest allowed Column: - const bestColumnSpanOption = closestColumnSpanOption(newColumnSpan, spanOptions, layoutColumns - blockStartCol); + const bestColumnSpanOption = closestColumnSpanOption(newColumnSpan, columnOptions, layoutColumns - blockStartCol); newColumnSpan = bestColumnSpanOption ?? layoutColumns; // Find allowed row spans: diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts index abf6497b5f..e9e8b905dd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts @@ -176,6 +176,7 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement (x) => x.contentUdi, (layoutEntry, index) => html` `, diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entry.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entry.context.ts index ad79fc4d13..c182b6e57b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entry.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entry.context.ts @@ -61,8 +61,10 @@ export abstract class UmbBlockEntryContext< this.#index.setValue(index); } - #createPath = new UmbStringState(undefined); - readonly createPath = this.#createPath.asObservable(); + #createBeforePath = new UmbStringState(undefined); + readonly createBeforePath = this.#createBeforePath.asObservable(); + #createAfterPath = new UmbStringState(undefined); + readonly createAfterPath = this.#createAfterPath.asObservable(); #contentElementTypeName = new UmbStringState(undefined); public readonly contentElementTypeName = this.#contentElementTypeName.asObservable(); @@ -173,7 +175,7 @@ export abstract class UmbBlockEntryContext< }); this.observe(this.index, () => { - this.#updateCreatePath(); + this.#updateCreatePaths(); }); } @@ -181,16 +183,18 @@ export abstract class UmbBlockEntryContext< return this._layout.value?.contentUdi; } - #updateCreatePath() { + #updateCreatePaths() { const index = this.#index.value; if (this._entries && index !== undefined) { this.observe( observeMultiple([this._entries.catalogueRouteBuilder, this._entries.canCreate]), ([catalogueRouteBuilder, canCreate]) => { if (catalogueRouteBuilder && canCreate) { - this.#createPath.setValue(this._entries!.getPathForCreateBlock(index)); + this.#createBeforePath.setValue(this._entries!.getPathForCreateBlock(index)); + this.#createAfterPath.setValue(this._entries!.getPathForCreateBlock(index + 1)); } else { - this.#createPath.setValue(undefined); + this.#createBeforePath.setValue(undefined); + this.#createAfterPath.setValue(undefined); } }, 'observeRouteBuilderCreate', @@ -227,7 +231,7 @@ export abstract class UmbBlockEntryContext< abstract _gotManager(): void; #gotEntries() { - this.#updateCreatePath(); + this.#updateCreatePaths(); this.#observeLayout(); if (this._entries) { this.observe(