229 lines
6.0 KiB
TypeScript
229 lines
6.0 KiB
TypeScript
import { assignIn } from 'lodash';
|
|
import * as React from 'react';
|
|
import { Nav, Navbar, NavDropdown } from 'react-bootstrap';
|
|
import { generateId } from '../../../lib/helpers/idMethods';
|
|
|
|
export interface ToolbarProps<D> {
|
|
toolbar: IToolbar<D>;
|
|
generateData(): D;
|
|
position?: 'top' | 'bottom',
|
|
sticky?: boolean;
|
|
bg?: 'light' | 'dark',
|
|
brand?: ILink
|
|
}
|
|
|
|
/**
|
|
* Definition of a Toolbar.
|
|
*
|
|
* @export
|
|
* @interface IToolbar
|
|
* @template D
|
|
*/
|
|
export interface IToolbar<D> {
|
|
/**
|
|
* Items of the toolbar.
|
|
*
|
|
* @type {(Array<IAction<D> | IMenu<D> | ILink>)}
|
|
* @memberof IToolbar
|
|
*/
|
|
items: Array<IAction<D> | IMenu<D> | ILink>
|
|
}
|
|
|
|
export interface IAction<D> {
|
|
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,
|
|
}
|
|
|
|
/**
|
|
* A Menu of the Toolbar
|
|
*
|
|
* @export
|
|
* @interface IMenu
|
|
* @template D
|
|
*/
|
|
export interface IMenu<D> {
|
|
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<IAction<D> | ILink | IDivider>)}
|
|
* @memberof IMenu
|
|
*/
|
|
items: Array<IAction<D> | IMenu<D> | 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;
|
|
}
|
|
|
|
/**
|
|
* A Divider in a Menu.
|
|
*
|
|
* @export
|
|
* @interface IDivider
|
|
*/
|
|
export interface IDivider {
|
|
/**
|
|
* Type Element
|
|
*
|
|
* @type {'divider'}
|
|
* @memberof IDivider
|
|
*/
|
|
type: 'divider'
|
|
}
|
|
|
|
export interface ToolbarState {
|
|
|
|
}
|
|
|
|
class Toolbar<D> extends React.Component<ToolbarProps<D>, ToolbarState> {
|
|
|
|
_renderMenuEntry(item: IAction<D> | IMenu<D> | ILink) {
|
|
|
|
const _this = this;
|
|
|
|
switch (item.type) {
|
|
case 'action':
|
|
return (
|
|
<Nav.Link key={generateId()} onClick={e => {
|
|
item.onClick(this.props.generateData());
|
|
}}>{item.label}</Nav.Link>
|
|
);
|
|
case 'menu':
|
|
return this._renderDropdown(item);
|
|
case 'link':
|
|
return (
|
|
<Nav.Link key={generateId()} href={item.ref}>{item.label}</Nav.Link>
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
_renderDropdown(item: IMenu<D>) {
|
|
return (
|
|
<NavDropdown key={generateId()} id={item.id} title={item.label}>
|
|
{/* Iterate over the deteced Modules. */}
|
|
{item.items.map(entry => {
|
|
switch (entry.type) {
|
|
case 'action':
|
|
return (
|
|
<NavDropdown.Item key={generateId()} onClick={e => {
|
|
entry.onClick(this.props.generateData());
|
|
}}>{entry.label}</NavDropdown.Item>
|
|
);
|
|
case 'divider':
|
|
return (
|
|
<NavDropdown.Divider key={generateId()} />
|
|
);
|
|
case 'link':
|
|
return (
|
|
<NavDropdown.Item key={generateId()} href={entry.ref}>{entry.label}</NavDropdown.Item>
|
|
);
|
|
case 'menu':
|
|
return this._renderDropdown(entry);
|
|
}
|
|
|
|
})}
|
|
</NavDropdown>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Main Function to Render the Layout
|
|
*/
|
|
render() {
|
|
const defaultOptions: Partial<ToolbarProps<D>> = {
|
|
bg: 'dark',
|
|
position: 'top',
|
|
sticky: true
|
|
}
|
|
|
|
const opts: ToolbarProps<D> = assignIn(defaultOptions, this.props);
|
|
|
|
return (
|
|
<>
|
|
{opts.sticky ?
|
|
// Render a collapsable Navbar containing the defined Menu structure.
|
|
<Navbar collapseOnSelect sticky={opts.position} expand="lg" bg={opts.bg} variant={opts.bg}>
|
|
{opts.brand ? <>
|
|
<Navbar.Brand href={opts.brand.ref}>{opts.brand.label}</Navbar.Brand>
|
|
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
|
|
</> :
|
|
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
|
|
}
|
|
<Navbar.Collapse id="responsive-navbar-nav">
|
|
{opts.toolbar.items.map(item => this._renderMenuEntry(item))}
|
|
</Navbar.Collapse>
|
|
</Navbar> :
|
|
<Navbar collapseOnSelect fixed={opts.position} expand="lg" variant={opts.bg}>
|
|
{opts.brand ? <>
|
|
<Navbar.Brand href={opts.brand.ref}>{opts.brand.label}</Navbar.Brand>
|
|
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
|
|
</> :
|
|
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
|
|
}
|
|
<Navbar.Collapse id="responsive-navbar-nav">
|
|
{opts.toolbar.items.map(item => this._renderMenuEntry(item))}
|
|
</Navbar.Collapse>
|
|
</Navbar>
|
|
}
|
|
</>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default Toolbar; |