console.log('to be continued')}
+ @click=${this.#openTemplatingPageFieldModal}
look="placeholder"
label=${this.localize.term('template_insert')}>
- Value (Not implemented)
+ Value
Displays the value of a named field from the current page, with options to modify the value or fallback to
@@ -89,7 +105,7 @@ export class UmbTemplatingItemPickerModalElement extends UmbModalBaseElement<
Partial view
@@ -101,7 +117,7 @@ export class UmbTemplatingItemPickerModalElement extends UmbModalBaseElement<
Dictionary Item
diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-item-picker/templating-item-picker-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-item-picker/templating-item-picker-modal.token.ts
index 79e593dae8..9a0a15e733 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-item-picker/templating-item-picker-modal.token.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-item-picker/templating-item-picker-modal.token.ts
@@ -1,4 +1,5 @@
import type { CodeSnippetType } from '../../types.js';
+import type { UmbPartialViewPickerModalValue, UmbTemplatingPageFieldBuilderModalValue } from '../index.js';
import { type UmbDictionaryItemPickerModalValue, UmbModalToken } from '@umbraco-cms/backoffice/modal';
export interface UmbTemplatingItemPickerModalData {
@@ -6,7 +7,7 @@ export interface UmbTemplatingItemPickerModalData {
}
export type UmbTemplatingItemPickerModalValue = {
- value: string | UmbDictionaryItemPickerModalValue;
+ value: string;
type: CodeSnippetType;
};
diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/index.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/index.ts
new file mode 100644
index 0000000000..696a5c05e5
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/index.ts
@@ -0,0 +1,2 @@
+export * from './templating-page-field-builder-modal.element.js';
+export * from './templating-page-field-builder-modal.token.js';
diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/templating-page-field-builder-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/templating-page-field-builder-modal.element.ts
new file mode 100644
index 0000000000..37afe148ca
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/templating-page-field-builder-modal.element.ts
@@ -0,0 +1,109 @@
+import { getUmbracoFieldSnippet } from '../../utils/index.js';
+import type {
+ UmbTemplatingPageFieldBuilderModalData,
+ UmbTemplatingPageFieldBuilderModalValue,
+} from './templating-page-field-builder-modal.token.js';
+import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
+import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
+import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
+
+@customElement('umb-templating-page-field-builder-modal')
+export class UmbTemplatingPageFieldBuilderModalElement extends UmbModalBaseElement<
+ UmbTemplatingPageFieldBuilderModalData,
+ UmbTemplatingPageFieldBuilderModalValue
+> {
+ private _close() {
+ this.modalContext?.reject();
+ }
+
+ private _submit() {
+ if (!this._field) return;
+ this.value = { output: getUmbracoFieldSnippet(this._field, this._default, this._recursive) };
+ this.modalContext?.submit();
+ }
+
+ @state()
+ private _field?: string;
+
+ @state()
+ private _haveDefault: boolean = false;
+
+ @state()
+ private _default?: string;
+
+ @state()
+ private _recursive: boolean = false;
+
+ /** TODO: Implement "Choose field" */
+
+ render() {
+ return html`
+
+
+
+
+ Choose field
+
+ (Not implemented yet)
+
+
+ Default value
+
+ ${!this._haveDefault
+ ? html` (this._haveDefault = true)}>`
+ : html``}
+
+ Recursive
+
+
+ Output sample
+ ${this._field ? getUmbracoFieldSnippet(this._field, this._default, this._recursive) : ''}
+
+
+
+
+
+ `;
+ }
+
+ static styles = [
+ UmbTextStyles,
+ css`
+ uui-box > div {
+ display: grid;
+ gap: var(--uui-size-space-2);
+ }
+
+ uui-label:not(:first-child) {
+ margin-top: var(--uui-size-space-6);
+ }
+ `,
+ ];
+}
+
+export default UmbTemplatingPageFieldBuilderModalElement;
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-templating-page-field-builder-modal': UmbTemplatingPageFieldBuilderModalElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/templating-page-field-builder-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/templating-page-field-builder-modal.token.ts
new file mode 100644
index 0000000000..ad621e61b5
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/templating-page-field-builder-modal.token.ts
@@ -0,0 +1,17 @@
+import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
+
+export interface UmbTemplatingPageFieldBuilderModalData {}
+
+export type UmbTemplatingPageFieldBuilderModalValue = {
+ output: string;
+};
+
+export const UMB_TEMPLATING_PAGE_FIELD_BUILDER_MODAL = new UmbModalToken<
+ UmbTemplatingPageFieldBuilderModalData,
+ UmbTemplatingPageFieldBuilderModalValue
+>('Umb.Modal.TemplatingPageFieldBuilder', {
+ modal: {
+ type: 'sidebar',
+ size: 'small',
+ },
+});
diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-section-picker/index.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-section-picker/index.ts
index 5bb66c95b5..d5571f146d 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-section-picker/index.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-section-picker/index.ts
@@ -1,2 +1,2 @@
-export * from './templating-section-picker-input.element.js';
export * from './templating-section-picker-modal.element.js';
+export * from './templating-section-picker-modal.token.js';
diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-section-picker/templating-section-picker-input.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-section-picker/templating-section-picker-input.element.ts
deleted file mode 100644
index c8cf5632d1..0000000000
--- a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-section-picker/templating-section-picker-input.element.ts
+++ /dev/null
@@ -1,150 +0,0 @@
-import type { UUIInputElement } from '@umbraco-cms/backoffice/external/uui';
-import { UUIBooleanInputElement } from '@umbraco-cms/backoffice/external/uui';
-import { css, html, customElement, property, query } from '@umbraco-cms/backoffice/external/lit';
-import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
-
-@customElement('umb-insert-section-checkbox')
-export class UmbInsertSectionCheckboxElement extends UUIBooleanInputElement {
- renderCheckbox() {
- return html``;
- }
-
- @property({ type: Boolean, attribute: 'show-mandatory' })
- showMandatory = false;
-
- @property({ type: Boolean, attribute: 'show-input' })
- showInput = false;
-
- @query('uui-input')
- input?: UUIInputElement;
-
- @query('form')
- form?: HTMLFormElement;
-
- @query('uui-checkbox')
- checkbox?: HTMLFormElement;
-
- get snippet() {
- if (!this.snippetMethod) return '';
- const snippet = this.snippetMethod(this.inputValue as string, this.isMandatory) ?? '';
- return snippet;
- }
-
- @property({ attribute: false })
- snippetMethod?: (value: string, isMandatory: boolean) => string;
-
- validate() {
- if (!this.form) return true;
-
- this.form.requestSubmit();
- return this.form.checkValidity();
- }
-
- #preventDefault(event: Event) {
- event.preventDefault();
- }
-
- get inputValue() {
- return this.input?.value;
- }
-
- get isMandatory() {
- return this.checkbox?.checked;
- }
-
- /* eslint-disable lit-a11y/click-events-have-key-events */
- render() {
- return html`
- ${super.render()}
-
- ${this.checked ? html`` : ''}${this.label}
-
-
-
here goes some description
-
- ${this.checked && this.showInput
- ? html`
-
- `
- : ''}
- `;
- }
- /* eslint-enable lit-a11y/click-events-have-key-events */
-
- static styles = [
- ...UUIBooleanInputElement.styles,
- UmbTextStyles,
- css`
- :host {
- display: block;
- border-style: dashed;
- background-color: transparent;
- color: var(--uui-color-default-standalone, rgb(28, 35, 59));
- border-color: var(--uui-color-border-standalone, #c2c2c2);
- border-radius: var(--uui-border-radius, 3px);
- border-width: 1px;
- line-height: normal;
- padding: 6px 18px;
- }
-
- :host(:hover),
- :host(:focus),
- :host(:focus-within) {
- background-color: var(--uui-button-background-color-hover, transparent);
- color: var(--uui-color-default-emphasis, #3544b1);
- border-color: var(--uui-color-default-emphasis, #3544b1);
- }
-
- uui-icon {
- background-color: var(--uui-color-positive-emphasis);
- border-radius: 50%;
- padding: 0.2em;
- margin-right: 1ch;
- color: var(--uui-color-positive-contrast);
- font-size: 0.7em;
- }
-
- ::slotted(*) {
- line-height: normal;
- }
-
- .label {
- display: none;
- }
-
- h3,
- p {
- text-align: left;
- }
-
- uui-input {
- width: 100%;
- }
- `,
- ];
-}
-
-export default UmbInsertSectionCheckboxElement;
-
-declare global {
- interface HTMLElementTagNameMap {
- 'umb-insert-section-input': UmbInsertSectionCheckboxElement;
- }
-}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-section-picker/templating-section-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-section-picker/templating-section-picker-modal.element.ts
index c8aa7f5056..fd92e4c79c 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-section-picker/templating-section-picker-modal.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-section-picker/templating-section-picker-modal.element.ts
@@ -1,143 +1,186 @@
import { getAddSectionSnippet, getRenderBodySnippet, getRenderSectionSnippet } from '../../utils/index.js';
+import { TemplatingSectionType } from '../../types.js';
import type {
UmbTemplatingSectionPickerModalData,
UmbTemplatingSectionPickerModalValue,
} from './templating-section-picker-modal.token.js';
-import type { UmbInsertSectionCheckboxElement } from './templating-section-picker-input.element.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
-import { css, html, customElement, queryAll, state } from '@umbraco-cms/backoffice/external/lit';
+import { css, html, customElement, state, query } from '@umbraco-cms/backoffice/external/lit';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
-import './templating-section-picker-input.element.js';
+import type { UUIBooleanInputElement, UUIInputElement } from '@umbraco-cms/backoffice/external/uui';
@customElement('umb-templating-section-picker-modal')
export class UmbTemplatingSectionPickerModalElement extends UmbModalBaseElement<
UmbTemplatingSectionPickerModalData,
UmbTemplatingSectionPickerModalValue
> {
- @queryAll('umb-insert-section-checkbox')
- checkboxes!: NodeListOf;
+ @query('#render-named-section-name')
+ private _renderNamedSectionNameInput?: UUIInputElement;
+
+ @query('#define-named-section-name')
+ private _defineNamedSectionNameInput?: UUIInputElement;
+
+ @query('#render-named-section-is-mandatory')
+ private _renderNamedSectionIsMandatoryCheckbox?: UUIBooleanInputElement;
@state()
- selectedCheckbox?: UmbInsertSectionCheckboxElement | null = null;
-
- @state()
- snippet = '';
-
- #chooseSection(event: Event) {
- const target = event.target as UmbInsertSectionCheckboxElement;
- const checkboxes = Array.from(this.checkboxes);
- if (checkboxes.every((checkbox) => checkbox.checked === false)) {
- this.selectedCheckbox = null;
- return;
- }
- if (target.checked) {
- this.selectedCheckbox = target;
- this.snippet = this.selectedCheckbox.snippet ?? '';
- checkboxes.forEach((checkbox) => {
- if (checkbox !== target) {
- checkbox.checked = false;
- }
- });
- }
- }
-
- firstUpdated() {
- this.selectedCheckbox = this.checkboxes[0];
- }
-
- snippetMethods = [getRenderBodySnippet, getRenderSectionSnippet, getAddSectionSnippet];
+ private _pickedSection: TemplatingSectionType = TemplatingSectionType.renderChildTemplate;
#close() {
this.modalContext?.reject();
}
#submit() {
- const value = this.selectedCheckbox?.snippet;
- if (this.selectedCheckbox?.validate()) {
- this.value = { value: value ?? '' };
- this.modalContext?.submit();
+ switch (this._pickedSection) {
+ case TemplatingSectionType.renderChildTemplate:
+ this.value = { value: getRenderBodySnippet() };
+ break;
+ case TemplatingSectionType.renderANamedSection:
+ this.value = {
+ value: getRenderSectionSnippet(
+ this._renderNamedSectionNameInput?.value as string,
+ this._renderNamedSectionIsMandatoryCheckbox?.checked ?? false,
+ ),
+ };
+ break;
+ case TemplatingSectionType.defineANamedSection:
+ this.value = { value: getAddSectionSnippet(this._defineNamedSectionNameInput?.value as string) };
+ break;
}
+ this.modalContext?.submit();
}
render() {
return html`
-
-
-
-
-
- Renders the contents of a child template, by inserting a @RenderBody() placeholder.
-
-
-
+
+
+ ${this.#renderRenderChildTemplate()} ${this.#renderRenderANamedSection()}
+ ${this.#renderDefineANamedSection()}
+
+
-
-
-
- Renders a named area of a child template, by inserting a
- @RenderSection(name) placeholder. This renders an area of a child template which is
- wrapped in a corresponding @section [name]{ ... } definition.
-
-
-
-
-
-
-
- Renders a named area of a child template, by inserting a
- @RenderSection(name) placeholder. This renders an area of a child template which is
- wrapped in a corresponding @section [name]{ ... } definition.
-
-
-
-
-
- Close
- Submit
+
+
`;
}
+ #renderRenderChildTemplate() {
+ return html` (this._pickedSection = TemplatingSectionType.renderChildTemplate)}
+ look="placeholder">
+ ${this._pickedSection === TemplatingSectionType.renderChildTemplate
+ ? html``
+ : ''}
+ Render Child Template
+
+
+ Renders the contents of a child template, by inserting a @RenderBody() placeholder.
+
+
+ `;
+ }
+
+ #renderRenderANamedSection() {
+ return html` (this._pickedSection = TemplatingSectionType.renderANamedSection)}
+ look="placeholder">
+ ${this._pickedSection === TemplatingSectionType.renderANamedSection
+ ? html``
+ : ''}
+ Render a named section
+
+
+ Renders a named area of a child template, by inserting a
+ @RenderSection(name) placeholder. This renders an area of a child template which is wrapped in a
+ corresponding @section [name]{ ... } definition.
+
+
+ ${this._pickedSection === TemplatingSectionType.renderANamedSection
+ ? html`
+
+ Section Name
+
+
+
+
+
+ If mandatory, the child template must contain a @section definition, otherwise an error is
+ shown.
+
+
+
`
+ : ''}
+ `;
+ }
+
+ #renderDefineANamedSection() {
+ return html` (this._pickedSection = TemplatingSectionType.defineANamedSection)}
+ look="placeholder">
+ ${this._pickedSection === TemplatingSectionType.defineANamedSection
+ ? html``
+ : ''}
+ Define a named section
+
+
+ Defines a part of your template as a named section by wrapping it in @section { ... }. This can
+ be rendered in a specific area of the parent of this template, by using @RenderSection.
+
+
+ ${this._pickedSection === TemplatingSectionType.defineANamedSection
+ ? html`
+
+ Section Name
+
+
+
`
+ : ''}
+ `;
+ }
+
static styles = [
UmbTextStyles,
css`
- :host {
- display: block;
- color: var(--uui-color-text);
- --umb-header-layout-height: 70px;
- }
-
- #main {
- box-sizing: border-box;
- height: calc(
- 100dvh - var(--umb-header-layout-height) - var(--umb-footer-layout-height) - 2 * var(--uui-size-layout-1)
- );
- }
-
- #main umb-insert-section-checkbox:not(:last-of-type) {
- margin-bottom: var(--uui-size-space-5);
- }
code {
background-color: var(--uui-color-surface-alt);
border: 1px solid var(--uui-color-border);
border-radius: var(--uui-border-radius);
}
+
+ #main {
+ display: grid;
+ grid-gap: var(--uui-size-space-5);
+ }
+
+ .section {
+ display: grid;
+ }
+
+ uui-button {
+ text-align: left;
+ }
+
+ uui-button p {
+ margin-top: 0;
+ }
+
+ uui-input,
+ small {
+ margin-block: var(--uui-size-space-2) var(--uui-size-space-6);
+ }
`,
];
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace-editor.element.ts
index a551b3c7d1..5e88ed098d 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace-editor.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace-editor.element.ts
@@ -109,6 +109,7 @@ export class UmbTemplateWorkspaceEditorElement extends UmbLitElement {
#openInsertSectionModal() {
const sectionModal = this._modalContext?.open(UMB_TEMPLATING_SECTION_PICKER_MODAL);
+
sectionModal?.onSubmit().then((insertSectionModalValue) => {
if (insertSectionModalValue?.value) {
this._codeEditor?.insert(insertSectionModalValue.value);
diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/types.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/types.ts
index 01a83f31b0..46069918b5 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/templating/types.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/templating/types.ts
@@ -1,4 +1,11 @@
export enum CodeSnippetType {
partialView = 'partialView',
dictionaryItem = 'dictionaryItem',
+ pageField = 'pageField',
+}
+
+export enum TemplatingSectionType {
+ renderChildTemplate = 'RenderChildTemplate',
+ renderANamedSection = 'RenderANamedSection',
+ defineANamedSection = 'DefineANamedSection',
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/utils/index.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/utils/index.ts
index 57c84ea4bf..43446d5e20 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/templating/utils/index.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/templating/utils/index.ts
@@ -45,7 +45,7 @@ export const getUmbracoFieldSnippet = (field: string, defaultValue: string | nul
const value = `${field !== null ? `@Model.Value("${field}"` : ''}${
fallback !== null ? `, fallback: ${fallback}` : ''
- }${defaultValue !== null ? `, defaultValue: new HtmlString("${defaultValue}")` : ''}${field ? ')' : ''}`;
+ }${defaultValue !== null ? `, defaultValue: new HtmlString("${defaultValue}")` : ''}${field ? ')' : ')'}`;
return value;
};