nope/resources/ui/layout/toolbar.tsx

225 lines
5.8 KiB
TypeScript
Raw Normal View History

2020-09-07 05:21:53 +00:00
import { assignIn } from 'lodash';
2020-09-02 15:00:03 +00:00
import * as React from 'react';
2020-09-07 05:21:53 +00:00
import { Nav, Navbar, NavDropdown } from 'react-bootstrap';
import { generateId } from '../../../lib/helpers/idMethods';
2020-09-02 15:00:03 +00:00
2020-09-07 05:21:53 +00:00
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,
}
2020-09-02 15:00:03 +00:00
2020-09-07 05:21:53 +00:00
/**
* 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
*
* @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'
2020-09-02 15:00:03 +00:00
}
export interface ToolbarState {
}
2020-09-07 05:21:53 +00:00
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>
);
}
2020-09-02 15:00:03 +00:00
render() {
2020-09-07 05:21:53 +00:00
const defaultOptions: Partial<ToolbarProps<D>> = {
bg: 'dark',
position: 'top',
sticky: true
}
const opts: ToolbarProps<D> = assignIn(defaultOptions, this.props);
return (
<>
{opts.sticky ?
<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>
}
</>
);
2020-09-02 15:00:03 +00:00
}
}
export default Toolbar;