@plone/volto
Version:
Volto
122 lines (113 loc) • 3.41 kB
JSX
import PropTypes from 'prop-types';
import React from 'react';
import { List } from 'semantic-ui-react';
import { Link as RouterLink } from 'react-router-dom';
import cx from 'classnames';
import { compose } from 'redux';
import { withRouter } from 'react-router';
import { defineMessages, useIntl } from 'react-intl';
import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
import Icon from '@plone/volto/components/theme/Icon/Icon';
import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
import { withContentNavigation } from './withContentNavigation';
import leftIcon from '@plone/volto/icons/left-key.svg';
import Image from '@plone/volto/components/theme/Image/Image';
const messages = defineMessages({
navigation: {
id: 'Navigation',
defaultMessage: 'Navigation',
},
});
function renderNode(node, parentLevel) {
const level = parentLevel + 1;
return (
<List.Item
key={node['@id']}
active={node.is_current}
className={`level-${level}`}
>
<List.Content>
{node.type !== 'link' ? (
<RouterLink
to={flattenToAppURL(node.href)}
title={node.description}
className={cx(`contenttype-${node.type}`, {
in_path: node.is_in_path,
})}
>
{node.thumb ? (
<Image src={flattenToAppURL(node.thumb)} className="ui image" />
) : (
''
)}
{node.title}
{node.is_current ? (
<List.Content className="active-indicator">
<Icon name={leftIcon} size="30px" />
</List.Content>
) : (
''
)}
</RouterLink>
) : (
<UniversalLink href={flattenToAppURL(node.href)}>
{node.title}
</UniversalLink>
)}
{(node.items?.length && (
<List.List>
{node.items.map((node) => renderNode(node, level))}
</List.List>
)) ||
''}
</List.Content>
</List.Item>
);
}
/**
* A navigation slot implementation, similar to the classic Plone navigation
* portlet. It uses the same API, so the options are similar to
* INavigationPortlet
*/
export function ContextNavigationComponent(props) {
const { navigation = {} } = props;
const { items = [] } = navigation;
const intl = useIntl();
return items.length ? (
<nav className="context-navigation">
{navigation.has_custom_name ? (
<div className="context-navigation-header">
<RouterLink to={flattenToAppURL(navigation.url || '')}>
{navigation.title}
</RouterLink>
</div>
) : (
<div className="context-navigation-header">
{intl.formatMessage(messages.navigation)}
</div>
)}
<List>{items.map((node) => renderNode(node, 0))}</List>
</nav>
) : (
''
);
}
ContextNavigationComponent.propTypes = {
/**
* Navigation tree returned from @contextnavigation restapi endpoint
*/
navigation: PropTypes.shape({
items: PropTypes.arrayOf(
PropTypes.shape({
title: PropTypes.string,
url: PropTypes.string,
}),
),
has_custom_name: PropTypes.bool,
title: PropTypes.string,
}),
};
export default compose(
withRouter,
withContentNavigation,
)(ContextNavigationComponent);