Merge pull request #1180 from umbraco/feature/block-type-create-labels
Feature/block type create labels
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user