2020-04-23 04:13:08 +02:00
|
|
|
import React, { useState } from 'react';
|
2020-04-06 22:39:49 +02:00
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
|
import classnames from 'classnames';
|
|
|
|
|
|
2020-08-14 20:25:08 +02:00
|
|
|
import { Button, Icon } from '../';
|
2020-04-06 22:39:49 +02:00
|
|
|
|
2020-04-07 19:03:47 +02:00
|
|
|
const borderSize = 4;
|
2020-04-14 00:35:32 +02:00
|
|
|
const expandedWidth = 248;
|
|
|
|
|
const collapsedWidth = 56;
|
2020-04-07 19:03:47 +02:00
|
|
|
|
2020-04-06 22:39:49 +02:00
|
|
|
const baseStyle = {
|
2020-04-07 19:03:47 +02:00
|
|
|
maxWidth: `${expandedWidth}px`,
|
|
|
|
|
width: `${expandedWidth}px`,
|
2020-04-06 22:39:49 +02:00
|
|
|
};
|
|
|
|
|
|
2020-04-08 17:00:08 +02:00
|
|
|
const collapsedHideWidth = expandedWidth - collapsedWidth - borderSize;
|
2020-04-07 19:03:47 +02:00
|
|
|
const styleMap = {
|
2020-04-06 22:39:49 +02:00
|
|
|
open: {
|
2020-04-07 19:03:47 +02:00
|
|
|
left: { marginLeft: '0px' },
|
|
|
|
|
right: { marginRight: '0px' },
|
2020-04-06 22:39:49 +02:00
|
|
|
},
|
|
|
|
|
closed: {
|
2020-04-08 17:00:08 +02:00
|
|
|
left: { marginLeft: `-${collapsedHideWidth}px` },
|
|
|
|
|
right: { marginRight: `-${collapsedHideWidth}px` },
|
2020-04-06 22:39:49 +02:00
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2020-04-08 17:00:08 +02:00
|
|
|
const baseClasses =
|
2020-04-14 00:35:32 +02:00
|
|
|
'transition-all duration-300 ease-in-out h-100 bg-primary-dark border-black flex flex-col justify-start box-content';
|
2020-04-07 19:03:47 +02:00
|
|
|
|
|
|
|
|
const classesMap = {
|
|
|
|
|
open: {
|
|
|
|
|
left: `border-r-${borderSize}`,
|
|
|
|
|
right: `border-l-${borderSize}`,
|
|
|
|
|
},
|
|
|
|
|
closed: {
|
|
|
|
|
left: `border-r-${borderSize} items-end`,
|
|
|
|
|
right: `border-l-${borderSize} items-start`,
|
|
|
|
|
},
|
|
|
|
|
};
|
2020-04-06 22:39:49 +02:00
|
|
|
|
2020-04-07 21:59:48 +02:00
|
|
|
const openIconName = {
|
2020-04-08 18:00:07 +02:00
|
|
|
left: 'push-left',
|
|
|
|
|
right: 'push-right',
|
2020-04-07 21:59:48 +02:00
|
|
|
};
|
|
|
|
|
|
2020-04-10 01:31:21 +02:00
|
|
|
const position = {
|
|
|
|
|
left: {
|
|
|
|
|
right: 5,
|
|
|
|
|
},
|
|
|
|
|
right: {
|
|
|
|
|
left: 5,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2020-04-23 04:13:08 +02:00
|
|
|
const getChildComponent = (childComponents, componentOpen) => {
|
|
|
|
|
if (Array.isArray(childComponents)) {
|
|
|
|
|
return childComponents.find(
|
2020-04-29 20:15:45 +02:00
|
|
|
_childComponent => _childComponent.name === componentOpen
|
2020-04-23 04:13:08 +02:00
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
return childComponents;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2020-04-06 22:39:49 +02:00
|
|
|
const SidePanel = ({
|
|
|
|
|
side,
|
|
|
|
|
className,
|
2020-04-23 04:13:08 +02:00
|
|
|
defaultComponentOpen,
|
|
|
|
|
childComponents,
|
2020-04-06 22:39:49 +02:00
|
|
|
}) => {
|
2020-04-23 04:13:08 +02:00
|
|
|
const [componentOpen, setComponentOpen] = useState(defaultComponentOpen);
|
|
|
|
|
|
|
|
|
|
const openStatus = componentOpen ? 'open' : 'closed';
|
2020-04-07 19:03:47 +02:00
|
|
|
const style = Object.assign({}, styleMap[openStatus][side], baseStyle);
|
|
|
|
|
|
2020-04-23 04:13:08 +02:00
|
|
|
const childComponent = getChildComponent(childComponents, componentOpen);
|
|
|
|
|
|
|
|
|
|
const getPanelButtons = () => {
|
|
|
|
|
const _childComponents = Array.isArray(childComponents)
|
|
|
|
|
? childComponents
|
|
|
|
|
: [childComponents];
|
2020-04-29 20:15:45 +02:00
|
|
|
return _childComponents.map((childComponent, i) => {
|
2020-04-23 04:13:08 +02:00
|
|
|
return (
|
|
|
|
|
<Button
|
2020-04-29 20:15:45 +02:00
|
|
|
key={i}
|
2020-04-23 04:13:08 +02:00
|
|
|
variant="text"
|
|
|
|
|
color="inherit"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setComponentOpen(childComponent.name);
|
|
|
|
|
}}
|
|
|
|
|
style={{
|
|
|
|
|
minWidth: `${collapsedWidth}px`,
|
|
|
|
|
width: `${collapsedWidth}px`,
|
|
|
|
|
}}
|
2021-03-01 16:52:54 +01:00
|
|
|
name={childComponent.name}
|
2020-04-23 04:13:08 +02:00
|
|
|
className="flex flex-col text-xs px-1 py-1 text-white border-transparent border-b"
|
|
|
|
|
>
|
|
|
|
|
<Icon
|
|
|
|
|
name={childComponent.iconName}
|
|
|
|
|
className="text-primary-active"
|
|
|
|
|
/>
|
|
|
|
|
<span className="mt-2 text-white text-xs">
|
|
|
|
|
{childComponent.iconLabel}
|
|
|
|
|
</span>
|
|
|
|
|
</Button>
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className={classnames(
|
|
|
|
|
className,
|
|
|
|
|
baseClasses,
|
|
|
|
|
classesMap[openStatus][side]
|
|
|
|
|
)}
|
|
|
|
|
style={style}
|
|
|
|
|
>
|
|
|
|
|
{componentOpen ? (
|
|
|
|
|
<React.Fragment>
|
2020-04-13 19:53:36 +02:00
|
|
|
<div className="px-3 border-b border-secondary-light">
|
|
|
|
|
<Button
|
|
|
|
|
variant="text"
|
|
|
|
|
color="inherit"
|
|
|
|
|
rounded="none"
|
|
|
|
|
onClick={() => {
|
2020-04-23 04:13:08 +02:00
|
|
|
setComponentOpen(null);
|
2020-04-13 19:53:36 +02:00
|
|
|
}}
|
2021-03-01 16:52:54 +01:00
|
|
|
name={childComponent.name}
|
2020-04-13 19:53:36 +02:00
|
|
|
className="flex flex-row items-center px-3 h-12 relative w-full"
|
|
|
|
|
>
|
|
|
|
|
<Icon
|
|
|
|
|
name={openIconName[side]}
|
|
|
|
|
className={classnames(
|
|
|
|
|
'text-primary-active absolute',
|
|
|
|
|
side === 'left' && 'order-last'
|
|
|
|
|
)}
|
|
|
|
|
style={{ ...position[side] }}
|
|
|
|
|
/>
|
|
|
|
|
<span className="flex-1 text-primary-active">
|
2020-04-23 04:13:08 +02:00
|
|
|
{childComponent.label}
|
2020-04-13 19:53:36 +02:00
|
|
|
</span>
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
2021-05-28 20:32:48 +02:00
|
|
|
<childComponent.content />
|
2020-04-23 04:13:08 +02:00
|
|
|
</React.Fragment>
|
|
|
|
|
) : (
|
|
|
|
|
<React.Fragment>{getPanelButtons()}</React.Fragment>
|
2020-04-07 19:03:47 +02:00
|
|
|
)}
|
2020-04-06 22:39:49 +02:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
SidePanel.defaultProps = {
|
2020-04-23 04:13:08 +02:00
|
|
|
defaultComponentOpen: null,
|
2020-04-06 22:39:49 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
SidePanel.propTypes = {
|
|
|
|
|
side: PropTypes.oneOf(['left', 'right']).isRequired,
|
|
|
|
|
className: PropTypes.string,
|
2020-04-23 04:13:08 +02:00
|
|
|
defaultComponentOpen: PropTypes.string,
|
|
|
|
|
childComponents: PropTypes.oneOfType([
|
|
|
|
|
PropTypes.shape({
|
|
|
|
|
iconName: PropTypes.string.isRequired,
|
|
|
|
|
iconLabel: PropTypes.string.isRequired,
|
|
|
|
|
name: PropTypes.string.isRequired,
|
|
|
|
|
label: PropTypes.string.isRequired,
|
2020-07-24 12:51:57 +02:00
|
|
|
content: PropTypes.func, // TODO: Should be node, but it keeps complaining?
|
2020-04-23 04:13:08 +02:00
|
|
|
}),
|
|
|
|
|
PropTypes.arrayOf(
|
|
|
|
|
PropTypes.shape({
|
|
|
|
|
iconName: PropTypes.string.isRequired,
|
|
|
|
|
iconLabel: PropTypes.string.isRequired,
|
|
|
|
|
name: PropTypes.string.isRequired,
|
|
|
|
|
label: PropTypes.string.isRequired,
|
2020-07-24 12:51:57 +02:00
|
|
|
content: PropTypes.func, // TODO: Should be node, but it keeps complaining?
|
2020-04-23 04:13:08 +02:00
|
|
|
})
|
|
|
|
|
),
|
|
|
|
|
]),
|
2020-04-06 22:39:49 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default SidePanel;
|