import { IconDefinition } from "@fortawesome/fontawesome-svg-core"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import "bootstrap/dist/css/bootstrap.min.css"; import * as React from "react"; import { Nav, Navbar, NavDropdown } from "react-bootstrap"; export interface ToolbarProps { toolbar: IToolbar; generateData(): D; position?: "top" | "bottom"; sticky?: boolean; bg?: "light" | "dark"; brand?: ILink; } /** * Definition of a Toolbar. * * @export * @interface IToolbar * @template D */ export interface IToolbar { /** * Items of the toolbar. * * @type {(Array | IMenu | ILink>)} * @memberof IToolbar */ items: Array | IMenu | ILink>; } export interface IAction { type: "action"; /** * Action which should be performed if the element * has been clicked. * * @param {D} data * @memberof IAction */ onClick(data: D): void; /** * Label of the Menu. * * @type {string} * @memberof IAction */ label: string; /** * Additional Icon. */ icon?: IconDefinition; } /** * A Menu of the Toolbar * * @export * @interface IMenu * @template D */ export interface IMenu { type: "menu"; /** * The Menu ID. * * @type {string} * @memberof IMenu */ id: string; /** * Label of the Menu * * @type {string} * @memberof IMenu */ label: string; /** * Items of the Menu. * * @type {(Array | ILink | IDivider>)} * @memberof IMenu */ items: Array | IMenu | ILink | IDivider>; } /** * A Classical Link. * * @export * @interface ILink */ export interface ILink { /** * Type of the Element. * * @type {'link'} * @memberof ILink */ type: "link"; /** * Label * * @type {string} * @memberof ILink */ label: string; /** * Referene, where the client should be navigated on click * * @type {string} * @memberof ILink */ ref: string; /** * Additional Icon. */ icon?: IconDefinition | string; } /** * A Divider in a Menu. * * @export * @interface IDivider */ export interface IDivider { /** * Type Element * * @type {'divider'} * @memberof IDivider */ type: "divider"; } export type ToolbarState = ToolbarProps; class Toolbar extends React.Component, ToolbarState> { private _currentId = 0; constructor(props) { super(props); this.state = Object.assign( { bg: "dark", position: "top", sticky: true }, this.props ); } _generateId() { const id = this._currentId; this._currentId += 1; return id; } _renderMenuEntry(entry: IAction | IMenu | ILink) { const _this = this; switch (entry.type) { case "action": if (entry.icon) { return ( { entry.onClick(this.state.generateData()); }} > {entry.label} ); } return ( { entry.onClick(this.state.generateData()); }} > {entry.label} ); case "menu": return this._renderDropdown(entry); case "link": if (entry.icon && typeof entry.icon === "object") { return ( {entry.label} ); } else if (entry.icon && typeof entry.icon === "string") { return ( ); } return ( {entry.label} ); } } _renderDropdown(item: IMenu) { // Issue: Drop-Down wont display the Dropdowns after opening a modal: // Issue: https://github.com/react-bootstrap/react-bootstrap/issues/5409 // Dirty Fix: onClick={e => e.stopPropagation() in the "NavDropdown" return ( e.stopPropagation()} > {/* Iterate over the deteced Modules. */} {item.items.map((entry) => { switch (entry.type) { case "action": if (entry.icon) { return ( { entry.onClick(this.state.generateData()); }} > {entry.label} ); } return ( { entry.onClick(this.state.generateData()); }} > {entry.label} ); case "divider": return ; case "link": if (entry.icon && typeof entry.icon === "object") { return ( {entry.label} ); } return ( {entry.label} ); case "menu": return this._renderDropdown(entry); } })} ); } _renderBrand() { switch (typeof this.state.brand.icon) { case "string": return ( ); case "object": return ; } } /** * Main Function to Render the Layout */ render() { this._currentId = 0; return ( <> {this.state.sticky ? ( // Render a collapsable Navbar containing the defined Menu structure. {this.state.brand ? ( <> {this._renderBrand()} {this.state.brand.label} ) : ( )} ) : ( {this.state.brand ? ( <> {this._renderBrand()} {this.state.brand.label} ) : ( )} )} ); } } export default Toolbar;