Merge pull request #1104 from umbraco/feature/block-catalogue-modal
block catalogue modal
This commit is contained in:
@@ -1 +1 @@
|
||||
export { debounce, clamp, camelCase } from 'lodash-es';
|
||||
export { debounce, clamp, camelCase, groupBy } from 'lodash-es';
|
||||
|
||||
@@ -490,6 +490,41 @@ export const data: Array<DataTypeResponseModel | FolderTreeItemResponseModel> =
|
||||
{
|
||||
label: 'Mocked Block Type for Block List',
|
||||
contentElementTypeKey: '4f68ba66-6fb2-4778-83b8-6ab4ca3a7c5c',
|
||||
icon: 'icon-server-alt',
|
||||
},
|
||||
{
|
||||
label: 'Mocked Coffee Block',
|
||||
contentElementTypeKey: 'coffee-umbraco-demo-block-id',
|
||||
iconColor: '#FFFDD0',
|
||||
backgroundColor: '#633f32',
|
||||
editorSize: 'medium',
|
||||
icon: 'icon-coffee',
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Headline',
|
||||
contentElementTypeKey: 'headline-umbraco-demo-block-id',
|
||||
backgroundColor: 'gold',
|
||||
editorSize: 'medium',
|
||||
icon: 'icon-edit',
|
||||
},
|
||||
{
|
||||
label: 'Image',
|
||||
contentElementTypeKey: 'image-umbraco-demo-block-id',
|
||||
editorSize: 'medium',
|
||||
icon: 'icon-picture',
|
||||
},
|
||||
{
|
||||
label: 'Rich Text',
|
||||
contentElementTypeKey: 'rich-text-umbraco-demo-block-id',
|
||||
editorSize: 'medium',
|
||||
icon: 'icon-diploma',
|
||||
},
|
||||
{
|
||||
label: 'Two Column Layout',
|
||||
contentElementTypeKey: 'two-column-layout-umbraco-demo-block-id',
|
||||
editorSize: 'medium',
|
||||
icon: 'icon-book-alt',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -560,6 +595,10 @@ export const data: Array<DataTypeResponseModel | FolderTreeItemResponseModel> =
|
||||
editorAlias: 'Umbraco.BlockGrid',
|
||||
editorUiAlias: 'Umb.PropertyEditorUi.BlockGrid',
|
||||
values: [
|
||||
{
|
||||
alias: 'blockGroups',
|
||||
value: [{ key: 'demo-block-group-id', name: 'Demo Blocks' }],
|
||||
},
|
||||
{
|
||||
alias: 'blocks',
|
||||
value: [
|
||||
@@ -567,6 +606,45 @@ export const data: Array<DataTypeResponseModel | FolderTreeItemResponseModel> =
|
||||
label: 'Mocked Block Type for Block Grid',
|
||||
contentElementTypeKey: '4f68ba66-6fb2-4778-83b8-6ab4ca3a7c5c',
|
||||
},
|
||||
{
|
||||
label: 'Mocked Coffee Block',
|
||||
contentElementTypeKey: 'coffee-umbraco-demo-block-id',
|
||||
iconColor: '#FFFDD0',
|
||||
backgroundColor: '#633f32',
|
||||
editorSize: 'medium',
|
||||
icon: 'icon-coffee',
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Headline',
|
||||
contentElementTypeKey: 'headline-umbraco-demo-block-id',
|
||||
backgroundColor: 'gold',
|
||||
editorSize: 'medium',
|
||||
icon: 'icon-edit',
|
||||
groupKey: 'demo-block-group-id',
|
||||
},
|
||||
{
|
||||
label: 'Image',
|
||||
contentElementTypeKey: 'image-umbraco-demo-block-id',
|
||||
editorSize: 'medium',
|
||||
icon: 'icon-picture',
|
||||
|
||||
groupKey: 'demo-block-group-id',
|
||||
},
|
||||
{
|
||||
label: 'Rich Text',
|
||||
contentElementTypeKey: 'rich-text-umbraco-demo-block-id',
|
||||
editorSize: 'medium',
|
||||
icon: 'icon-diploma',
|
||||
groupKey: 'demo-block-group-id',
|
||||
},
|
||||
{
|
||||
label: 'Two Column Layout',
|
||||
contentElementTypeKey: 'two-column-layout-umbraco-demo-block-id',
|
||||
editorSize: 'medium',
|
||||
icon: 'icon-book-alt',
|
||||
groupKey: 'demo-block-group-id',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1198,4 +1198,302 @@ export const data: Array<UmbMockDocumentTypeModel> = [
|
||||
keepLatestVersionPerDayForDays: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'document-type',
|
||||
allowedTemplateIds: [],
|
||||
defaultTemplateId: null,
|
||||
id: 'folder-umbraco-demo-blocks-id',
|
||||
alias: 'folderUmbracoDemoBlocks',
|
||||
name: 'Umbraco Demo Blocks',
|
||||
description: null,
|
||||
icon: 'icon-folder',
|
||||
allowedAsRoot: true,
|
||||
variesByCulture: false,
|
||||
variesBySegment: false,
|
||||
isElement: false,
|
||||
hasChildren: true,
|
||||
isContainer: false,
|
||||
parentId: null,
|
||||
isFolder: true,
|
||||
allowedContentTypes: [],
|
||||
compositions: [],
|
||||
cleanup: {
|
||||
preventCleanup: false,
|
||||
keepAllVersionsNewerThanDays: null,
|
||||
keepLatestVersionPerDayForDays: null,
|
||||
},
|
||||
properties: [],
|
||||
containers: [],
|
||||
},
|
||||
{
|
||||
type: 'document-type',
|
||||
allowedTemplateIds: [],
|
||||
defaultTemplateId: null,
|
||||
id: 'coffee-umbraco-demo-block-id',
|
||||
alias: 'coffeeUmbracoDemoBlock',
|
||||
name: 'Favorite Coffee',
|
||||
description: null,
|
||||
icon: 'icon-coffee',
|
||||
allowedAsRoot: true,
|
||||
variesByCulture: false,
|
||||
variesBySegment: false,
|
||||
isElement: true,
|
||||
hasChildren: false,
|
||||
isContainer: false,
|
||||
parentId: 'folder-umbraco-demo-blocks-id',
|
||||
isFolder: false,
|
||||
allowedContentTypes: [],
|
||||
compositions: [],
|
||||
cleanup: {
|
||||
preventCleanup: false,
|
||||
keepAllVersionsNewerThanDays: null,
|
||||
keepLatestVersionPerDayForDays: null,
|
||||
},
|
||||
properties: [
|
||||
{
|
||||
id: 'coffee-name-id',
|
||||
containerId: 'coffee-content-group-key',
|
||||
alias: 'coffeeName',
|
||||
name: 'Name of Coffee',
|
||||
description: '',
|
||||
dataTypeId: 'dt-textBox',
|
||||
variesByCulture: false,
|
||||
variesBySegment: false,
|
||||
sortOrder: 10,
|
||||
validation: {
|
||||
mandatory: true,
|
||||
mandatoryMessage: null,
|
||||
regEx: null,
|
||||
regExMessage: null,
|
||||
},
|
||||
appearance: {
|
||||
labelOnTop: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'coffee-size-id',
|
||||
containerId: 'coffee-content-group-key',
|
||||
alias: 'coffeeSize',
|
||||
name: 'Amount (deciliter)',
|
||||
description: '',
|
||||
dataTypeId: 'dt-integer',
|
||||
variesByCulture: false,
|
||||
variesBySegment: false,
|
||||
sortOrder: 10,
|
||||
validation: {
|
||||
mandatory: true,
|
||||
mandatoryMessage: null,
|
||||
regEx: null,
|
||||
regExMessage: null,
|
||||
},
|
||||
appearance: {
|
||||
labelOnTop: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
containers: [
|
||||
{
|
||||
id: 'coffee-content-group-key',
|
||||
parentId: null,
|
||||
name: 'Content',
|
||||
type: 'Group',
|
||||
sortOrder: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'document-type',
|
||||
allowedTemplateIds: [],
|
||||
defaultTemplateId: null,
|
||||
id: 'headline-umbraco-demo-block-id',
|
||||
alias: 'headlineUmbracoDemoBlock',
|
||||
name: 'Headline',
|
||||
description: null,
|
||||
icon: 'icon-edit',
|
||||
allowedAsRoot: true,
|
||||
variesByCulture: false,
|
||||
variesBySegment: false,
|
||||
isElement: true,
|
||||
hasChildren: false,
|
||||
isContainer: false,
|
||||
parentId: 'folder-umbraco-demo-blocks-id',
|
||||
isFolder: false,
|
||||
allowedContentTypes: [],
|
||||
compositions: [],
|
||||
cleanup: {
|
||||
preventCleanup: false,
|
||||
keepAllVersionsNewerThanDays: null,
|
||||
keepLatestVersionPerDayForDays: null,
|
||||
},
|
||||
properties: [
|
||||
{
|
||||
id: 'headline-id',
|
||||
containerId: 'headline-content-group-key',
|
||||
alias: 'headline',
|
||||
name: 'Headline',
|
||||
description: '',
|
||||
dataTypeId: 'dt-textBox',
|
||||
variesByCulture: false,
|
||||
variesBySegment: false,
|
||||
sortOrder: 10,
|
||||
validation: {
|
||||
mandatory: true,
|
||||
mandatoryMessage: null,
|
||||
regEx: null,
|
||||
regExMessage: null,
|
||||
},
|
||||
appearance: {
|
||||
labelOnTop: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
containers: [
|
||||
{
|
||||
id: 'headline-content-group-key',
|
||||
parentId: null,
|
||||
name: 'Content',
|
||||
type: 'Group',
|
||||
sortOrder: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'document-type',
|
||||
allowedTemplateIds: [],
|
||||
defaultTemplateId: null,
|
||||
id: 'image-umbraco-demo-block-id',
|
||||
alias: 'imageUmbracoDemoBlock',
|
||||
name: 'Image',
|
||||
description: null,
|
||||
icon: 'icon-picture',
|
||||
allowedAsRoot: true,
|
||||
variesByCulture: false,
|
||||
variesBySegment: false,
|
||||
isElement: true,
|
||||
hasChildren: false,
|
||||
isContainer: false,
|
||||
parentId: 'folder-umbraco-demo-blocks-id',
|
||||
isFolder: false,
|
||||
allowedContentTypes: [],
|
||||
compositions: [],
|
||||
cleanup: {
|
||||
preventCleanup: false,
|
||||
keepAllVersionsNewerThanDays: null,
|
||||
keepLatestVersionPerDayForDays: null,
|
||||
},
|
||||
properties: [
|
||||
{
|
||||
id: 'image-id',
|
||||
containerId: 'image-content-group-key',
|
||||
alias: 'image',
|
||||
name: 'Image',
|
||||
description: '',
|
||||
dataTypeId: 'dt-mediaPicker',
|
||||
variesByCulture: false,
|
||||
variesBySegment: false,
|
||||
sortOrder: 10,
|
||||
validation: {
|
||||
mandatory: true,
|
||||
mandatoryMessage: null,
|
||||
regEx: null,
|
||||
regExMessage: null,
|
||||
},
|
||||
appearance: {
|
||||
labelOnTop: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
containers: [
|
||||
{
|
||||
id: 'image-content-group-key',
|
||||
parentId: null,
|
||||
name: 'Content',
|
||||
type: 'Group',
|
||||
sortOrder: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'document-type',
|
||||
allowedTemplateIds: [],
|
||||
defaultTemplateId: null,
|
||||
id: 'rich-text-umbraco-demo-block-id',
|
||||
alias: 'richTextUmbracoDemoBlock',
|
||||
name: 'Rich Text',
|
||||
description: null,
|
||||
icon: 'icon-diploma',
|
||||
allowedAsRoot: true,
|
||||
variesByCulture: false,
|
||||
variesBySegment: false,
|
||||
isElement: true,
|
||||
hasChildren: false,
|
||||
isContainer: false,
|
||||
parentId: 'folder-umbraco-demo-blocks-id',
|
||||
isFolder: false,
|
||||
allowedContentTypes: [],
|
||||
compositions: [],
|
||||
cleanup: {
|
||||
preventCleanup: false,
|
||||
keepAllVersionsNewerThanDays: null,
|
||||
keepLatestVersionPerDayForDays: null,
|
||||
},
|
||||
properties: [
|
||||
{
|
||||
id: 'rich-text-id',
|
||||
containerId: 'rich-text-content-group-key',
|
||||
alias: 'richText',
|
||||
name: 'Text',
|
||||
description: '',
|
||||
dataTypeId: 'dt-richTextEditor',
|
||||
variesByCulture: false,
|
||||
variesBySegment: false,
|
||||
sortOrder: 10,
|
||||
validation: {
|
||||
mandatory: true,
|
||||
mandatoryMessage: null,
|
||||
regEx: null,
|
||||
regExMessage: null,
|
||||
},
|
||||
appearance: {
|
||||
labelOnTop: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
containers: [
|
||||
{
|
||||
id: 'rich-text-content-group-key',
|
||||
parentId: null,
|
||||
name: 'Content',
|
||||
type: 'Group',
|
||||
sortOrder: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'document-type',
|
||||
allowedTemplateIds: [],
|
||||
defaultTemplateId: null,
|
||||
id: 'two-column-layout-umbraco-demo-block-id',
|
||||
alias: 'twoColumnLayoutUmbracoDemoBlock',
|
||||
name: 'Two Column Layout',
|
||||
description: null,
|
||||
icon: 'icon-book-alt',
|
||||
allowedAsRoot: true,
|
||||
variesByCulture: false,
|
||||
variesBySegment: false,
|
||||
isElement: true,
|
||||
hasChildren: false,
|
||||
isContainer: false,
|
||||
parentId: 'folder-umbraco-demo-blocks-id',
|
||||
isFolder: false,
|
||||
allowedContentTypes: [],
|
||||
compositions: [],
|
||||
cleanup: {
|
||||
preventCleanup: false,
|
||||
keepAllVersionsNewerThanDays: null,
|
||||
keepLatestVersionPerDayForDays: null,
|
||||
},
|
||||
properties: [],
|
||||
containers: [],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -33,6 +33,9 @@ export class UmbPropertyEditorUIBlockListBlockElement extends UmbLitElement impl
|
||||
this.observe(this.#context.label, (label) => {
|
||||
this._label = label;
|
||||
});
|
||||
this.observe(this.#context.layout, (layout) => {
|
||||
console.log('layout', layout);
|
||||
});
|
||||
}
|
||||
|
||||
#requestDelete() {
|
||||
@@ -81,8 +84,9 @@ export class UmbPropertyEditorUIBlockListBlockElement extends UmbLitElement impl
|
||||
}
|
||||
uui-action-bar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: var(--uui-size-2);
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { UMB_BLOCK_LIST_PROPERTY_EDITOR_ALIAS } from './manifests.js';
|
||||
import { html, customElement, property, state, styleMap, repeat, css } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { html, customElement, property, state, repeat, css, nothing } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
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,
|
||||
UmbBlockLayoutBaseModel,
|
||||
UmbBlockManagerContext,
|
||||
UmbBlockTypeBase,
|
||||
@@ -14,6 +15,7 @@ import '../../components/block-list-block/index.js';
|
||||
import { buildUdi } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbId } from '@umbraco-cms/backoffice/id';
|
||||
import type { NumberRangeValueType } from '@umbraco-cms/backoffice/models';
|
||||
import { UMB_MODAL_MANAGER_CONTEXT_TOKEN, UmbModalManagerContext } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
export interface UmbBlockListLayoutModel extends UmbBlockLayoutBaseModel {}
|
||||
|
||||
@@ -67,13 +69,23 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
|
||||
@state()
|
||||
private _limitMax?: number;
|
||||
|
||||
@state()
|
||||
private _blocks?: Array<UmbBlockTypeBase>;
|
||||
|
||||
#context = new UmbBlockManagerContext(this);
|
||||
|
||||
@state()
|
||||
_layouts: Array<UmbBlockLayoutBaseModel> = [];
|
||||
|
||||
#modalContext?: UmbModalManagerContext;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => {
|
||||
this.#modalContext = instance;
|
||||
});
|
||||
|
||||
// TODO: Prevent initial notification from these observes:
|
||||
this.observe(this.#context.layouts, (layouts) => {
|
||||
this._value.layout[UMB_BLOCK_LIST_PROPERTY_EDITOR_ALIAS] = layouts;
|
||||
@@ -93,24 +105,34 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
|
||||
// Notify that the value has changed.
|
||||
//console.log('settings changed', this._value);
|
||||
});
|
||||
this.observe(this.#context.blockTypes, (blockTypes) => {
|
||||
this._blocks = blockTypes;
|
||||
});
|
||||
}
|
||||
|
||||
#openBlockCatalogue() {
|
||||
// Open modal.
|
||||
async #openBlockCatalogue(openClipboard: boolean = false) {
|
||||
//Open modal
|
||||
const modalContext = this.#modalContext?.open(UMB_BLOCK_CATALOGUE_MODAL, {
|
||||
data: { blocks: this._blocks ?? [], openClipboard },
|
||||
});
|
||||
|
||||
// TEMP Hack:
|
||||
const data = await modalContext?.onSubmit();
|
||||
|
||||
const contentElementTypeKey = this.#context.getBlockTypes()[0]!.contentElementTypeKey;
|
||||
/**TODO: Insert next modal for data */
|
||||
console.log('submitted', data);
|
||||
|
||||
const contentUdi = buildUdi('element', UmbId.new());
|
||||
const settingsUdi = buildUdi('element', UmbId.new());
|
||||
if (!data) return;
|
||||
|
||||
const block = this._blocks?.find((x) => x.contentElementTypeKey === data.key);
|
||||
|
||||
if (!block?.contentElementTypeKey) return;
|
||||
|
||||
this.#context.createBlock(
|
||||
{
|
||||
contentUdi,
|
||||
settingsUdi,
|
||||
contentUdi: buildUdi('element', UmbId.new()),
|
||||
settingsUdi: buildUdi('element', UmbId.new()),
|
||||
},
|
||||
contentElementTypeKey,
|
||||
block.contentElementTypeKey,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -119,21 +141,46 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
|
||||
this._layouts,
|
||||
(x) => x.contentUdi,
|
||||
(layoutEntry) =>
|
||||
html` <uui-button-inline-create></uui-button-inline-create>
|
||||
html`<uui-button-inline-create></uui-button-inline-create>
|
||||
<umb-property-editor-ui-block-list-block .layout=${layoutEntry}>
|
||||
</umb-property-editor-ui-block-list-block>`,
|
||||
</umb-property-editor-ui-block-list-block> `,
|
||||
)}
|
||||
<uui-button id="add-button" look="placeholder" @click=${this.#openBlockCatalogue} label="open">Add</uui-button>`;
|
||||
<uui-button-group>
|
||||
<uui-button
|
||||
id="add-button"
|
||||
look="placeholder"
|
||||
label=${this.localize.term('content_createEmpty')}
|
||||
@click=${() => this.#openBlockCatalogue()}>
|
||||
${this.localize.term('content_createEmpty')}
|
||||
</uui-button>
|
||||
<uui-button
|
||||
label=${this.localize.term('content_createFromClipboard')}
|
||||
look="placeholder"
|
||||
@click=${() => this.#openBlockCatalogue(true)}>
|
||||
<uui-icon name="icon-paste-in"></uui-icon>
|
||||
</uui-button>
|
||||
</uui-button-group>`;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -9,4 +9,14 @@ export interface UmbBlockTypeBase {
|
||||
iconColor?: string;
|
||||
backgroundColor?: string;
|
||||
editorSize?: UUIModalSidebarSize;
|
||||
icon?: string; // remove later
|
||||
}
|
||||
|
||||
export interface UmbBlockTypeGroup {
|
||||
name?: string | null;
|
||||
key: string;
|
||||
}
|
||||
|
||||
export interface UmbBlockTypeWithGroupKey extends UmbBlockTypeBase {
|
||||
groupKey?: string | null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from './modals/index.js';
|
||||
@@ -0,0 +1,3 @@
|
||||
import { manifests as modalManifests } from './modals/manifests.js';
|
||||
|
||||
export const manifests = [...modalManifests];
|
||||
@@ -0,0 +1,129 @@
|
||||
import {
|
||||
UmbBlockCatalogueModalData,
|
||||
UmbBlockCatalogueModalValue,
|
||||
UmbBlockTypeWithGroupKey,
|
||||
} from '@umbraco-cms/backoffice/block';
|
||||
import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/document';
|
||||
import { css, html, customElement, state, repeat, ifDefined, nothing } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { groupBy } from '@umbraco-cms/backoffice/external/lodash';
|
||||
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
@customElement('umb-block-catalogue-modal')
|
||||
export class UmbBlockCatalogueModalElement extends UmbModalBaseElement<
|
||||
UmbBlockCatalogueModalData,
|
||||
UmbBlockCatalogueModalValue
|
||||
> {
|
||||
@state()
|
||||
private _blocks: Array<UmbBlockTypeWithGroupKey> = [];
|
||||
|
||||
@state()
|
||||
private _blockGroups: Array<{ key: string; name: string }> = [];
|
||||
|
||||
@state()
|
||||
openClipboard?: boolean;
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
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();
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<umb-body-layout headline="${this.localize.term('blockEditor_addBlock')}">
|
||||
${this.#renderViews()} ${this.openClipboard ? this.#renderClipboard() : this.#renderCreateEmpty()}
|
||||
<div slot="actions">
|
||||
<uui-button label=${this.localize.term('general_close')} @click=${this._rejectModal}></uui-button>
|
||||
<uui-button
|
||||
label=${this.localize.term('general_submit')}
|
||||
look="primary"
|
||||
color="positive"
|
||||
@click=${this._submitModal}></uui-button>
|
||||
</div>
|
||||
</umb-body-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderClipboard() {
|
||||
return html`Clipboard`;
|
||||
}
|
||||
|
||||
#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(
|
||||
(group) => html`
|
||||
${group.name ? html`<h2>${group.name}</h2>` : nothing}
|
||||
<div class="blockGroup">
|
||||
${repeat(
|
||||
group.blocks,
|
||||
(block) => block.contentElementTypeKey,
|
||||
(block) => html`
|
||||
<uui-card-block-type
|
||||
name=${ifDefined(block.label)}
|
||||
background=${ifDefined(block.backgroundColor)}
|
||||
style="color: ${block.iconColor}"
|
||||
@open=${() => this.#onClickBlock(block.contentElementTypeKey)}>
|
||||
<uui-icon .name=${block.icon ?? ''}></uui-icon>
|
||||
</uui-card-block-type>
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
`,
|
||||
)}
|
||||
`;
|
||||
}
|
||||
|
||||
#renderViews() {
|
||||
return html`
|
||||
<uui-tab-group slot="navigation">
|
||||
<uui-tab label="Create Empty" ?active=${!this.openClipboard} @click=${() => (this.openClipboard = false)}>
|
||||
Create Empty
|
||||
<uui-icon slot="icon" name="icon-add"></uui-icon>
|
||||
</uui-tab>
|
||||
<uui-tab label="Clipboard" ?active=${this.openClipboard} @click=${() => (this.openClipboard = true)}>
|
||||
Clipboard
|
||||
<uui-icon slot="icon" name="icon-paste-in"></uui-icon>
|
||||
</uui-tab>
|
||||
</uui-tab-group>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
css`
|
||||
.blockGroup {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr));
|
||||
}
|
||||
|
||||
uui-tab-group {
|
||||
--uui-tab-divider: var(--uui-color-border);
|
||||
border-left: 1px solid var(--uui-color-border);
|
||||
border-right: 1px solid var(--uui-color-border);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
export default UmbBlockCatalogueModalElement;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-block-catalogue-modal': UmbBlockCatalogueModalElement;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { UmbBlockTypeBase } from '@umbraco-cms/backoffice/block';
|
||||
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
export interface UmbBlockCatalogueModalData {
|
||||
blocks: Array<UmbBlockTypeBase>;
|
||||
blockGroups?: Array<{ name: string; key: string }>;
|
||||
openClipboard?: boolean;
|
||||
}
|
||||
|
||||
export interface UmbBlockCatalogueModalValue {
|
||||
key: string;
|
||||
}
|
||||
|
||||
export const UMB_BLOCK_CATALOGUE_MODAL = new UmbModalToken<UmbBlockCatalogueModalData, UmbBlockCatalogueModalValue>(
|
||||
'Umb.Modal.BlockCatalogue',
|
||||
{
|
||||
modal: {
|
||||
type: 'sidebar',
|
||||
size: 'small',
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './block-catalogue-modal.element.js';
|
||||
export * from './block-catalogue-modal.token.js';
|
||||
@@ -0,0 +1 @@
|
||||
export * from './block-catalogue/index.js';
|
||||
@@ -0,0 +1,12 @@
|
||||
import type { ManifestModal } from '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
const modals: Array<ManifestModal> = [
|
||||
{
|
||||
type: 'modal',
|
||||
alias: 'Umb.Modal.BlockCatalogue',
|
||||
name: 'Block Catalogue Modal',
|
||||
js: () => import('./block-catalogue/block-catalogue-modal.element.js'),
|
||||
},
|
||||
];
|
||||
|
||||
export const manifests = [...modals];
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './block/index.js';
|
||||
export * from './block-grid/index.js';
|
||||
export * from './block-list/index.js';
|
||||
export * from './block-manager/index.js';
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { manifests as blockManifests } from './block/manifests.js';
|
||||
import { manifests as blockGridManifests } from './block-grid/manifests.js';
|
||||
import { manifests as blockListManifests } from './block-list/manifests.js';
|
||||
import { manifests as blockRteManifests } from './block-rte/manifests.js';
|
||||
import { manifests as blockTypeManifests } from './block-type/manifests.js';
|
||||
|
||||
export const manifests = [...blockTypeManifests, ...blockListManifests, ...blockGridManifests, ...blockRteManifests];
|
||||
export const manifests = [
|
||||
...blockManifests,
|
||||
...blockTypeManifests,
|
||||
...blockListManifests,
|
||||
...blockGridManifests,
|
||||
...blockRteManifests,
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user