Proof-of-concept: independent menu section providers

- Replace god-class resolvers with a service that populates the menus from lists of injectable providers
- Static menu sections are resolved at the root route ~ `resolveStatic`
- Route-dependent menu sections can be declared in the same structure, but are resolved on-demand ~ `resolveRoute`
- More and more easily customizable
  - Parts can be moved between menus, removed, replaced or extended individually
  - The dependencies of each provider are independent of each other
  - Order of providers determines the order of each menu → single source of truth for the order
This commit is contained in:
Yury Bondarenko
2023-12-28 13:46:39 +01:00
parent 404ccd9b0e
commit 0291942613
60 changed files with 2281 additions and 227 deletions

View File

@@ -1,15 +1,82 @@
import { MenuItemModel } from './menu-item/models/menu-item.model';
import { MenuItemType } from './menu-item-type.model';
import { AltmetricMenuItemModel } from './menu-item/models/altmetric.model';
import { ExternalLinkMenuItemModel } from './menu-item/models/external-link.model';
import { LinkMenuItemModel } from './menu-item/models/link.model';
import { OnClickMenuItemModel } from './menu-item/models/onclick.model';
import { SearchMenuItemModel } from './menu-item/models/search.model';
import { TextMenuItemModel } from './menu-item/models/text.model';
/**
* Represents the state of a single menu section in the store
*/
export class MenuSection {
id: string;
parentID?: string;
visible: boolean;
active: boolean;
model: MenuItemModel;
index?: number;
icon?: string;
shouldPersistOnRouteChange? = false;
export type MenuItemModels =
LinkMenuItemModel
| AltmetricMenuItemModel
| ExternalLinkMenuItemModel
| OnClickMenuItemModel
| SearchMenuItemModel
| TextMenuItemModel;
function itemModelFactory(type: MenuItemType): MenuItemModels {
switch (type) {
case MenuItemType.TEXT:
return new TextMenuItemModel();
case MenuItemType.LINK:
return new LinkMenuItemModel();
case MenuItemType.ALTMETRIC:
return new AltmetricMenuItemModel();
case MenuItemType.SEARCH:
return new SearchMenuItemModel();
case MenuItemType.ONCLICK:
return new OnClickMenuItemModel();
case MenuItemType.EXTERNAL:
return new ExternalLinkMenuItemModel();
default: {
throw new Error(`No such menu item type: ${type}`);
}
}
}
export interface MenuSection {
/**
* The identifier for this section
*/
id: string;
/**
* Whether this section should be visible.
*/
visible: boolean;
/**
*
*/
model: MenuItemModels;
/**
* The identifier of this section's parent section (optional).
*/
parentID?: string;
/**
* The index of this section in its menu.
*/
index?: number;
/**
* Whether this section is currently active.
* Newly created sections are inactive until toggled.
*/
active?: boolean;
/**
* Whether this section is independent of the route (default: true).
* This value should be set explicitly for route-dependent sections.
*/
shouldPersistOnRouteChange?: boolean;
/**
* An optional icon for this section.
* Must correspond to a FontAwesome icon class save for the `.fa-` prefix.
* Note that not all menus may render icons.
*/
icon?: string;
}