Skip to content

Commit 2760e04

Browse files
authored
Merge pull request #7494 from bszyman/menus
Menus
2 parents 352d4ff + 9788cf3 commit 2760e04

File tree

2 files changed

+85
-467
lines changed
  • 16/umbraco-cms/customizing/extending-overview/extension-types
  • 17/umbraco-cms/customizing/extending-overview/extension-types

2 files changed

+85
-467
lines changed
Lines changed: 43 additions & 232 deletions
Original file line numberDiff line numberDiff line change
@@ -1,259 +1,70 @@
1-
# Menu
1+
---
2+
description: >-
3+
Create menus that appear throughout the backoffice, including in sidebars and button flyouts.
4+
---
25

3-
<figure><img src="../../../.gitbook/assets/menu.png" alt="" width="250"><figcaption><p>Menu</p></figcaption></figure>
6+
# Menus
47

5-
## Creating a custom menu
8+
Menu extensions contain one or more [menu item extensions](menu-item.md) and can appear throughout the backoffice, such as in sidebars and flyouts.
69

7-
In this section, you can learn how to register and create a custom Menu for the Umbraco backoffice.
10+
<figure><img src="../../../.gitbook/assets/menu.png" alt="" width="250"><figcaption><p>Menu</p></figcaption></figure>
811

9-
### Manifest
12+
## Creating a custom menu
1013

11-
The manifest file can be created using either JSON or TypeScript. Both methods are shown below.
14+
Menu extensions can be created using either JSON or TypeScript. Both approaches are shown below.
1215

1316
{% tabs %}
14-
1517
{% tab title="JSON" %}
16-
17-
We can create the manifest using JSON in the `umbraco-package.json`.
18-
18+
{% code title="umbraco-package.json" %}
1919
```json
2020
{
21-
"type": "menu",
22-
"alias": "My.Menu",
23-
"name": "My Menu"
21+
"$schema": "../../umbraco-package-schema.json",
22+
"name": "My Package",
23+
"version": "0.1.0",
24+
"extensions": [
25+
{
26+
"type": "menu",
27+
"alias": "My.Menu",
28+
"name": "My Menu"
29+
}
30+
]
2431
}
2532
```
33+
{% endcode %}
2634
{% endtab %}
27-
2835
{% tab title="TypeScript" %}
36+
Extension authors define the menu manifest, then register it dynamically/during runtime using a [Backoffice Entry Point](../../extending-overview/extension-types/backoffice-entry-point.md) extension.
2937

30-
The manifest can also be written in TypeScript.
31-
32-
For this TypeScript example we used a [Backoffice Entry Point](../../extending-overview/extension-types/backoffice-entry-point.md) extension to register the manifests.
33-
38+
{% code title="my-menu/manifests.ts" %}
3439
```typescript
3540
import type { ManifestMenu } from '@umbraco-cms/backoffice/menu';
3641

37-
const menuManifest: Array<ManifestMenu> = [
38-
{
39-
type: 'menu',
40-
alias: 'My.Menu',
41-
name: 'My Menu'
42-
}
43-
];
44-
```
45-
46-
{% endtab %}
47-
48-
{% endtabs %}
49-
50-
# Menu Item
51-
52-
<figure><img src="../../../.gitbook/assets/menu-item.png" alt="" width="250"><figcaption><p>Menu Item</p></figcaption></figure>
53-
54-
Menu items are the items that appear in the menu.
55-
56-
## Creating a custom menu items
57-
58-
In this section, you can learn how to add custom Menu Items to your Umbraco backoffice Menu.
59-
60-
### Manifest
61-
62-
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.
63-
64-
The code snippets below show how to declare a new menu item using JSON or TypeScript.
65-
66-
{% tabs %}
67-
68-
{% tab title="JSON" %}
69-
70-
We can create the manifest using JSON in the `umbraco-package.json`.
71-
72-
```json
73-
{
74-
"type": "menuItem",
75-
"alias": "My.MenuItem",
76-
"name": "My Menu Item",
77-
"element": "./menu-items.ts",
78-
"meta": {
79-
"label": "My Menu Item",
80-
"menus": ["My.Menu"]
81-
}
82-
}
83-
```
84-
85-
{% endtab %}
86-
87-
{% tab title="TypeScript" %}
88-
89-
The manifest can also be written in TypeScript.
90-
91-
For this TypeScript example we used a [Backoffice Entry Point](../../extending-overview/extension-types/backoffice-entry-point.md) extension to register the manifests.
92-
93-
{% code title="manifest.ts" overflow="wrap" lineNumbers="true" %}
94-
```typescript
95-
const menuItemManifest: Array<ManifestMenuItem> = [
96-
{
97-
type: 'menuItem',
98-
alias: 'My.MenuItem',
99-
name: 'My Menu Item',
100-
meta: {
101-
label: 'My Menu Item',
102-
menus: ["My.Menu"]
103-
},
104-
element: () => import('./menu-items.ts')
105-
}
106-
];
42+
export const menuManifest: ManifestMenu = {
43+
type: 'menu',
44+
alias: 'My.Menu',
45+
name: 'My Menu'
46+
};
10747
```
10848
{% endcode %}
10949

