diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace-editor.element.ts index f4b12415ff..939579de9c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace-editor.element.ts @@ -24,7 +24,7 @@ export class UmbBlockWorkspaceEditorElement extends UmbLitElement { this.consumeContext(UMB_BLOCK_WORKSPACE_CONTEXT, (instance) => { this.#workspaceContext = instance; - this.#workspaceContext?.createPropertyDatasetContext(this); + this.#workspaceContext?.content.createPropertyDatasetContext(this); }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/manifests.ts index 85454e80de..3afce80e47 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/manifests.ts @@ -31,4 +31,22 @@ export const manifests: Array = [ entityType: 'block', }, }, + { + type: 'workspaceView', + alias: 'Umb.WorkspaceView.Block.Content', + name: 'Block Workspace Content View', + js: () => import('./views/edit/block-workspace-view-edit.element.js'), + weight: 1000, + meta: { + label: 'Content', + pathname: 'content', + icon: 'icon-document', + }, + conditions: [ + { + alias: 'Umb.Condition.WorkspaceAlias', + match: UMB_BLOCK_WORKSPACE_ALIAS, + }, + ], + }, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-properties.element.ts new file mode 100644 index 0000000000..cf683c464a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-properties.element.ts @@ -0,0 +1,72 @@ +import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../../block-workspace.context.js'; +import { css, html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { UmbContentTypePropertyStructureHelper, PropertyContainerTypes } from '@umbraco-cms/backoffice/content-type'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; +import { PropertyTypeModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; + +@customElement('umb-block-workspace-view-edit-properties') +export class UmbBlockWorkspaceViewEditPropertiesElement extends UmbLitElement { + @property({ type: String, attribute: 'container-name', reflect: false }) + public get containerName(): string | undefined { + return this._propertyStructureHelper.getContainerName(); + } + public set containerName(value: string | undefined) { + this._propertyStructureHelper.setContainerName(value); + } + + @property({ type: String, attribute: 'container-type', reflect: false }) + public get containerType(): PropertyContainerTypes | undefined { + return this._propertyStructureHelper.getContainerType(); + } + public set containerType(value: PropertyContainerTypes | undefined) { + this._propertyStructureHelper.setContainerType(value); + } + + _propertyStructureHelper = new UmbContentTypePropertyStructureHelper(this); + + @state() + _propertyStructure: Array = []; + + constructor() { + super(); + + this.consumeContext(UMB_BLOCK_WORKSPACE_CONTEXT, (workspaceContext) => { + this._propertyStructureHelper.setStructureManager(workspaceContext.content.structure); + }); + this.observe(this._propertyStructureHelper.propertyStructure, (propertyStructure) => { + this._propertyStructure = propertyStructure; + }); + } + + render() { + return repeat( + this._propertyStructure, + (property) => property.alias, + (property) => + html` `, + ); + } + + static styles = [ + UmbTextStyles, + css` + .property { + border-bottom: 1px solid var(--uui-color-divider); + } + .property:last-child { + border-bottom: 0; + } + `, + ]; +} + +export default UmbBlockWorkspaceViewEditPropertiesElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-block-workspace-view-edit-properties': UmbBlockWorkspaceViewEditPropertiesElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-tab.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-tab.element.ts new file mode 100644 index 0000000000..315bdc107a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-tab.element.ts @@ -0,0 +1,112 @@ +import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../../block-workspace.context.js'; +import { css, html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { UmbContentTypeContainerStructureHelper } from '@umbraco-cms/backoffice/content-type'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; +import { PropertyTypeContainerModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; + +import './block-workspace-view-edit-properties.element.js'; + +@customElement('umb-block-workspace-view-edit-tab') +export class UmbBlockWorkspaceViewEditTabElement extends UmbLitElement { + private _tabName?: string | undefined; + + @property({ type: String }) + public get tabName(): string | undefined { + return this._groupStructureHelper.getName(); + } + public set tabName(value: string | undefined) { + if (value === this._tabName) return; + const oldValue = this._tabName; + this._tabName = value; + this._groupStructureHelper.setName(value); + this.requestUpdate('tabName', oldValue); + } + + @property({ type: Boolean }) + public get noTabName(): boolean { + return this._groupStructureHelper.getIsRoot(); + } + public set noTabName(value: boolean) { + this._groupStructureHelper.setIsRoot(value); + } + + private _ownerTabId?: string | null; + @property({ type: String }) + public get ownerTabId(): string | null | undefined { + return this._ownerTabId; + } + public set ownerTabId(value: string | null | undefined) { + if (value === this._ownerTabId) return; + this._ownerTabId = value; + this._groupStructureHelper.setOwnerId(value); + } + + _groupStructureHelper = new UmbContentTypeContainerStructureHelper(this); + + @state() + _groups: Array = []; + + @state() + _hasProperties = false; + + constructor() { + super(); + + this.consumeContext(UMB_BLOCK_WORKSPACE_CONTEXT, (workspaceContext) => { + this._groupStructureHelper.setStructureManager(workspaceContext.content.structure); + }); + this.observe(this._groupStructureHelper.containers, (groups) => { + this._groups = groups; + }); + this.observe(this._groupStructureHelper.hasProperties, (hasProperties) => { + this._hasProperties = hasProperties; + }); + } + + render() { + return html` + ${this._hasProperties + ? html` + + + + ` + : ''} + ${repeat( + this._groups, + (group) => group.name, + (group) => + html` + + `, + )} + `; + } + + static styles = [ + UmbTextStyles, + css` + uui-box { + --uui-box-default-padding: 0 var(--uui-size-space-5); + } + uui-box:not(:first-child) { + margin-top: var(--uui-size-layout-1); + } + `, + ]; +} + +export default UmbBlockWorkspaceViewEditTabElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-block-workspace-view-edit-tab': UmbBlockWorkspaceViewEditTabElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts new file mode 100644 index 0000000000..ddb4f3b067 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts @@ -0,0 +1,171 @@ +import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../../block-workspace.context.js'; +import type { UmbBlockWorkspaceViewEditTabElement } from './block-workspace-view-edit-tab.element.js'; +import { css, html, customElement, state, repeat } from '@umbraco-cms/backoffice/external/lit'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { UmbContentTypeContainerStructureHelper } from '@umbraco-cms/backoffice/content-type'; +import { + encodeFolderName, + UmbRoute, + UmbRouterSlotChangeEvent, + UmbRouterSlotInitEvent, +} from '@umbraco-cms/backoffice/router'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; +import { PropertyTypeContainerModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; +import { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry'; + +@customElement('umb-block-workspace-view-edit') +export class UmbBlockWorkspaceViewEditElement extends UmbLitElement implements UmbWorkspaceViewElement { + //private _hasRootProperties = false; + private _hasRootGroups = false; + + @state() + private _routes: UmbRoute[] = []; + + @state() + _tabs?: Array; + + @state() + private _routerPath?: string; + + @state() + private _activePath = ''; + + private _workspaceContext?: typeof UMB_BLOCK_WORKSPACE_CONTEXT.TYPE; + + private _tabsStructureHelper = new UmbContentTypeContainerStructureHelper(this); + + constructor() { + super(); + + this._tabsStructureHelper.setIsRoot(true); + this._tabsStructureHelper.setContainerChildType('Tab'); + this.observe(this._tabsStructureHelper.containers, (tabs) => { + this._tabs = tabs; + this._createRoutes(); + }); + + // _hasRootProperties can be gotten via _tabsStructureHelper.hasProperties. But we do not support root properties currently. + + this.consumeContext(UMB_BLOCK_WORKSPACE_CONTEXT, (workspaceContext) => { + this._workspaceContext = workspaceContext; + this._tabsStructureHelper.setStructureManager(workspaceContext.content.structure); + this._observeRootGroups(); + }); + } + + private _observeRootGroups() { + if (!this._workspaceContext) return; + + this.observe( + this._workspaceContext.content.structure.hasRootContainers('Group'), + (hasRootGroups) => { + this._hasRootGroups = hasRootGroups; + this._createRoutes(); + }, + '_observeGroups', + ); + } + + private _createRoutes() { + if (!this._tabs || !this._workspaceContext) return; + const routes: UmbRoute[] = []; + + if (this._tabs.length > 0) { + this._tabs?.forEach((tab) => { + const tabName = tab.name ?? ''; + routes.push({ + path: `tab/${encodeFolderName(tabName).toString()}`, + component: () => import('./block-workspace-view-edit-tab.element.js'), + setup: (component) => { + (component as UmbBlockWorkspaceViewEditTabElement).tabName = tabName; + // TODO: Consider if we can link these more simple, and not parse this on. + // Instead have the structure manager looking at wether one of the OwnerALikecontainers is in the owner document. + (component as UmbBlockWorkspaceViewEditTabElement).ownerTabId = + this._workspaceContext?.content.structure.isOwnerContainer(tab.id!) ? tab.id : undefined; + }, + }); + }); + } + + if (this._hasRootGroups) { + routes.push({ + path: '', + component: () => import('./block-workspace-view-edit-tab.element.js'), + setup: (component) => { + (component as UmbBlockWorkspaceViewEditTabElement).noTabName = true; + (component as UmbBlockWorkspaceViewEditTabElement).ownerTabId = null; + }, + }); + } + + if (routes.length !== 0) { + routes.push({ + path: '', + redirectTo: routes[0]?.path, + }); + } + + this._routes = routes; + } + + render() { + if (!this._routes || !this._tabs) return; + return html` + + ${this._routerPath && (this._tabs.length > 1 || (this._tabs.length === 1 && this._hasRootGroups)) + ? html` + ${this._hasRootGroups && this._tabs.length > 0 + ? html` + Content + ` + : ''} + ${repeat( + this._tabs, + (tab) => tab.name, + (tab) => { + const path = this._routerPath + '/tab/' + encodeFolderName(tab.name || ''); + return html`${tab.name}`; + }, + )} + ` + : ''} + + { + this._routerPath = event.target.absoluteRouterPath; + }} + @change=${(event: UmbRouterSlotChangeEvent) => { + this._activePath = event.target.absoluteActiveViewPath || ''; + }}> + + + `; + } + + static styles = [ + UmbTextStyles, + css` + :host { + display: block; + height: 100%; + --uui-tab-background: var(--uui-color-surface); + } + `, + ]; +} + +export default UmbBlockWorkspaceViewEditElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-block-workspace-view-edit': UmbBlockWorkspaceViewEditElement; + } +}