Merge pull request #1180 from umbraco/feature/block-type-create-labels

Feature/block type create labels
This commit is contained in:
Niels Lyngsø
2024-02-06 09:31:10 +01:00
committed by GitHub
4 changed files with 185 additions and 110 deletions

View File

@@ -1,108 +1,154 @@
import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property';
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import { html, customElement, property, state, css } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import type { UmbRoute, UmbRouterSlotChangeEvent, UmbRouterSlotInitEvent } from '@umbraco-cms/backoffice/router';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import {
UMB_BLOCK_CATALOGUE_MODAL,
type UmbBlockLayoutBaseModel,
type UmbBlockTypeBaseModel,
type UmbBlockTypeGroup,
} from '@umbraco-cms/backoffice/block';
import { type UmbModalRouteBuilder, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
import type { NumberRangeValueType } from '@umbraco-cms/backoffice/models';
import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property';
/**
* @element umb-property-editor-ui-block-grid
*/
@customElement('umb-property-editor-ui-block-grid')
export class UmbPropertyEditorUIBlockGridElement extends UmbLitElement implements UmbPropertyEditorUiElement {
#catalogueModal: UmbModalRouteRegistrationController<typeof UMB_BLOCK_CATALOGUE_MODAL.DATA, undefined>;
@property()
value = '';
@state()
private _limitMin?: number;
@state()
private _limitMax?: number;
@state()
private _blocks?: Array<UmbBlockTypeBaseModel>;
@state()
private _blockGroups?: Array<UmbBlockTypeGroup>;
@state()
private _layouts: Array<UmbBlockLayoutBaseModel> = [];
@state()
private _catalogueRouteBuilder?: UmbModalRouteBuilder;
@state()
private _directRoute?: string;
@state()
private _createButtonLabel = this.localize.term('blockEditor_addBlock');
@property({ attribute: false })
public config?: UmbPropertyEditorConfigCollection;
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
if (!config) return;
@state()
private _routes: UmbRoute[] = [];
const validationLimit = config.getValueByAlias<NumberRangeValueType>('validationLimit');
@state()
private _routerPath: string | undefined;
this._limitMin = validationLimit?.min;
this._limitMax = validationLimit?.max;
@state()
private _activePath: string | undefined;
this._blocks = config.getValueByAlias<Array<UmbBlockTypeBaseModel>>('blocks') ?? [];
this._blockGroups = config.getValueByAlias<Array<UmbBlockTypeGroup>>('blockGroups') ?? [];
@state()
private _variantId?: UmbVariantId;
const customCreateButtonLabel = config.getValueByAlias<string>('createLabel');
if (customCreateButtonLabel) {
this._createButtonLabel = customCreateButtonLabel;
} else if (this._blocks.length === 1) {
this._createButtonLabel = this.localize.term('blockEditor_addThis', [this._blocks[0].label]);
}
//const useInlineEditingAsDefault = config.getValueByAlias<boolean>('useInlineEditingAsDefault');
//this.#context.setInlineEditingMode(useInlineEditingAsDefault);
//config.useSingleBlockMode
//config.useLiveEditing
//config.useInlineEditingAsDefault
this.style.maxWidth = config.getValueByAlias<string>('maxPropertyWidth') ?? '';
//this.#context.setEditorConfiguration(config);
}
constructor() {
super();
this.consumeContext(UMB_PROPERTY_CONTEXT, (context) => {
this.observe(context?.variantId, (propertyVariantId) => {
this._variantId = propertyVariantId;
this.setupRoutes();
});
this.consumeContext(UMB_PROPERTY_CONTEXT, (propertyContext) => {
this.observe(
propertyContext?.alias,
(alias) => {
this.#catalogueModal.setUniquePathValue('propertyAlias', alias);
},
'observePropertyAlias',
);
});
}
setupRoutes() {
this._routes = [];
if (this._variantId !== undefined) {
this._routes = [
{
path: 'modal-1',
component: () => {
return import('./property-editor-ui-block-grid-inner-test.element.js');
this.#catalogueModal = new UmbModalRouteRegistrationController(this, UMB_BLOCK_CATALOGUE_MODAL)
.addUniquePaths(['propertyAlias'])
.addAdditionalPath(':view/:index')
.onSetup((routingInfo) => {
const index = routingInfo.index ? parseInt(routingInfo.index) : -1;
return {
data: {
blocks: this._blocks ?? [],
blockGroups: this._blockGroups ?? [],
openClipboard: routingInfo.view === 'clipboard',
blockOriginData: { index: index },
},
setup: (component) => {
if (component instanceof HTMLElement) {
(component as any).name = 'block-grid-1';
}
},
},
{
path: 'modal-2',
component: () => {
return import('./property-editor-ui-block-grid-inner-test.element.js');
},
setup: (component) => {
if (component instanceof HTMLElement) {
(component as any).name = 'block-grid-2';
}
},
},
];
}
};
})
.observeRouteBuilder((routeBuilder) => {
this._catalogueRouteBuilder = routeBuilder;
});
}
render() {
return this._variantId
? html`<div>
umb-property-editor-ui-block-grid, inner routing test:
<uui-tab-group slot="navigation">
<uui-tab
label="TAB 1"
href="${this._routerPath + '/'}modal-1"
.active=${this._routerPath + '/' + 'modal-1' === this._activePath}></uui-tab>
<uui-tab
label="TAB 2"
href="${this._routerPath + '/'}modal-2"
.active=${this._routerPath + '/' + 'modal-2' === this._activePath}></uui-tab>
</uui-tab-group>
<umb-variant-router-slot
.variantId=${[this._variantId]}
id="router-slot"
.routes="${this._routes}"
@init=${(event: UmbRouterSlotInitEvent) => {
this._routerPath = event.target.absoluteRouterPath;
}}
@change=${(event: UmbRouterSlotChangeEvent) => {
this._activePath = event.target.localActiveViewPath;
}}>
</umb-variant-router-slot>
</div>`
: 'loading...';
if (this._blocks?.length === 1) {
const elementKey = this._blocks[0].contentElementTypeKey;
this._directRoute =
this._catalogueRouteBuilder?.({ view: 'create', index: -1 }) + 'modal/umb-modal-workspace/create/' + elementKey;
}
return html`<uui-button-group>
<uui-button
id="add-button"
look="placeholder"
label=${this._createButtonLabel}
href=${this._directRoute ?? this._catalogueRouteBuilder?.({ view: 'create', index: -1 }) ?? ''}></uui-button>
<uui-button
label=${this.localize.term('content_createFromClipboard')}
look="placeholder"
href=${this._catalogueRouteBuilder?.({ view: 'clipboard', index: -1 }) ?? ''}>
<uui-icon name="icon-paste-in"></uui-icon>
</uui-button>
</uui-button-group>`;
}
static styles = [UmbTextStyles];
static styles = [
UmbTextStyles,
css`
:host {
display: grid;
gap: 1px;
}
> div {
display: flex;
flex-direction: column;
align-items: stretch;
}
uui-button-group {
padding-top: 1px;
display: grid;
grid-template-columns: 1fr auto;
}
`,
];
}
export default UmbPropertyEditorUIBlockGridElement;

View File

@@ -15,6 +15,7 @@ import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/mod
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import type { UmbSorterConfig } from '@umbraco-cms/backoffice/sorter';
import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property';
export interface UmbBlockListLayoutModel extends UmbBlockLayoutBaseModel {}
@@ -45,6 +46,8 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
},
});
#catalogueModal: UmbModalRouteRegistrationController<typeof UMB_BLOCK_CATALOGUE_MODAL.DATA, undefined>;
private _value: UmbBlockListValueModel = {
layout: {},
contentData: [],
@@ -67,9 +70,13 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
this.#context.setSettings(buildUpValue.settingsData);
}
@state()
private _createButtonLabel = this.localize.term('content_createEmpty');
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
if (!config) return;
const validationLimit = config.getValueByAlias<NumberRangeValueType>('validationLimit');
this._limitMin = validationLimit?.min;
@@ -78,6 +85,13 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
const blocks = config.getValueByAlias<Array<UmbBlockTypeBaseModel>>('blocks') ?? [];
this.#context.setBlockTypes(blocks);
const customCreateButtonLabel = config.getValueByAlias<string>('createLabel');
if (customCreateButtonLabel) {
this._createButtonLabel = customCreateButtonLabel;
} else if (blocks.length === 1) {
this._createButtonLabel = `${this.localize.term('general_add')} ${blocks[0].label}`;
}
const useInlineEditingAsDefault = config.getValueByAlias<boolean>('useInlineEditingAsDefault');
this.#context.setInlineEditingMode(useInlineEditingAsDefault);
//config.useSingleBlockMode
@@ -97,16 +111,29 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
private _blocks?: Array<UmbBlockTypeBaseModel>;
@state()
_layouts: Array<UmbBlockLayoutBaseModel> = [];
private _layouts: Array<UmbBlockLayoutBaseModel> = [];
@state()
_catalogueRouteBuilder?: UmbModalRouteBuilder;
private _catalogueRouteBuilder?: UmbModalRouteBuilder;
@state()
private _directRoute?: string;
#context = new UmbBlockListManagerContext(this);
constructor() {
super();
this.consumeContext(UMB_PROPERTY_CONTEXT, (propertyContext) => {
this.observe(
propertyContext?.alias,
(alias) => {
this.#catalogueModal.setUniquePathValue('propertyAlias', alias);
},
'observePropertyAlias',
);
});
// TODO: Prevent initial notification from these observes:
this.observe(this.#context.layouts, (layouts) => {
this._value = { ...this._value, layout: { [UMB_BLOCK_LIST_PROPERTY_EDITOR_ALIAS]: layouts } };
@@ -133,7 +160,8 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
this._blocks = blockTypes;
});
new UmbModalRouteRegistrationController(this, UMB_BLOCK_CATALOGUE_MODAL)
this.#catalogueModal = new UmbModalRouteRegistrationController(this, UMB_BLOCK_CATALOGUE_MODAL)
.addUniquePaths(['propertyAlias'])
.addAdditionalPath(':view/:index')
.onSetup((routingInfo) => {
const index = routingInfo.index ? parseInt(routingInfo.index) : -1;
@@ -151,6 +179,11 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
}
render() {
if (this._blocks?.length === 1) {
const elementKey = this._blocks[0].contentElementTypeKey;
this._directRoute =
this._catalogueRouteBuilder?.({ view: 'create', index: -1 }) + 'modal/umb-modal-workspace/create/' + elementKey;
}
return html` ${repeat(
this._layouts,
(x) => x.contentUdi,
@@ -164,10 +197,8 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
<uui-button
id="add-button"
look="placeholder"
label=${this.localize.term('content_createEmpty')}
href=${this._catalogueRouteBuilder?.({ view: 'create', index: -1 }) ?? ''}>
${this.localize.term('content_createEmpty')}
</uui-button>
label=${this._createButtonLabel}
href=${this._directRoute ?? this._catalogueRouteBuilder?.({ view: 'create', index: -1 }) ?? ''}></uui-button>
<uui-button
label=${this.localize.term('content_createFromClipboard')}
look="placeholder"

View File

@@ -2,10 +2,10 @@ import { UMB_BLOCK_WORKSPACE_MODAL } from '../../workspace/index.js';
import type {
UmbBlockCatalogueModalData,
UmbBlockCatalogueModalValue,
UmbBlockTypeGroup,
UmbBlockTypeWithGroupKey,
} from '@umbraco-cms/backoffice/block';
import { css, html, customElement, state, repeat, ifDefined, nothing } from '@umbraco-cms/backoffice/external/lit';
import { groupBy } from '@umbraco-cms/backoffice/external/lodash';
import {
UMB_MODAL_CONTEXT,
UmbModalBaseElement,
@@ -18,10 +18,7 @@ export class UmbBlockCatalogueModalElement extends UmbModalBaseElement<
UmbBlockCatalogueModalValue
> {
@state()
private _blocks: Array<UmbBlockTypeWithGroupKey> = [];
@state()
private _blockGroups: Array<{ key: string; name: string }> = [];
private _groupedBlocks: Array<{ name?: string; blocks: Array<UmbBlockTypeWithGroupKey> }> = [];
@state()
_openClipboard?: boolean;
@@ -55,16 +52,18 @@ export class UmbBlockCatalogueModalElement extends UmbModalBaseElement<
if (!this.data) return;
this._openClipboard = this.data.openClipboard ?? false;
this._blocks = this.data.blocks ?? [];
this._blockGroups = this.data.blockGroups ?? [];
}
/*
#onClickBlock(contentElementTypeKey: string) {
this.modalContext?.updateValue({ key: contentElementTypeKey });
this.modalContext?.submit();
const blocks: Array<UmbBlockTypeWithGroupKey> = this.data.blocks ?? [];
const blockGroups: Array<UmbBlockTypeGroup> = this.data.blockGroups ?? [];
const noGroupBlocks = blocks.filter((block) => !blockGroups.find((group) => group.key === block.groupKey));
const grouped = blockGroups.map((group) => ({
name: group.name ?? '',
blocks: blocks.filter((block) => block.groupKey === group.key),
}));
this._groupedBlocks = [{ blocks: noGroupBlocks }, ...grouped];
}
*/
render() {
return html`
@@ -87,17 +86,10 @@ export class UmbBlockCatalogueModalElement extends UmbModalBaseElement<
}
#renderCreateEmpty() {
const blockArrays = groupBy(this._blocks, 'groupKey');
const mappedGroupsAndBlocks = Object.entries(blockArrays).map(([key, value]) => {
const group = this._blockGroups.find((group) => group.key === key);
return { name: group?.name, blocks: value };
});
return html`
${mappedGroupsAndBlocks.map(
${this._groupedBlocks.map(
(group) => html`
${group.name ? html`<h2>${group.name}</h2>` : nothing}
${group.name ? html`<h4>${group.name}</h4>` : nothing}
<div class="blockGroup">
${repeat(
group.blocks,
@@ -121,12 +113,18 @@ export class UmbBlockCatalogueModalElement extends UmbModalBaseElement<
#renderViews() {
return html`
<uui-tab-group slot="navigation">
<uui-tab label="Create Empty" ?active=${!this._openClipboard} @click=${() => (this._openClipboard = false)}>
Create Empty
<uui-tab
label=${this.localize.term('blockEditor_tabCreateEmpty')}
?active=${!this._openClipboard}
@click=${() => (this._openClipboard = false)}>
<umb-localize key=${this.localize.term('blockEditor_tabCreateEmpty')}>Create Empty</umb-localize>
<uui-icon slot="icon" name="icon-add"></uui-icon>
</uui-tab>
<uui-tab label="Clipboard" ?active=${this._openClipboard} @click=${() => (this._openClipboard = true)}>
Clipboard
<uui-tab
label=${this.localize.term('blockEditor_tabClipboard')}
?active=${this._openClipboard}
@click=${() => (this._openClipboard = true)}>
<umb-localize key=${this.localize.term('blockEditor_tabClipboard')}>Clipboard</umb-localize>
<uui-icon slot="icon" name="icon-paste-in"></uui-icon>
</uui-tab>
</uui-tab-group>

View File

@@ -1,9 +1,9 @@
import type { UmbBlockTypeBaseModel, UmbBlockWorkspaceData } from '@umbraco-cms/backoffice/block';
import type { UmbBlockTypeBaseModel, UmbBlockTypeGroup, UmbBlockWorkspaceData } from '@umbraco-cms/backoffice/block';
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export interface UmbBlockCatalogueModalData {
blocks: Array<UmbBlockTypeBaseModel>;
blockGroups?: Array<{ name: string; key: string }>;
blockGroups?: Array<UmbBlockTypeGroup>;
openClipboard?: boolean;
blockOriginData: UmbBlockWorkspaceData['originData'];
}