110-
111-
{% endtab %}
112-
113-
{% endtabs %}
114-
115-
### The UI Element
116-
117-
#### Rendering menu items with Umbraco's UI menu item component
118-
119-
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.
120-
121-
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}`.
122-
123-
**Example:**
124-
125-
```tsx
126-
<uui-menu-item label="Menu Item 1" has-children>
127-
<uui-menu-item label="Nested Menu Item 1"></uui-menu-item>
128-
<uui-menu-item label="Nested Menu Item 2"></uui-menu-item>
129-
</uui-menu-item>
130-
```
131-
132-
#### Custom menu item element example
133-
134-
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.
135-
136-
{% code title="menu-items.ts" overflow="wrap" lineNumbers="true" %}
50+
{% code title="entrypoints/entrypoints.ts" %}
13751
```typescript
138-
import type { UmbMenuItemElement } from '@umbraco-cms/backoffice/menu';
139-
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
140-
import { html, TemplateResult, customElement, state } from '@umbraco-cms/backoffice/external/lit';
141-
import { MyMenuItemResponseModel, MyMenuResource } from '../../../api';
142-
143-
const elementName = 'my-menu-item';
144-
145-
@customElement(elementName)
146-
class MyMenuItems extends UmbLitElement implements UmbMenuItemElement {
147-
@state()
148-
private _items: MyMenuItemResponseModel[] = []; // Store fetched items
149-
150-
@state()
151-
private _loading: boolean = true; // Track loading state
152-
153-
@state()
154-
private _error: string | null = null; // Track any errors
155-
156-
override firstUpdated() {
157-
this.fetchInitialItems(); // Start fetching on component load
158-
}
159-
160-
// Fetch initial items
161-
async fetchInitialItems() {
162-
try {
163-
this._loading = true;
164-
this._items = ((await MyMenuResource.getMenuApiV1()).items); // Fetch root-level items
165-
} catch (e) {
166-
this._error = 'Error fetching items';
167-
} finally {
168-
this._loading = false;
169-
}
170-
}
171-
172-
// Render items
173-
renderItems(items: MyMenuItemResponseModel[]): TemplateResult {
174-
return html`
175-
${items.map(element => html`
176-
<uui-menu-item label="${element.name}" ?has-children=${element.hasChildren}>
177-
${element.type === 1
178-
? html`<uui-icon slot="icon" name="icon-folder"></uui-icon>`
179-
: html`<uui-icon slot="icon" name="icon-autofill"></uui-icon>`}
180-
<!-- recursively render children -->
181-
${element.hasChildren ? this.renderItems(element.children) : ''}
182-
</uui-menu-item>
183-
`)}
184-
`;
185-
}
186-
187-
// Main render function
188-
override render() {
189-
if (this._loading) {
190-
return html`<uui-loader></uui-loader>`;
191-
}
192-
193-
if (this._error) {
194-
return html`<uui-menu-item active disabled label="Could not load form tree!">
195-
</uui-menu-item>`;
196-
}
197-
198-
// Render items if loading is done and no error occurred
199-
return this.renderItems(this._items);
200-
}
201-
}
202-
203-
export { MyMenuItems as element };
52+
import type {
53+
UmbEntryPointOnInit,
54+
} from "@umbraco-cms/backoffice/extension-api";
55+
import { umbExtensionsRegistry } from "@umbraco-cms/backoffice/extension-registry";
56+
import { menuManifest } from "./../my-menu/manifests.ts";
20457

205-
declare global {
206-
interface HTMLElementTagNameMap {
207-
[elementName]: MyMenuItems;
208-
}
209-
}
58+
export const onInit: UmbEntryPointOnInit = (_host, _extensionRegistry) => {
59+
console.log("Hello from my extension 🎉");
21060

61+
umbExtensionsRegistry.register(menuManifest);
62+
};
21163
```
21264
{% endcode %}
65+
{% endtab %}
66+
{% endtabs %}
21367

214-
215-
## Tree Menu Item
216-
217-
### Manifest
218-
219-
```json
220-
// it will be something like this
221-
{
222-
"type": "menuItem",
223-
"kind": "tree",
224-
"alias": "My.TreeMenuItem",
225-
"name": "My Tree Menu Item",
226-
"meta": {
227-
"label": "My Tree Menu Item",
228-
"menus": ["My.Menu"]
229-
}
230-
}
231-
```
232-
233-
#### Default Element
234-
235-
The default element supports rendering a subtree of menu items.
236-
237-
```typescript
238-
class UmbMenuItemTreeDefaultElement {}
239-
```
240-
241-
### Adding menu items to an existing menu
242-
243-
The backoffice comes with a couple of menus.
244-
245-
* Content, Media, Settings, Templating, Dictionary, etc.
246-
247-
To add a menu item to an existing menu, you can use the `meta.menus` property.
248-
249-
```typescript
250-
{
251-
"type": "menuItem",
252-
"alias": "My.MenuItem",
253-
"name": "My Menu Item",
254-
"meta": {
255-
"label": "My Menu Item",
256-
"menus": ["Umb.Menu.Content"]
257-
}
258-
}
259-
```
68+
## See Also
69+
* [Section Sidebar](sections/section-sidebar.md) for information on creating menus for navigation within section extensions.
70+
* [Menu Item](menu-item.md) for information on creating menu items.

0 commit comments

Comments
 (0)