create before and after buttons

This commit is contained in:
Niels Lyngsø
2024-05-22 15:38:49 +02:00
parent 13d438c0d3
commit f95ae32958
4 changed files with 112 additions and 18 deletions

View File

@@ -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<UmbBlockGridLayoutModel> = { 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<any> | Map<PropertyKey, unknown>): 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`<umb-block-grid-block-inline
.contentUdi=${this.contentUdi}
@@ -171,8 +238,13 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper
#renderBlock() {
return this.contentUdi
? html`
${this._createPath
? html`<uui-button-inline-create href=${this._createPath}></uui-button-inline-create>`
${this._createBeforePath && this._showInlineCreateBefore
? html`<uui-button-inline-create
href=${this._createBeforePath}
label=${this.localize.term('blockEditor_addBlock')}
style=${this._inlineCreateAboveWidth
? `width: ${this._inlineCreateAboveWidth}`
: ''}></uui-button-inline-create>`
: nothing}
<div class="umb-block-grid__block" part="umb-block-grid__block">
<umb-extension-slot
@@ -204,6 +276,12 @@ export class UmbBlockGridEntryElement extends UmbLitElement implements UmbProper
</umb-block-scale-handler>`
: nothing}
</div>
${this._createAfterPath && this._showInlineCreateAfter
? html`<uui-button-inline-create
vertical
label=${this.localize.term('blockEditor_addBlock')}
href=${this._createAfterPath}></uui-button-inline-create>`
: 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;

View File

@@ -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:

View File

@@ -176,6 +176,7 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
(x) => x.contentUdi,
(layoutEntry, index) =>
html`<uui-button-inline-create
label=${this._createButtonLabel}
href=${this._catalogueRouteBuilder?.({ view: 'create', index: index }) ?? ''}></uui-button-inline-create>
<umb-block-list-entry .contentUdi=${layoutEntry.contentUdi} .layout=${layoutEntry}>
</umb-block-list-entry> `,

View File

@@ -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(