diff --git a/14/umbraco-cms/customizing/extending-overview/extension-types/menu.md b/14/umbraco-cms/customizing/extending-overview/extension-types/menu.md index 5fb8fa401f6..632fbdb6157 100644 --- a/14/umbraco-cms/customizing/extending-overview/extension-types/menu.md +++ b/14/umbraco-cms/customizing/extending-overview/extension-types/menu.md @@ -4,27 +4,81 @@ This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. {% endhint %} -## Menu -

Menu

-```typescript +## Creating a custom menu + +In this section, you can learn how to register and create a custom Menu for the Umbraco backoffice. + +### Manifest + +The manifest file can be created using either JSON or TypeScript. Both methods are shown below. + +{% tabs %} + +{% tab title="JSON" %} + +We can create the manifest using JSON in the `umbraco-package.json`. + +```json { "type": "menu", "alias": "My.Menu", "name": "My Menu" } ``` +{% endtab %} -### Menu Item +{% tab title="TypeScript" %} -

Menu Item

+The manifest can also be written in TypeScript. + +For this TypeScript example we used a [Backoffice Entry Point](../../extending-overview/extension-types/backoffice-entry-point) extension to register the manifests ```typescript +import { ManifestMenu } from "@umbraco-cms/backoffice/extension-registry"; + +const menuManifest: Array = [ + { + type: 'menu', + alias: 'My.Menu', + name: 'My Menu' + } +]; +``` + +{% endtab %} + +{% endtabs %} + +# Menu Item + +

Menu Item

+ +Menu items are the items that appear in the menu. + +## Creating a custom menu items + +In this section, you can learn how to add custom Menu Items to your Umbraco backoffice Menu. + +### Manifest + +To add custom menu items, you can define a single MenuItem manifest and link an element to it. In this element, you can fetch the data and render as many menu items as you want based on that data. + +The code snippets below show how to declare a new menu item using JSON or TypeScript. + +{% tabs %} + +{% tab title="JSON" %} + +We can create the manifest using JSON in the `umbraco-package.json`. + +```json { "type": "menuItem", "alias": "My.MenuItem", "name": "My Menu Item", + "element": "./menu-items.ts", "meta": { "label": "My Menu Item", "menus": ["My.Menu"] @@ -32,9 +86,139 @@ This page is a work in progress and may undergo further revisions, updates, or a } ``` -### **Tree Menu Item** +{% endtab %} + +{% tab title="TypeScript" %} + +The manifest can also be written in TypeScript. + +For this TypeScript example we used a [Backoffice Entry Point](../../extending-overview/extension-types/backoffice-entry-point) extension to register the manifests + +{% code title="manifest.ts" %} +```typescript +const menuItemManifest: Array = [ + { + type: 'menuItem', + alias: 'My.MenuItem', + name: 'My Menu Item', + meta: { + label: 'My Menu Item', + menus: ["My.Menu"] + }, + element: () => import('./menu-items.ts') + } +]; +``` +{% endcode %} + + +{% endtab %} + +{% endtabs %} + +### The UI Element + +#### Rendering menu items with Umbraco's UI menu item component + +To render your menu items in Umbraco, you can use the [Umbraco UI Menu Item component](https://uui.umbraco.com/?path=/docs/uui-menu-item--docs). This component allows you to create nested menu structures with a few lines of code. + +By default, you can set the `has-children` attribute to display the caret icon indicating nested items. It will look like this: `?has-children=${bool}`. + +**Example:** + +```tsx + + + + +``` + +#### Custom menu item element example + +You can fetch the data and render the menu items using the Lit element above. By putting the result of the fetch in a `@state()`, we can trigger a re-render of the component when the data is fetched. + +{% code title="menu-items.ts" %} +```typescript +import { UmbMenuItemElement } from '@umbraco-cms/backoffice/extension-registry'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { html, TemplateResult } from 'lit'; +import { customElement, state } from 'lit/decorators.js'; +import { MyMenuItemResponseModel, MyMenuResource } from '../../../api'; + +const elementName = 'my-menu-item'; + +@customElement(elementName) +class MyMenuItems extends UmbLitElement implements UmbMenuItemElement { + @state() + private _items: MyMenuItemResponseModel[] = []; // Store fetched items + @state() + private _loading: boolean = true; // Track loading state + @state() + private _error: string | null = null; // Track any errors + + constructor() { + super(); + this.fetchInitialItems(); // Start fetching on component load + } + + // Fetch initial items + async fetchInitialItems() { + try { + this._loading = true; + this._items = ((await MyMenuResource.getMenuApiV1()).items); // Fetch root-level items + } catch (e) { + this._error = 'Error fetching items'; + } finally { + this._loading = false; + } + } + + // Render items + renderItems(items: MyMenuItemResponseModel[]): TemplateResult { + return html` + ${items.map(element => html` + + ${element.type === 1 + ? html`` + : html``} + + ${element.hasChildren ? this.renderItems(element.children) : ''} + + `)} + `; + } + + // Main render function + render() { + if (this._loading) { + return html``; + } + + if (this._error) { + return html` + `; + } + + // Render items if loading is done and no error occurred + return html`${this.renderItems(this._items)}`; + } +} + +export { MyMenuItems as element }; + +declare global { + interface HTMLElementTagNameMap { + [elementName]: MyMenuItems; + } +} + +``` +{% endcode %} + + +## Tree Menu Item -#### **Manifest** +### Manifest ```typescript // it will be something like this @@ -50,14 +234,14 @@ This page is a work in progress and may undergo further revisions, updates, or a } ``` -#### **Default Element** +#### Default Element ```typescript // get interface interface UmbTreeMenuItemElement {} ``` -### **Adding menu items to an existing menu** +### Adding menu items to an existing menu The backoffice comes with a couple of menus. diff --git a/15/umbraco-cms/customizing/extending-overview/extension-types/menu.md b/15/umbraco-cms/customizing/extending-overview/extension-types/menu.md index 5fb8fa401f6..533af4c5f91 100644 --- a/15/umbraco-cms/customizing/extending-overview/extension-types/menu.md +++ b/15/umbraco-cms/customizing/extending-overview/extension-types/menu.md @@ -4,27 +4,81 @@ This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. {% endhint %} -## Menu -

Menu

-```typescript +## Creating a custom menu + +In this section, you can learn how to register and create a custom Menu for the Umbraco backoffice. + +### Manifest + +The manifest file can be created using either JSON or TypeScript. Both methods are shown below. + +{% tabs %} + +{% tab title="JSON" %} + +We can create the manifest using JSON in the `umbraco-package.json`. + +```json { "type": "menu", "alias": "My.Menu", "name": "My Menu" } ``` +{% endtab %} -### Menu Item +{% tab title="TypeScript" %} -

Menu Item

+The manifest can also be written in TypeScript. + +For this TypeScript example we used a [Backoffice Entry Point](../../extending-overview/extension-types/backoffice-entry-point) extension to register the manifests. ```typescript +import { ManifestMenu } from "@umbraco-cms/backoffice/extension-registry"; + +const menuManifest: Array = [ + { + type: 'menu', + alias: 'My.Menu', + name: 'My Menu' + } +]; +``` + +{% endtab %} + +{% endtabs %} + +# Menu Item + +

Menu Item

+ +Menu items are the items that appear in the menu. + +## Creating a custom menu items + +In this section, you can learn how to add custom Menu Items to your Umbraco backoffice Menu. + +### Manifest + +To add custom menu items, you can define a single MenuItem manifest and link an element to it. In this element, you can fetch the data and render as many menu items as you want based on that data. + +The code snippets below show how to declare a new menu item using JSON or TypeScript. + +{% tabs %} + +{% tab title="JSON" %} + +We can create the manifest using JSON in the `umbraco-package.json`. + +```json { "type": "menuItem", "alias": "My.MenuItem", "name": "My Menu Item", + "element": "./menu-items.ts", "meta": { "label": "My Menu Item", "menus": ["My.Menu"] @@ -32,9 +86,139 @@ This page is a work in progress and may undergo further revisions, updates, or a } ``` -### **Tree Menu Item** +{% endtab %} + +{% tab title="TypeScript" %} + +The manifest can also be written in TypeScript. + +For this TypeScript example we used a [Backoffice Entry Point](../../extending-overview/extension-types/backoffice-entry-point) extension to register the manifests. + +{% code title="manifest.ts" overflow="wrap" lineNumbers="true" %} +```typescript +const menuItemManifest: Array = [ + { + type: 'menuItem', + alias: 'My.MenuItem', + name: 'My Menu Item', + meta: { + label: 'My Menu Item', + menus: ["My.Menu"] + }, + element: () => import('./menu-items.ts') + } +]; +``` +{% endcode %} + + +{% endtab %} + +{% endtabs %} + +### The UI Element + +#### Rendering menu items with Umbraco's UI menu item component + +To render your menu items in Umbraco, you can use the [Umbraco UI Menu Item component](https://uui.umbraco.com/?path=/docs/uui-menu-item--docs). This component allows you to create nested menu structures with a few lines of code. + +By default, you can set the `has-children` attribute to display the caret icon indicating nested items. It will look like this: `?has-children=${bool}`. + +**Example:** + +```tsx + + + + +``` + +#### Custom menu item element example + +You can fetch the data and render the menu items using the Lit element above. By putting the result of the fetch in a `@state()`, we can trigger a re-render of the component when the data is fetched. + +{% code title="menu-items.ts" overflow="wrap" lineNumbers="true" %} +```typescript +import { UmbMenuItemElement } from '@umbraco-cms/backoffice/extension-registry'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { html, TemplateResult } from 'lit'; +import { customElement, state } from 'lit/decorators.js'; +import { MyMenuItemResponseModel, MyMenuResource } from '../../../api'; + +const elementName = 'my-menu-item'; + +@customElement(elementName) +class MyMenuItems extends UmbLitElement implements UmbMenuItemElement { + @state() + private _items: MyMenuItemResponseModel[] = []; // Store fetched items + @state() + private _loading: boolean = true; // Track loading state + @state() + private _error: string | null = null; // Track any errors + + constructor() { + super(); + this.fetchInitialItems(); // Start fetching on component load + } + + // Fetch initial items + async fetchInitialItems() { + try { + this._loading = true; + this._items = ((await MyMenuResource.getMenuApiV1()).items); // Fetch root-level items + } catch (e) { + this._error = 'Error fetching items'; + } finally { + this._loading = false; + } + } + + // Render items + renderItems(items: MyMenuItemResponseModel[]): TemplateResult { + return html` + ${items.map(element => html` + + ${element.type === 1 + ? html`` + : html``} + + ${element.hasChildren ? this.renderItems(element.children) : ''} + + `)} + `; + } + + // Main render function + render() { + if (this._loading) { + return html``; + } + + if (this._error) { + return html` + `; + } + + // Render items if loading is done and no error occurred + return html`${this.renderItems(this._items)}`; + } +} + +export { MyMenuItems as element }; + +declare global { + interface HTMLElementTagNameMap { + [elementName]: MyMenuItems; + } +} + +``` +{% endcode %} + + +## Tree Menu Item -#### **Manifest** +### Manifest ```typescript // it will be something like this @@ -50,14 +234,14 @@ This page is a work in progress and may undergo further revisions, updates, or a } ``` -#### **Default Element** +#### Default Element ```typescript // get interface interface UmbTreeMenuItemElement {} ``` -### **Adding menu items to an existing menu** +### Adding menu items to an existing menu The backoffice comes with a couple of menus.