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; } /** * A Divider in a Menu. * * @export * @interface IDivider */ export interface IDivider { /** * Type Element * * @type {'divider'} * @memberof IDivider */ type: 'divider' } export interface ToolbarState extends 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){ return ( {entry.label} ); } 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){ return ( {entry.label} ); } return ( {entry.label} ); case 'menu': return this._renderDropdown(entry); } })} ); } /** * 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.state.brand.icon ? : ''} {this.state.brand.label} : } : {this.state.brand ? <> {this.state.brand.icon ? : ''} {this.state.brand.label} : } } ); } } export default Toolbar;