This commit is contained in:
Lone Iversen
2023-03-23 11:22:49 +01:00
parent 1f78421699
commit 74f56186ca
11 changed files with 356 additions and 106 deletions

View File

@@ -123,8 +123,9 @@ export class UmbWorkspaceViewDocumentTypeDesignElement extends UmbLitElement {
<div id="wrapper">
<uui-box class="group-wrapper">
<div class="group-headline" slot="headline">
<uui-input label="Group name" value="${this._documentType?.name ?? ''}" size="10"></uui-input>
<uui-button label="Delete group" compact><uui-icon name="umb:trash"></uui-icon></uui-button>
<uui-input label="Group name" value="${this._documentType?.name ?? ''}" size="10">
<uui-button slot="append" label="Delete group" compact><uui-icon name="umb:trash"></uui-icon></uui-button>
</uui-input>
</div>
<umb-property-creator></umb-property-creator>
</uui-box>

View File

@@ -1,10 +1,9 @@
import { css, html } from 'lit';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement, property, state } from 'lit/decorators.js';
import { customElement, state } from 'lit/decorators.js';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import { DocumentTypeResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbWorkspaceDocumentTypeContext } from '../../document-type-workspace.context';
import '../../../../../shared/property-creator/property-creator.element.ts';
@customElement('umb-workspace-view-document-type-templates')
@@ -37,24 +36,13 @@ export class UmbWorkspaceViewDocumentTypeTemplatesElement extends UmbLitElement
`,
];
@property()
defaultTemplateKey?: string = '123';
@state()
_documentType?: DocumentTypeResponseModel;
@state()
_templates = [
{ key: '123', name: 'Blog Post Page' },
{ key: '456', name: 'Blog Entry Page' },
];
private _workspaceContext?: UmbWorkspaceDocumentTypeContext;
constructor() {
super();
// TODO: Figure out if this is the best way to consume the context or if it can be strongly typed with an UmbContextToken
this.consumeContext<UmbWorkspaceDocumentTypeContext>('umbWorkspaceContext', (documentTypeContext) => {
this._workspaceContext = documentTypeContext;
this._observeDocumentType();
@@ -69,13 +57,14 @@ export class UmbWorkspaceViewDocumentTypeTemplatesElement extends UmbLitElement
});
}
#changeDefaultTemplate(e: CustomEvent) {
//this.defaultTemplateKey = (e.target as UmbTemplateCardElement).value as string;
console.log('default template key', this.defaultTemplateKey);
async #changeDefaultKey(e: CustomEvent) {
// save new default key
console.log('workspace: default template key', e);
}
#removeTemplate(key: string) {
console.log('remove template', key);
#changeAllowedKeys(e: CustomEvent) {
// save new allowed keys
console.log('workspace: allowed templates changed', e);
}
render() {
@@ -83,7 +72,11 @@ export class UmbWorkspaceViewDocumentTypeTemplatesElement extends UmbLitElement
<umb-workspace-property-layout alias="Templates" label="Allowed Templates">
<div slot="description">Choose which templates editors are allowed to use on content of this type</div>
<div id="templates" slot="editor">
<umb-input-template-picker umb-input-template-picker></umb-input-template-picker>
<umb-input-template-picker
.defaultKey="${this._documentType?.defaultTemplateKey ?? ''}"
.allowedKeys="${this._documentType?.allowedTemplateKeys ?? []}"
@change-default="${this.#changeDefaultKey}"
@change-allowed="${this.#changeAllowedKeys}"></umb-input-template-picker>
</div>
</umb-workspace-property-layout>
</uui-box>`;

View File

