-
Notifications
You must be signed in to change notification settings - Fork 811
Menus #7494
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
bszyman
wants to merge
6
commits into
umbraco:main
Choose a base branch
from
bszyman:menus
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Menus #7494
Changes from 4 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
08d3e10
Update menus article
bszyman 43d56b0
Revamp "Menus" documentation: updated examples to align with new JSONβ¦
bszyman d761635
Merge branch 'umbraco:main' into menus
bszyman 79532ab
Streamline "Menus" documentation: simplified descriptions, cross-linkβ¦
bszyman 906f1d2
Update 16/umbraco-cms/customizing/extending-overview/extension-types/β¦
eshanrnh 3536221
Update 16/umbraco-cms/customizing/extending-overview/extension-types/β¦
eshanrnh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
277 changes: 42 additions & 235 deletions
277
16/umbraco-cms/customizing/extending-overview/extension-types/menu.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,263 +1,70 @@ | ||
| # Menu | ||
| --- | ||
| description: >- | ||
| Create menus that appear throughout the backoffice, including sidebars and button flyouts. | ||
| --- | ||
|
|
||
| {% hint style="warning" %} | ||
| 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 %} | ||
| # Menus | ||
|
|
||
| Menu extensions contain one or more [menu item extensions](menu-item.md) and can appear throughout the backofficeβsuch as in sidebars and flyouts. | ||
eshanrnh marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| <figure><img src="../../../.gitbook/assets/menu.png" alt="" width="250"><figcaption><p>Menu</p></figcaption></figure> | ||
|
|
||
| ## 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. | ||
| Menu extensions can be created using either JSON or TypeScript. Both approaches are shown below. | ||
|
|
||
| {% tabs %} | ||
|
|
||
| {% tab title="JSON" %} | ||
|
|
||
| We can create the manifest using JSON in the `umbraco-package.json`. | ||
|
|
||
| {% code title="umbraco-package.json" %} | ||
| ```json | ||
| { | ||
| "type": "menu", | ||
| "alias": "My.Menu", | ||
| "name": "My Menu" | ||
| "$schema": "../../umbraco-package-schema.json", | ||
| "name": "My Package", | ||
| "version": "0.1.0", | ||
| "extensions": [ | ||
| { | ||
| "type": "menu", | ||
| "alias": "My.Menu", | ||
| "name": "My Menu" | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
|
|
||
| {% tab title="TypeScript" %} | ||
| 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. | ||
|
|
||
| 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.md) extension to register the manifests. | ||
|
|
||
| {% code title="my-menu/manifests.ts" %} | ||
| ```typescript | ||
| import type { ManifestMenu } from '@umbraco-cms/backoffice/menu'; | ||
|
|
||
| const menuManifest: Array<ManifestMenu> = [ | ||
| { | ||
| type: 'menu', | ||
| alias: 'My.Menu', | ||
| name: 'My Menu' | ||
| } | ||
| ]; | ||
| ``` | ||
|
|
||
| {% endtab %} | ||
|
|
||
| {% endtabs %} | ||
|
|
||
| # Menu Item | ||
|
|
||
| <figure><img src="../../../.gitbook/assets/menu-item.png" alt="" width="250"><figcaption><p>Menu Item</p></figcaption></figure> | ||
|
|
||
| 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"] | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| {% 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.md) extension to register the manifests. | ||
|
|
||
| {% code title="manifest.ts" overflow="wrap" lineNumbers="true" %} | ||
| ```typescript | ||
| const menuItemManifest: Array<ManifestMenuItem> = [ | ||
| { | ||
| type: 'menuItem', | ||
| alias: 'My.MenuItem', | ||
| name: 'My Menu Item', | ||
| meta: { | ||
| label: 'My Menu Item', | ||
| menus: ["My.Menu"] | ||
| }, | ||
| element: () => import('./menu-items.ts') | ||
| } | ||
| ]; | ||
| export const menuManifest: ManifestMenu = { | ||
| type: 'menu', | ||
| alias: 'My.Menu', | ||
| name: 'My Menu' | ||
| }; | ||
| ``` | ||
| {% 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 | ||
| <uui-menu-item label="Menu Item 1" has-children> | ||
| <uui-menu-item label="Nested Menu Item 1"></uui-menu-item> | ||
| <uui-menu-item label="Nested Menu Item 2"></uui-menu-item> | ||
| </uui-menu-item> | ||
| ``` | ||
|
|
||
| #### 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" %} | ||
| {% code title="entrypoints/entrypoints.ts" %} | ||
| ```typescript | ||
| import type { UmbMenuItemElement } from '@umbraco-cms/backoffice/menu'; | ||
| import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; | ||
| import { html, TemplateResult, customElement, state } from '@umbraco-cms/backoffice/external/lit'; | ||
| 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 | ||
| import type { | ||
| UmbEntryPointOnInit, | ||
| } from "@umbraco-cms/backoffice/extension-api"; | ||
| import { umbExtensionsRegistry } from "@umbraco-cms/backoffice/extension-registry"; | ||
| import { menuManifest } from "./../my-menu/manifests.ts"; | ||
|
|
||
| override firstUpdated() { | ||
| 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` | ||
| <uui-menu-item label="${element.name}" ?has-children=${element.hasChildren}> | ||
| ${element.type === 1 | ||
| ? html`<uui-icon slot="icon" name="icon-folder"></uui-icon>` | ||
| : html`<uui-icon slot="icon" name="icon-autofill"></uui-icon>`} | ||
| <!-- recursively render children --> | ||
| ${element.hasChildren ? this.renderItems(element.children) : ''} | ||
| </uui-menu-item> | ||
| `)} | ||
| `; | ||
| } | ||
|
|
||
| // Main render function | ||
| override render() { | ||
| if (this._loading) { | ||
| return html`<uui-loader></uui-loader>`; | ||
| } | ||
|
|
||
| if (this._error) { | ||
| return html`<uui-menu-item active disabled label="Could not load form tree!"> | ||
| </uui-menu-item>`; | ||
| } | ||
|
|
||
| // Render items if loading is done and no error occurred | ||
| return this.renderItems(this._items); | ||
| } | ||
| } | ||
|
|
||
| export { MyMenuItems as element }; | ||
|
|
||
| declare global { | ||
| interface HTMLElementTagNameMap { | ||
| [elementName]: MyMenuItems; | ||
| } | ||
| } | ||
| export const onInit: UmbEntryPointOnInit = (_host, _extensionRegistry) => { | ||
| console.log("Hello from my extension π"); | ||
|
|
||
| umbExtensionsRegistry.register(menuManifest); | ||
| }; | ||
| ``` | ||
| {% endcode %} | ||
| {% endtab %} | ||
| {% endtabs %} | ||
|
|
||
|
|
||
| ## Tree Menu Item | ||
|
|
||
| ### Manifest | ||
|
|
||
| ```json | ||
| // it will be something like this | ||
| { | ||
| "type": "menuItem", | ||
| "kind": "tree", | ||
| "alias": "My.TreeMenuItem", | ||
| "name": "My Tree Menu Item", | ||
| "meta": { | ||
| "label": "My Tree Menu Item", | ||
| "menus": ["My.Menu"] | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| #### Default Element | ||
|
|
||
| The default element supports rendering a subtree of menu items. | ||
|
|
||
| ```typescript | ||
| class UmbMenuItemTreeDefaultElement {} | ||
| ``` | ||
|
|
||
| ### Adding menu items to an existing menu | ||
|
|
||
| The backoffice comes with a couple of menus. | ||
|
|
||
| * Content, Media, Settings, Templating, Dictionary, etc. | ||
|
|
||
| To add a menu item to an existing menu, you can use the `meta.menus` property. | ||
|
|
||
| ```typescript | ||
| { | ||
| "type": "menuItem", | ||
| "alias": "My.MenuItem", | ||
| "name": "My Menu Item", | ||
| "meta": { | ||
| "label": "My Menu Item", | ||
| "menus": ["Umb.Menu.Content"] | ||
| } | ||
| } | ||
| ``` | ||
| ## See Also | ||
| * [Section Sidebar](sections/section-sidebar.md) for information on creating menus for navigation within section extensions. | ||
| * [Menu Item](menu-item.md) for information on creating menu items. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.