Skip to content

Commit cea99b6

Browse files
committed
feat(Add Application Launcher Component):
fix #184
1 parent 4a69ebd commit cea99b6

15 files changed

+759
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import classNames from 'classnames';
4+
import ApplicationLauncherToggle from './ApplicationLauncherToggle';
5+
import { Dropdown } from '../Dropdown';
6+
7+
class ApplicationLauncher extends React.Component {
8+
constructor(props) {
9+
super(props);
10+
11+
this.state = {
12+
showLauncher: false,
13+
type: props.type
14+
};
15+
}
16+
17+
componentWillReceiveProps = nextProps => {
18+
this.setState({ type: nextProps.type });
19+
};
20+
21+
toggleLauncher = () => {
22+
this.setState({ showLauncher: !this.state.showLauncher });
23+
};
24+
25+
render() {
26+
const classes = classNames(
27+
{
28+
'applauncher-pf applauncher-pf-block-list dropdown dropdown-kebab-pf':
29+
this.state.type === 'grid'
30+
},
31+
{
32+
'applauncher-pf dropdown dropdown-kebab-pf': this.state.type === 'list'
33+
},
34+
{ open: this.state.showLauncher }
35+
);
36+
return (
37+
<li className={classes}>
38+
<ApplicationLauncherToggle
39+
tooltipPlacement={this.props.tooltipPlacement}
40+
onClick={this.toggleLauncher}
41+
/>
42+
<Dropdown.Menu className="dropdown-menu-right">
43+
{this.props.children}
44+
</Dropdown.Menu>
45+
</li>
46+
);
47+
}
48+
}
49+
ApplicationLauncher.propTypes = {
50+
/** Children Node */
51+
children: PropTypes.node.isRequired,
52+
/** tooltipPlacement */
53+
tooltipPlacement: PropTypes.string,
54+
/** Application Launcher Type */
55+
type: PropTypes.string.isRequired
56+
};
57+
ApplicationLauncher.defaultProps = {
58+
tooltipPlacement: 'left'
59+
};
60+
61+
export default ApplicationLauncher;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { storiesOf } from '@storybook/react';
2+
import { withKnobs } from '@storybook/addon-knobs';
3+
import {
4+
NavApplicationLauncherStory,
5+
WrapperNavApplicationLauncherStory
6+
} from './Stories/index';
7+
8+
const stories = storiesOf('ApplicationLauncher', module);
9+
stories.addDecorator(withKnobs);
10+
11+
NavApplicationLauncherStory(stories);
12+
WrapperNavApplicationLauncherStory(stories);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from 'react';
2+
import { mount } from 'enzyme';
3+
import {
4+
ApplicationLauncher,
5+
ApplicationLauncherItem,
6+
ApplicationLauncherToggle
7+
} from './index';
8+
9+
const handleClick = e => {
10+
e.preventDefault();
11+
};
12+
13+
test('ApplicationLauncher is working properly', () => {
14+
const component = mount(
15+
<ApplicationLauncher type="grid" tooltipPlacement="left">
16+
<ApplicationLauncherItem
17+
icon="pficon pficon-storage-domain"
18+
title="Recteque"
19+
tooltip="Tooltip!"
20+
onClick={handleClick}
21+
/>
22+
</ApplicationLauncher>
23+
);
24+
25+
expect(component.render()).toMatchSnapshot();
26+
});
27+
28+
test('ApplicationLauncherItem is working properly', () => {
29+
const component = mount(
30+
<ApplicationLauncherItem
31+
icon="pficon pficon-storage-domain"
32+
title="Recteque"
33+
tooltip="Tooltip!"
34+
onClick={handleClick}
35+
/>
36+
);
37+
38+
expect(component.render()).toMatchSnapshot();
39+
});
40+
41+
test('ApplicationLauncherToggle is working properly', () => {
42+
const component = mount(
43+
<ApplicationLauncherToggle tooltipPlacement="left" onClick={handleClick} />
44+
);
45+
46+
expect(component.render()).toMatchSnapshot();
47+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import classNames from 'classnames';
2+
import React from 'react';
3+
import PropTypes from 'prop-types';
4+
import { Tooltip } from '../Tooltip';
5+
import { OverlayTrigger } from '../OverlayTrigger';
6+
import { Icon } from '../Icon';
7+
8+
const ApplicationLauncherItem = ({
9+
onClick,
10+
tooltip,
11+
tooltipPlacement,
12+
title,
13+
icon,
14+
noIcons,
15+
className,
16+
...props
17+
}) => {
18+
const classes = classNames('applauncher-pf-item', className);
19+
20+
return (
21+
<OverlayTrigger
22+
overlay={<Tooltip id="tooltip">{tooltip}</Tooltip>}
23+
placement={tooltipPlacement}
24+
trigger={['hover', 'focus']}
25+
rootClose={false}
26+
>
27+
<li className={classes} role="menuitem">
28+
<a className="applauncher-pf-link" href="#" onClick={e => onClick(e)}>
29+
{!noIcons && (
30+
<Icon type="pf" name={icon} className="applauncher-pf-link-icon" />
31+
)}
32+
<span className="applauncher-pf-link-title">{title}</span>
33+
</a>
34+
</li>
35+
</OverlayTrigger>
36+
);
37+
};
38+
ApplicationLauncherItem.propTypes = {
39+
/** Additional element css classes */
40+
className: PropTypes.string,
41+
/** onClick func */
42+
onClick: PropTypes.func,
43+
/** Title String */
44+
title: PropTypes.string.isRequired,
45+
/** Icon Type */
46+
icon: PropTypes.string.isRequired,
47+
/** App Tooltip */
48+
tooltip: PropTypes.string.isRequired,
49+
/** Tooltip Placement */
50+
tooltipPlacement: PropTypes.string,
51+
/** No Icons Bool */
52+
noIcons: PropTypes.bool
53+
};
54+
ApplicationLauncherItem.defaultProps = {
55+
className: '',
56+
onClick: null,
57+
noIcons: false,
58+
tooltipPlacement: 'left'
59+
};
60+
export default ApplicationLauncherItem;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { OverlayTrigger } from '../OverlayTrigger';
4+
import { Tooltip } from '../Tooltip';
5+
import { Icon } from '../Icon';
6+
import { Button } from '../Button';
7+
8+
const ApplicationLauncherToggle = ({ onClick, tooltipPlacement }) => {
9+
const tooltip = <Tooltip id="tooltip">Application Launcher</Tooltip>;
10+
11+
return (
12+
<OverlayTrigger
13+
placement={tooltipPlacement}
14+
id="applauncher-pf-block-list"
15+
overlay={tooltip}
16+
>
17+
<Button onClick={onClick} bsStyle="link" className="nav-item-iconic">
18+
<Icon
19+
className="fa fa-th applauncher-pf-icon"
20+
aria-describedby="tooltip"
21+
name=""
22+
/>
23+
</Button>
24+
</OverlayTrigger>
25+
);
26+
};
27+
ApplicationLauncherToggle.propTypes = {
28+
/** onClick func */
29+
onClick: PropTypes.func,
30+
/** tooltipPlacement */
31+
tooltipPlacement: PropTypes.string
32+
};
33+
ApplicationLauncherToggle.defaultProps = {
34+
onClick: null,
35+
tooltipPlacement: 'bottom'
36+
};
37+
38+
export default ApplicationLauncherToggle;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import React from 'react';
2+
import { action } from '@storybook/addon-actions';
3+
import { boolean, select } from '@storybook/addon-knobs';
4+
import { inlineTemplate } from '../../../../storybook/decorators/storyTemplates';
5+
import { DOCUMENTATION_URL } from '../../../../storybook/constants';
6+
import ApplicationLauncher from '../ApplicationLauncher';
7+
import ApplicationLauncherItem from '../ApplicationLauncherItem';
8+
9+
const handleClick = e => {
10+
e.preventDefault();
11+
action('app clicked!')();
12+
};
13+
14+
const NavApplicationLauncherStory = stories => {
15+
stories.addWithInfo('Application Launcher', '', () => {
16+
const type = select(
17+
'Launcher Type',
18+
{ grid: 'Grid', list: 'List' },
19+
'grid'
20+
);
21+
22+
const iconBool = boolean('Icons', true);
23+
24+
const story = (
25+
<nav className="navbar navbar-pf-vertical">
26+
<nav className="collapse navbar-collapse">
27+
<ul className="nav navbar-nav navbar-right navbar-iconic">
28+
<ApplicationLauncher type={type} tooltipPlacement="left">
29+
<ApplicationLauncherItem
30+
icon="storage-domain"
31+
title="Recteque"
32+
tooltip="Tooltip!"
33+
tooltipPlacement="left"
34+
onClick={handleClick}
35+
noIcons={!iconBool}
36+
/>
37+
<ApplicationLauncherItem
38+
icon="virtual-machine"
39+
title="Ipsum"
40+
tooltip="Tooltip!"
41+
tooltipPlacement="left"
42+
onClick={handleClick}
43+
noIcons={!iconBool}
44+
/>
45+
<ApplicationLauncherItem
46+
icon="domain"
47+
title="Lorem"
48+
tooltip="Tooltip!"
49+
tooltipPlacement="left"
50+
onClick={handleClick}
51+
noIcons={!iconBool}
52+
/>
53+
<ApplicationLauncherItem
54+
icon="home"
55+
title="Home"
56+
tooltip="Tooltip!"
57+
tooltipPlacement="left"
58+
onClick={handleClick}
59+
noIcons={!iconBool}
60+
/>
61+
</ApplicationLauncher>
62+
</ul>
63+
</nav>
64+
</nav>
65+
);
66+
return inlineTemplate({
67+
title: 'ApplicationLauncher',
68+
documentationLink: `${
69+
DOCUMENTATION_URL.PATTERNFLY_ORG_APPLICATION_FRAMEWORK
70+
}launcher/`,
71+
story
72+
});
73+
});
74+
};
75+
76+
export default NavApplicationLauncherStory;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import React from 'react';
2+
import { action } from '@storybook/addon-actions';
3+
import { boolean, select } from '@storybook/addon-knobs';
4+
import { inlineTemplate } from '../../../../storybook/decorators/storyTemplates';
5+
import { DOCUMENTATION_URL } from '../../../../storybook/constants';
6+
import ApplicationLauncherWrapper from '../Wrappers/ApplicationLauncherWrapper';
7+
8+
const handleClick = e => {
9+
e.preventDefault();
10+
action('app clicked!')();
11+
};
12+
13+
const Apps = [
14+
{
15+
title: 'Ipsum',
16+
icon: 'home',
17+
tooltip: 'Tooltip!',
18+
onClick: e => {
19+
handleClick(e);
20+
}
21+
},
22+
{
23+
title: 'Royal',
24+
icon: 'virtual-machine',
25+
tooltip: 'Tooltip!',
26+
onClick: e => {
27+
handleClick(e);
28+
}
29+
},
30+
{
31+
title: 'Lemon',
32+
icon: 'storage-domain',
33+
tooltip: 'Tooltip!',
34+
onClick: e => {
35+
handleClick(e);
36+
}
37+
},
38+
{
39+
title: 'Domain',
40+
icon: 'domain',
41+
tooltip: 'Tooltip!',
42+
onClick: e => {
43+
handleClick(e);
44+
}
45+
}
46+
];
47+
48+
const WrapperNavApplicationLauncherStory = stories => {
49+
stories.addWithInfo('Wrapper Application Launcher', '', () => {
50+
const type = select(
51+
'Launcher Type',
52+
{ grid: 'Grid', list: 'List' },
53+
'grid'
54+
);
55+
56+
const iconBool = boolean('Icons', true);
57+
58+
const story = (
59+
<nav className="navbar navbar-pf-vertical">
60+
<nav className="collapse navbar-collapse">
61+
<ul className="nav navbar-nav navbar-right navbar-iconic">
62+
<ApplicationLauncherWrapper
63+
apps={Apps}
64+
noIcons={!iconBool}
65+
type={type}
66+
tooltipPlacement="left"
67+
/>
68+
</ul>
69+
</nav>
70+
</nav>
71+
);
72+
return inlineTemplate({
73+
title: 'WrapperApplicationLauncher',
74+
documentationLink: `${
75+
DOCUMENTATION_URL.PATTERNFLY_ORG_APPLICATION_FRAMEWORK
76+
}launcher/`,
77+
story
78+
});
79+
});
80+
};
81+
82+
export default WrapperNavApplicationLauncherStory;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export {
2+
default as NavApplicationLauncherStory
3+
} from './NavApplicationLauncherStory';
4+
export {
5+
default as WrapperNavApplicationLauncherStory
6+
} from './WrapperNavApplicationLauncherStory';

0 commit comments

Comments
 (0)