@@ -1,15 +1,14 @@
import { css, html } from 'lit';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement, property, queryAll, state } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import { customElement, property, state } from 'lit/decorators.js';
import { FormControlMixin } from '@umbraco-ui/uui-base/lib/mixins';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/modal';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import { TemplateResource } from '@umbraco-cms/backoffice/backend-api';
import { UMB_CONFIRM_MODAL_TOKEN } from '../../modals/confirm';
import { TemplateResource, TemplateResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { UmbTemplateCardElement } from '../template-card/template-card.element';
import { UMB_TEMPLATE_PICKER_MODAL_TOKEN } from '../../modals/template-picker';
import { UMB_TEMPLATE_MODAL_TOKEN } from '../../modals/template';
@customElement('umb-input-template-picker')
export class UmbInputTemplatePickerElement extends FormControlMixin(UmbLitElement) {
@@ -31,19 +30,6 @@ export class UmbInputTemplatePickerElement extends FormControlMixin(UmbLitElemen
min-width: 180px;
min-height: 150px;
}
.fade-in {
animation: fadeIn 1s;
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
`,
];
/**
@@ -82,30 +68,43 @@ export class UmbInputTemplatePickerElement extends FormControlMixin(UmbLitElemen
@property({ type: String, attribute: 'min-message' })
maxMessage = 'This field exceeds the allowed amount of items';
@state()
private _items: Array<any> = [
{ key: '2bf464b6-3aca-4388-b043-4eb439cc2643', name: 'Doc 1', default: false },
{ key: '9a84c0b3-03b4-4dd4-84ac-706740ac0f71', name: 'Test', default: true },
];
_allowedKeys: Array<string> = [];
@property({ type: Array<string> })
public get allowedKeys() {
return this._allowedKeys;
}
public set allowedKeys(newKeys: Array<string>) {
//this.#observePickedTemplates();
this._allowedKeys = newKeys;
}
_defaultKey = '';
@property({ type: String })
public get defaultKey(): string {
return this._defaultKey;
}
public set defaultKey(newKey: string) {
this._defaultKey = newKey;
super.value = newKey;
}
private _modalContext?: UmbModalContext;
//private _documentStore?: UmbDocumentTreeStore;
//private _pickedItemsObserver?: UmbObserverController<FolderTreeItemModel>;
//private _templateStore?: UmbTemplateTreeStore;
//private _pickedItemsObserver?: UmbObserverController<EntityTreeItemResponseModel[]>;
@state()
_templates: TemplateResponseModel[] = [];
public get templates(): TemplateResponseModel[] {
return this._templates;
}
public set templates(newTemplates: TemplateResponseModel[]) {
this._templates = newTemplates;
this.allowedKeys = newTemplates.map((template) => template.key ?? '');
}
constructor() {
super();
this.addValidator(
'rangeUnderflow',
() => this.minMessage,
() => !!this.min && this._items.length < this.min
);
this.addValidator(
'rangeOverflow',
() => this.maxMessage,
() => !!this.max && this._items.length > this.max
);
this.consumeContext(UMB_MODAL_CONTEXT_TOKEN, (instance) => {
this._modalContext = instance;
});
@@ -113,79 +112,83 @@ export class UmbInputTemplatePickerElement extends FormControlMixin(UmbLitElemen
connectedCallback(): void {
super.connectedCallback();
this._items = this._items.sort((a, b) => b.default - a.default);
this.#setup();
this.allowedKeys.forEach((key) => this.#setup(key));
}
async #setup() {
const templates = await tryExecuteAndNotify(this, TemplateResource.getTreeTemplateRoot({ skip: 0, take: 9999 }));
console.log(templates);
async #setup(templateKey: string) {
const { data } = await tryExecuteAndNotify(this, TemplateResource.getTemplateByKey({ key: templateKey }));
if (!data) return;
this.templates = [...this.templates, data];
}
protected getFormElement() {
return undefined;
}
#openTemplatePickerModal() {
console.log('template picker modal');
}
#changeSelected() {
console.log('selected');
}
/** Clicking the template card buttons */
#changeDefault(e: CustomEvent) {
const key = (e.target as UmbTemplateCardElement).value;
e.stopPropagation();
const newKey = (e.target as UmbTemplateCardElement).value as string;
this.defaultKey = newKey;
this.dispatchEvent(new CustomEvent('change-default', { bubbles: true, composed: true }));
}
const oldDefault = this._items.find((x) => x.default === true);
const newDefault = this._items.find((x) => x.key === key);
const items = this._items.map((item) => {
if (item.default === true) return { ...newDefault, default: true };
if (item.key === key) return { ...oldDefault, default: false };
return item;
#openPicker() {
//TODO: Tree-picker modal?
const modalHandler = this._modalContext?.open(UMB_TEMPLATE_PICKER_MODAL_TOKEN, {
multiple: true,
selection: [...this.allowedKeys],
});
this._items = items;
}
#openTemplate(e: CustomEvent) {
const key = (e.target as UmbTemplateCardElement).value;
console.log('open', key);
modalHandler?.onSubmit().then((data) => {
console.log(data.selection);
this.dispatchEvent(new CustomEvent('change-allowed', { bubbles: true, composed: true }));
});
}
#removeTemplate(key: string) {
console.log('remove', key);
console.log('picker: remove', key);
const templateIndex = this.templates.findIndex((x) => x.key === key);
this.templates.splice(templateIndex, 1);
this.templates = [...this._templates];
}
render() {
return html`
${repeat(
this._items,
(template) => template.default,
(template, index) => html`<div class="fade-in">
${this.templates.map(
(template) => html`
<umb-template-card
class="template-card"
name="${template.name}"
key="${template.key}"
@default-change="${this.#changeDefault}"
.name="${template.name ?? ''}"
.key="${template.key ?? ''}"
@change-default="${this.#changeDefault}"
@open="${this.#openTemplate}"
?default="${template.default}">
?default="${template.key === this.defaultKey}">
<uui-button
slot="actions"
label="Remove document ${template.name}"
@click="${() => this.#removeTemplate(template.key)}"
@click="${() => this.#removeTemplate(template.key ?? '')}"
compact>
<uui-icon name="umb:trash"> </uui-icon>
</uui-button>
</umb-template-card>
</div>`
`
)}
<uui-button id="add-button" look="placeholder" label="open">Add</uui-button>
<uui-button id="add-button" look="placeholder" label="open" @click="${this.#openPicker}">Add</uui-button>
`;
}
#openTemplate(e: CustomEvent) {
const key = (e.target as UmbTemplateCardElement).value;
const modalHandler = this._modalContext?.open(UMB_TEMPLATE_MODAL_TOKEN, {
multiple: true,
selection: [...this.allowedKeys],
});
modalHandler?.onSubmit().then((res) => {
console.log('save template');
});
}
}
export default UmbInputTemplatePickerElement;

View File

@@ -139,7 +139,7 @@ export class UmbTemplateCardElement extends FormControlMixin(UmbLitElement) {
e.preventDefault();
e.stopPropagation();
//this.selected = true;
this.dispatchEvent(new CustomEvent('default-change', { bubbles: true, composed: true }));
this.dispatchEvent(new CustomEvent('change-default', { bubbles: true, composed: true }));
}
#openTemplate(e: KeyboardEvent) {
e.preventDefault();
@@ -149,7 +149,6 @@ export class UmbTemplateCardElement extends FormControlMixin(UmbLitElement) {
render() {
return html`<div id="card">
<slot name="actions"></slot>
<button id="open-part" aria-label="Open ${this.name}" @click="${this.#openTemplate}">
<uui-icon class="logo" name="umb:layout"></uui-icon>
<strong>${this.name.length ? this.name : 'Untitled template'}</strong>
@@ -157,6 +156,7 @@ export class UmbTemplateCardElement extends FormControlMixin(UmbLitElement) {
<uui-button id="bottom" label="Default template" ?disabled="${this.default}" @click="${this.#setSelection}">
${this.default ? '(Default template)' : 'Set default'}
</uui-button>
<slot name="actions"></slot>
</div>`;
}
}

View File

@@ -40,9 +40,9 @@ export class UmbWorkspaceLayout extends UmbLitElement {
}
#router-slot {
display:flex;
flex-direction:column;
height:100%;
display: flex;
flex-direction: column;
height: 100%;
}
uui-input {

View File

@@ -31,6 +31,18 @@ const modals: Array<ManifestModal> = [
name: 'Section Picker Modal',
loader: () => import('./section-picker/section-picker-modal.element'),
},
{
type: 'modal',
alias: 'Umb.Modal.TemplatePicker',
name: 'Template Picker Modal',
loader: () => import('./template-picker/template-picker-modal.element'),
},
{
type: 'modal',
alias: 'Umb.Modal.Template',
name: 'Template Modal',
loader: () => import('./template/template-modal.element'),
},
];
export const manifests = [...modals];

View File

@@ -0,0 +1,18 @@
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export interface UmbTemplatePickerModalData {
multiple: boolean;
selection: string[];
}
export interface UmbTemplatePickerModalResult {
selection: string[] | undefined;
}
export const UMB_TEMPLATE_PICKER_MODAL_TOKEN = new UmbModalToken<
UmbTemplatePickerModalData,
UmbTemplatePickerModalResult
>('Umb.Modal.TemplatePicker', {
type: 'sidebar',
size: 'small',
});

View File

@@ -0,0 +1,104 @@
import { css, html } from 'lit';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement, state } from 'lit/decorators.js';
import { UmbModalBaseElement } from '@umbraco-cms/internal/modal';
import { UmbTreeElement } from '../../components/tree/tree.element';
import { UmbTemplatePickerModalData, UmbTemplatePickerModalResult } from '.';
//TODO: make a default tree-picker that can be used across multiple pickers
// TODO: make use of UmbPickerLayoutBase
@customElement('umb-template-picker-modal')
export class UmbTemplatePickerModalElement extends UmbModalBaseElement<
UmbTemplatePickerModalData,
UmbTemplatePickerModalResult
> {
static styles = [
UUITextStyles,
css`
h3 {
margin-left: var(--uui-size-space-5);
margin-right: var(--uui-size-space-5);
}
uui-input {
width: 100%;
}
hr {
border: none;
border-bottom: 1px solid var(--uui-color-divider);
margin: 16px 0;
}
#content-list {
display: flex;
flex-direction: column;
gap: var(--uui-size-space-3);
}
.content-item {
cursor: pointer;
}
.content-item.selected {
background-color: var(--uui-color-selected);
color: var(--uui-color-selected-contrast);
}
`,
];
@state()
_selection: Array<string> = [];
@state()
_multiple = true;
connectedCallback() {
super.connectedCallback();
this._selection = this.data?.selection ?? [];
this._multiple = this.data?.multiple ?? true;
}
private _handleSelectionChange(e: CustomEvent) {
e.stopPropagation();
const element = e.target as UmbTreeElement;
//TODO: Should multiple property be implemented here or be passed down into umb-tree?
this._selection = this._multiple ? element.selection : [element.selection[element.selection.length - 1]];
}
private _submit() {
this.modalHandler?.submit({ selection: this._selection });
}
private _close() {
this.modalHandler?.reject();
}
render() {
return html`
<umb-workspace-layout headline="Select Content">
<uui-box>
<uui-input></uui-input>
<hr />
<umb-tree
alias="Umb.Tree.Templates"
@selected=${this._handleSelectionChange}
.selection=${this._selection}
selectable></umb-tree>
</uui-box>
<div slot="actions">
<uui-button label="Close" @click=${this._close}></uui-button>
<uui-button label="Submit" look="primary" color="positive" @click=${this._submit}></uui-button>
</div>
</umb-workspace-layout>
`;
}
}
export default UmbTemplatePickerModalElement;
declare global {
interface HTMLElementTagNameMap {
'umb-template-picker-modal': UmbTemplatePickerModalElement;
}
}

View File

@@ -0,0 +1,18 @@
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export interface UmbTemplateModalData {
multiple: boolean;
selection: string[];
}
export interface UmbTemplateModalResult {
selection: string[] | undefined;
}
export const UMB_TEMPLATE_MODAL_TOKEN = new UmbModalToken<UmbTemplateModalData, UmbTemplateModalResult>(
'Umb.Modal.Template',
{
type: 'sidebar',
size: 'large',
}
);

View File

@@ -0,0 +1,97 @@
import { css, html } from 'lit';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement, state } from 'lit/decorators.js';
import { UmbModalBaseElement } from '@umbraco-cms/internal/modal';
import { UmbTreeElement } from '../../components/tree/tree.element';
import { UmbTemplateModalData, UmbTemplateModalResult } from '.';
//TODO: make a default tree-picker that can be used across multiple pickers
// TODO: make use of UmbPickerLayoutBase
@customElement('umb-template-modal')
export class UmbTemplateModalElement extends UmbModalBaseElement<UmbTemplateModalData, UmbTemplateModalResult> {
static styles = [
UUITextStyles,
css`
h3 {
margin-left: var(--uui-size-space-5);
margin-right: var(--uui-size-space-5);
}
uui-input {
width: 100%;
}
hr {
border: none;
border-bottom: 1px solid var(--uui-color-divider);
margin: 16px 0;
}
#content-list {
display: flex;
flex-direction: column;
gap: var(--uui-size-space-3);
}
.content-item {
cursor: pointer;
}
.content-item.selected {
background-color: var(--uui-color-selected);
color: var(--uui-color-selected-contrast);
}
`,
];
@state()
_selection: Array<string> = [];
@state()
_multiple = true;
connectedCallback() {
super.connectedCallback();
this._selection = this.data?.selection ?? [];
this._multiple = this.data?.multiple ?? true;
}
private _handleSelectionChange(e: CustomEvent) {
e.stopPropagation();
const element = e.target as UmbTreeElement;
//TODO: Should multiple property be implemented here or be passed down into umb-tree?
this._selection = this._multiple ? element.selection : [element.selection[element.selection.length - 1]];
}
private _submit() {
this.modalHandler?.submit({ selection: this._selection });
}
private _close() {
this.modalHandler?.reject();
}
render() {
return html`
<umb-workspace-layout headline="Templates">
<uui-box>
<uui-input></uui-input>
<hr />
Code editor?
</uui-box>
<div slot="actions">
<uui-button label="Close" @click=${this._close}></uui-button>
<uui-button label="Submit" look="primary" color="positive" @click=${this._submit}></uui-button>
</div>
</umb-workspace-layout>
`;
}
}
export default UmbTemplateModalElement;
declare global {
interface HTMLElementTagNameMap {
'umb-template-modal': UmbTemplateModalElement;
}
}

View File

@@ -890,8 +890,12 @@ export const data: Array<DocumentTypeResponseModel> = [
},
},
{
allowedTemplateKeys: [],
defaultTemplateKey: null,
allowedTemplateKeys: [
'2bf464b6-3aca-4388-b043-4eb439cc2643',
'9a84c0b3-03b4-4dd4-84ac-706740ac0f71',
'9a84c0b3-03b4-4dd4-84ac-706740ac0f72',
],
defaultTemplateKey: '2bf464b6-3aca-4388-b043-4eb439cc2643',
key: 'simple-document-type-key',
alias: 'simpleDocumentType',
name: 'Simple Document Type',