forked from geosolutions-it/geonode-mapstore-client
-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Client - Uniform items object configuration for all menus (#139)
- Loading branch information
1 parent
17f1f21
commit a629631
Showing
16 changed files
with
712 additions
and
356 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
geonode_mapstore_client/client/js/components/Menu/DropdownList.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/* | ||
* Copyright 2021, GeoSolutions Sas. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
|
||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import Message from '@mapstore/framework/components/I18N/Message'; | ||
import { Dropdown, Badge } from 'react-bootstrap-v1'; | ||
import isNil from 'lodash/isNil'; | ||
import { createPortal } from 'react-dom'; | ||
|
||
const isValidBadgeValue = value => !!(value !== '' && !isNil(value)); | ||
/** | ||
* DropdownList component | ||
* @name DropdownList | ||
* @memberof components.Menu.DropdownList | ||
* @prop {number} id to apply to toogle | ||
* @prop {array} items list od items of Dropdown | ||
* @prop {string} label label to apply to toogle | ||
* @prop {string} labelId alternative to label | ||
* @prop {string} labelId alternative to labe | ||
* @prop {object} toogleStyle inline style to apply to toogle comp | ||
* @prop {string} toogleImage image to apply to toogle comp | ||
* @prop {string} dropdownClass the css class to apply to the comp | ||
* @prop {number} tabIndex define navigation order | ||
* @prop {number} badgeValue to apply the value to the item in list | ||
* @prop {node} containerNode the node to append the child element into a DOM | ||
* @example | ||
* <DropdownList | ||
* id={id} | ||
* items={items} | ||
* label={label} | ||
* labelId={labelId} | ||
* toogleStyle={style} | ||
* toogleImage={image} | ||
* state={state} | ||
* dropdownClass={classItem} | ||
* tabIndex={tabIndex} | ||
* badgeValue={badgeValue} | ||
* containerNode={containerNode} | ||
* /> | ||
* | ||
*/ | ||
|
||
|
||
const DropdownList = ({ | ||
id, | ||
items, | ||
label, | ||
labelId, | ||
toogleStyle, | ||
toogleImage, | ||
dropdownClass, | ||
tabIndex, | ||
badgeValue, | ||
containerNode | ||
}) => { | ||
|
||
|
||
const dropdownItems = items | ||
.map((itm, idx) => { | ||
if (itm.type === 'divider') { | ||
return <Dropdown.Divider key={idx} />; | ||
} | ||
return ( | ||
<Dropdown.Item | ||
key={idx} | ||
href={itm.href} | ||
style={itm.style} | ||
> | ||
{itm.labelId && <Message msgId={itm.labelId} /> || itm.label} | ||
{isValidBadgeValue(itm.badge) && <Badge>{itm.badge}</Badge>} | ||
</Dropdown.Item> | ||
); | ||
}); | ||
|
||
const DropdownToogle = ( | ||
<Dropdown.Toggle | ||
id={'gn-toggle-dropdown-' + id} | ||
variant="default" | ||
tabIndex={tabIndex} | ||
style={toogleStyle} | ||
> | ||
{toogleImage | ||
? <img src={toogleImage} /> | ||
: null | ||
} | ||
{labelId && <Message msgId={labelId} /> || label} | ||
{isValidBadgeValue(badgeValue) && <Badge>{badgeValue}</Badge>} | ||
</Dropdown.Toggle> | ||
|
||
); | ||
|
||
|
||
return ( | ||
<Dropdown | ||
className={`${dropdownClass}`} | ||
> | ||
{DropdownToogle} | ||
{containerNode | ||
? createPortal(<Dropdown.Menu> | ||
{dropdownItems} | ||
</Dropdown.Menu>, containerNode.parentNode) | ||
: <Dropdown.Menu> | ||
{dropdownItems} | ||
</Dropdown.Menu>} | ||
</Dropdown> | ||
); | ||
|
||
}; | ||
|
||
DropdownList.propTypes = { | ||
id: PropTypes.number, | ||
items: PropTypes.array.isRequired, | ||
label: PropTypes.string, | ||
labelId: PropTypes.string, | ||
toogleStyle: PropTypes.object, | ||
toogleImage: PropTypes.string, | ||
state: PropTypes.object, | ||
dropdownClass: PropTypes.string, | ||
tabIndex: PropTypes.number, | ||
badgeValue: PropTypes.number, | ||
containerNode: PropTypes.element | ||
|
||
}; | ||
|
||
export default DropdownList; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/* | ||
* Copyright 2021, GeoSolutions Sas. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import MenuItem from './MenuItem'; | ||
|
||
/** | ||
* Menu component | ||
* @name Menu | ||
* @memberof components.Menu | ||
* @prop {array} items list of menu item | ||
* @prop {string} containerClass css class of list container | ||
* @prop {string} childrenClass css class of item in list | ||
* @prop {string} query string to build the query url in case of link item | ||
* @prop {function} formatHref function to format the href in case of link item | ||
* @example | ||
* <Menu items={items} user={user} /> | ||
* | ||
*/ | ||
|
||
|
||
const Menu = ({ | ||
items, | ||
containerClass, | ||
childrenClass, | ||
query, | ||
formatHref | ||
}) => { | ||
|
||
return ( | ||
<ul className={`${containerClass}`}> | ||
{items | ||
.map((item, idx) => { | ||
return ( | ||
<li key={idx}> | ||
<MenuItem | ||
item={{ ...item, id: item.id || idx }} | ||
menuItemsProps={{ | ||
query, | ||
formatHref | ||
}} | ||
classItem={childrenClass} | ||
/> | ||
</li> | ||
); | ||
})} | ||
</ul> | ||
); | ||
}; | ||
|
||
Menu.propTypes = { | ||
items: PropTypes.array.isRequired, | ||
containerClass: PropTypes.string, | ||
childrenClass: PropTypes.string, | ||
query: PropTypes.string, | ||
formatHref: PropTypes.func | ||
|
||
}; | ||
|
||
Menu.defaultProps = { | ||
items: [], | ||
query: {}, | ||
user: undefined, | ||
formatHref: () => '#' | ||
}; | ||
|
||
|
||
export default Menu; |
119 changes: 119 additions & 0 deletions
119
geonode_mapstore_client/client/js/components/Menu/MenuItem.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/* | ||
* Copyright 2021, GeoSolutions Sas. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
|
||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import castArray from 'lodash/castArray'; | ||
import isNil from 'lodash/isNil'; | ||
import Tag from '@js/components/home/Tag'; | ||
import { Badge, Nav } from 'react-bootstrap-v1'; | ||
import Message from '@mapstore/framework/components/I18N/Message'; | ||
import DropdownList from './DropdownList'; | ||
const isValidBadgeValue = value => !!(value !== '' && !isNil(value)); | ||
/** | ||
* Menu item component | ||
* @name MenuItem | ||
* @memberof components.Menu.MenuItem | ||
* @prop {object} item the item menu | ||
* @prop {object} menuItemsProps contains pros to apply to items, to manage single permissions, build href and query url | ||
* @prop {node} containerNode the node to append the child element into a DOM | ||
* @prop {number} tabIndex define navigation order | ||
* @prop {boolean} draggable is element is draggable | ||
* @prop {function} classItem class to apply to the Item | ||
* @example | ||
* <MenuItem | ||
* tabIndex={tabindex} | ||
* item={{ ...item, id: item.id || idx }} | ||
* draggable={false} | ||
* menuItemsProps={menuItemsProps} | ||
* containerNode={containerNode.current} | ||
* /> | ||
* | ||
*/ | ||
|
||
const MenuItem = ({ item, menuItemsProps, containerNode, tabIndex, draggable, classItem }) => { | ||
|
||
const { formatHref, query } = menuItemsProps; | ||
const { id, type, label, labelId = '', items = [], href, style, badge = '', image, subType } = item; | ||
|
||
const badgeValue = badge; | ||
if (type === 'dropdown') { | ||
return (<DropdownList | ||
id={id} | ||
items={items} | ||
label={label} | ||
labelId={labelId} | ||
toogleStyle={style} | ||
toogleImage={image} | ||
dropdownClass={classItem} | ||
tabIndex={tabIndex} | ||
badgeValue={badgeValue} | ||
containerNode={containerNode} | ||
/>); | ||
} | ||
|
||
if (type === 'link') { | ||
if (subType === 'tag') { | ||
return ( | ||
<Tag | ||
tabIndex={tabIndex} | ||
draggable={draggable} | ||
href={href} | ||
style={style} | ||
|
||
> | ||
{labelId && <Message msgId={labelId} /> || label} | ||
{isValidBadgeValue(badgeValue) && <Badge>{badgeValue}</Badge>} | ||
</Tag> | ||
); | ||
} | ||
|
||
return ( | ||
<Nav.Link href={href}>{labelId && <Message msgId={labelId} /> || label}</Nav.Link> | ||
); | ||
|
||
} | ||
|
||
if (type === 'divider') { | ||
return <div className="gn-menu-index-divider" style={style}></div>; | ||
} | ||
if (type === 'filter') { | ||
const active = castArray(query.f || []).find(value => value === item.id); | ||
return ( | ||
<Tag | ||
tabIndex={tabIndex} | ||
draggable={draggable} | ||
active={active} | ||
style={style} | ||
href={formatHref({ | ||
query: { f: item.id }, | ||
replaceQuery: active ? false : true | ||
})} | ||
> | ||
{labelId && <Message msgId={labelId} /> || label} | ||
{isValidBadgeValue(badgeValue) && <Badge>{badgeValue}</Badge>} | ||
</Tag> | ||
); | ||
} | ||
return null; | ||
|
||
|
||
}; | ||
|
||
MenuItem.propTypes = { | ||
item: PropTypes.object.isRequired, | ||
menuItemsProps: PropTypes.object.isRequired, | ||
containerNode: PropTypes.element, | ||
tabIndex: PropTypes.number, | ||
draggable: PropTypes.bool, | ||
classItem: PropTypes.string | ||
|
||
}; | ||
|
||
export default MenuItem; |
Oops, something went wrong.