@eeacms/volto-eea-website-theme 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -1
- package/package.json +3 -1
- package/src/components/manage/Blocks/ContextNavigation/ContextNavigationEdit.jsx +45 -0
- package/src/components/manage/Blocks/ContextNavigation/ContextNavigationEdit.test.jsx +88 -0
- package/src/components/manage/Blocks/ContextNavigation/ContextNavigationView.jsx +14 -0
- package/src/components/manage/Blocks/ContextNavigation/ContextNavigationView.test.jsx +71 -0
- package/src/components/manage/Blocks/ContextNavigation/index.js +30 -0
- package/src/components/manage/Blocks/ContextNavigation/schema.js +88 -0
- package/src/components/manage/Blocks/ContextNavigation/variations/Accordion.jsx +179 -0
- package/src/components/manage/Blocks/ContextNavigation/variations/Default.jsx +9 -0
- package/src/components/manage/Blocks/ContextNavigation/variations/index.js +18 -0
- package/src/components/manage/Blocks/Title/Edit.jsx +7 -4
- package/src/components/manage/Blocks/Title/View.jsx +14 -24
- package/src/components/manage/Blocks/Title/index.js +52 -0
- package/src/components/manage/Blocks/Title/variations/Default.jsx +43 -0
- package/src/components/manage/Blocks/Title/variations/WebReport.jsx +69 -0
- package/src/components/manage/Blocks/Title/variations/WebReportPage.jsx +59 -0
- package/src/components/manage/Blocks/Title/variations/styles.less +28 -0
- package/src/components/theme/Banner/View.jsx +5 -1
- package/src/components/theme/SubsiteClass.jsx +3 -1
- package/src/components/theme/WebReport/WebReportSectionView.jsx +49 -0
- package/src/customizations/volto/components/theme/Breadcrumbs/Breadcrumbs.jsx +20 -2
- package/src/customizations/volto/components/theme/Header/Header.jsx +3 -3
- package/src/customizations/volto/components/theme/View/DefaultView.jsx +190 -0
- package/src/hocs/withDeviceSize.test.jsx +79 -0
- package/src/index.js +20 -7
package/CHANGELOG.md
CHANGED
@@ -4,7 +4,17 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
4
4
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
6
6
|
|
7
|
-
### [2.
|
7
|
+
### [2.4.0](https://github.com/eea/volto-eea-website-theme/compare/2.3.0...2.4.0) - 11 October 2024
|
8
|
+
|
9
|
+
#### :bug: Bug Fixes
|
10
|
+
|
11
|
+
- fix: add subsite_css class when not undefined [nileshgulia1 - [`db3f80f`](https://github.com/eea/volto-eea-website-theme/commit/db3f80f9dac34f528030d1d2a2f858555059879e)]
|
12
|
+
|
13
|
+
#### :hammer_and_wrench: Others
|
14
|
+
|
15
|
+
- Increase test coverage [dobri1408 - [`e2d46a9`](https://github.com/eea/volto-eea-website-theme/commit/e2d46a981c6f50980f0b0bf1f35b2d03121f3c88)]
|
16
|
+
- Update package.json [Ichim David - [`24ea8f0`](https://github.com/eea/volto-eea-website-theme/commit/24ea8f0ef7c474bcf171f4720465e12a0d600b46)]
|
17
|
+
### [2.3.0](https://github.com/eea/volto-eea-website-theme/compare/2.2.2...2.3.0) - 13 September 2024
|
8
18
|
|
9
19
|
#### :house: Internal changes
|
10
20
|
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@eeacms/volto-eea-website-theme",
|
3
|
-
"version": "2.
|
3
|
+
"version": "2.4.0",
|
4
4
|
"description": "@eeacms/volto-eea-website-theme: Volto add-on",
|
5
5
|
"main": "src/index.js",
|
6
6
|
"author": "European Environment Agency: IDM2 A-Team",
|
@@ -14,6 +14,7 @@
|
|
14
14
|
"react"
|
15
15
|
],
|
16
16
|
"addons": [
|
17
|
+
"@eeacms/volto-block-toc",
|
17
18
|
"@eeacms/volto-group-block",
|
18
19
|
"@eeacms/volto-eea-design-system",
|
19
20
|
"volto-subsites"
|
@@ -23,6 +24,7 @@
|
|
23
24
|
"url": "git@github.com:eea/volto-eea-website-theme.git"
|
24
25
|
},
|
25
26
|
"dependencies": {
|
27
|
+
"@eeacms/volto-block-toc": "*",
|
26
28
|
"@eeacms/volto-block-style": "*",
|
27
29
|
"@eeacms/volto-eea-design-system": "*",
|
28
30
|
"@eeacms/volto-group-block": "*",
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { EditSchema } from './schema';
|
3
|
+
import { SidebarPortal } from '@plone/volto/components';
|
4
|
+
import BlockDataForm from '@plone/volto/components/manage/Form/BlockDataForm';
|
5
|
+
|
6
|
+
import ContextNavigationView from './ContextNavigationView';
|
7
|
+
|
8
|
+
const ContextNavigationFillEdit = (props) => {
|
9
|
+
const contentTypes = props.properties?.['@components']?.types;
|
10
|
+
const availableTypes = React.useMemo(
|
11
|
+
() => contentTypes?.map((type) => [type.id, type.title || type.name]),
|
12
|
+
[contentTypes],
|
13
|
+
);
|
14
|
+
|
15
|
+
const schema = React.useMemo(
|
16
|
+
() => EditSchema({ availableTypes }),
|
17
|
+
[availableTypes],
|
18
|
+
);
|
19
|
+
|
20
|
+
return (
|
21
|
+
<>
|
22
|
+
<h3>Context navigation</h3>
|
23
|
+
<ContextNavigationView {...props} mode="edit" />{' '}
|
24
|
+
<SidebarPortal selected={props.selected}>
|
25
|
+
<BlockDataForm
|
26
|
+
schema={schema}
|
27
|
+
title={schema.title}
|
28
|
+
onChangeField={(id, value) => {
|
29
|
+
props.onChangeBlock(props.block, {
|
30
|
+
...props.data,
|
31
|
+
[id]: value,
|
32
|
+
});
|
33
|
+
}}
|
34
|
+
onChangeBlock={props.onChangeBlock}
|
35
|
+
formData={props.data}
|
36
|
+
block={props.block}
|
37
|
+
navRoot={props.navRoot}
|
38
|
+
contentType={props.contentType}
|
39
|
+
/>
|
40
|
+
</SidebarPortal>
|
41
|
+
</>
|
42
|
+
);
|
43
|
+
};
|
44
|
+
|
45
|
+
export default ContextNavigationFillEdit;
|
@@ -0,0 +1,88 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { render, fireEvent } from '@testing-library/react';
|
3
|
+
import ContextNavigationEdit from './ContextNavigationEdit';
|
4
|
+
import { Router } from 'react-router-dom';
|
5
|
+
import { Provider } from 'react-intl-redux';
|
6
|
+
import configureStore from 'redux-mock-store';
|
7
|
+
import { createMemoryHistory } from 'history';
|
8
|
+
import '@testing-library/jest-dom/extend-expect';
|
9
|
+
|
10
|
+
jest.mock('@plone/volto/components', () => ({
|
11
|
+
InlineForm: ({ onChangeField }) => (
|
12
|
+
<div>
|
13
|
+
<p>InlineForm</p>
|
14
|
+
<input id="test" onChange={onChangeField} />
|
15
|
+
</div>
|
16
|
+
),
|
17
|
+
SidebarPortal: ({ children, selected }) =>
|
18
|
+
selected ? (
|
19
|
+
<div>
|
20
|
+
<div>SidebarPortal</div>
|
21
|
+
{children}
|
22
|
+
</div>
|
23
|
+
) : null,
|
24
|
+
}));
|
25
|
+
|
26
|
+
jest.mock('@plone/volto/components/theme/Navigation/ContextNavigation', () => {
|
27
|
+
return {
|
28
|
+
__esModule: true,
|
29
|
+
default: ({ params }) => {
|
30
|
+
return <div>ConnectedContextNavigation {params.root_path}</div>;
|
31
|
+
},
|
32
|
+
};
|
33
|
+
});
|
34
|
+
|
35
|
+
jest.mock('@plone/volto/helpers', () => ({
|
36
|
+
withBlockExtensions: jest.fn((Component) => Component),
|
37
|
+
emptyBlocksForm: jest.fn(),
|
38
|
+
getBlocksLayoutFieldname: () => 'blocks_layout',
|
39
|
+
withVariationSchemaEnhancer: jest.fn((Component) => Component),
|
40
|
+
}));
|
41
|
+
|
42
|
+
const mockStore = configureStore();
|
43
|
+
const store = mockStore({
|
44
|
+
intl: {
|
45
|
+
locale: 'en',
|
46
|
+
messages: {},
|
47
|
+
},
|
48
|
+
});
|
49
|
+
|
50
|
+
describe('ContextNavigationEdit', () => {
|
51
|
+
it('renders corectly', () => {
|
52
|
+
const history = createMemoryHistory();
|
53
|
+
const { getByText, queryByText } = render(
|
54
|
+
<Provider store={store}>
|
55
|
+
<Router history={history}>
|
56
|
+
<ContextNavigationEdit selected={false} />
|
57
|
+
</Router>
|
58
|
+
,
|
59
|
+
</Provider>,
|
60
|
+
);
|
61
|
+
|
62
|
+
expect(getByText('Context navigation')).toBeInTheDocument();
|
63
|
+
expect(getByText('ConnectedContextNavigation')).toBeInTheDocument();
|
64
|
+
expect(queryByText('InlineForm')).toBeNull();
|
65
|
+
expect(queryByText('SidebarPortal')).toBeNull();
|
66
|
+
});
|
67
|
+
|
68
|
+
it('renders corectly', () => {
|
69
|
+
const history = createMemoryHistory();
|
70
|
+
const { container, getByText } = render(
|
71
|
+
<Provider store={store}>
|
72
|
+
<Router history={history}>
|
73
|
+
<ContextNavigationEdit selected={true} onChangeBlock={() => {}} />
|
74
|
+
</Router>
|
75
|
+
,
|
76
|
+
</Provider>,
|
77
|
+
);
|
78
|
+
|
79
|
+
expect(getByText('Context navigation')).toBeInTheDocument();
|
80
|
+
expect(getByText('ConnectedContextNavigation')).toBeInTheDocument();
|
81
|
+
expect(getByText('InlineForm')).toBeInTheDocument();
|
82
|
+
expect(getByText('SidebarPortal')).toBeInTheDocument();
|
83
|
+
|
84
|
+
fireEvent.change(container.querySelector('#test'), {
|
85
|
+
target: { value: 'test' },
|
86
|
+
});
|
87
|
+
});
|
88
|
+
});
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { flattenToAppURL, withBlockExtensions } from '@plone/volto/helpers';
|
3
|
+
import DefaultTemplate from './variations/Default';
|
4
|
+
|
5
|
+
const ContextNavigationView = (props = {}) => {
|
6
|
+
const { variation, data = {} } = props;
|
7
|
+
const navProps = { ...data };
|
8
|
+
const root_path = data?.root_node?.[0]?.['@id'];
|
9
|
+
if (root_path) navProps['root_path'] = flattenToAppURL(root_path);
|
10
|
+
const Renderer = variation?.view ?? DefaultTemplate;
|
11
|
+
return <Renderer params={navProps} mode={props.mode} />;
|
12
|
+
};
|
13
|
+
|
14
|
+
export default withBlockExtensions(ContextNavigationView);
|
@@ -0,0 +1,71 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { render } from '@testing-library/react';
|
3
|
+
import ContextNavigationView from './ContextNavigationView';
|
4
|
+
import { Router } from 'react-router-dom';
|
5
|
+
import { Provider } from 'react-intl-redux';
|
6
|
+
import configureStore from 'redux-mock-store';
|
7
|
+
import { createMemoryHistory } from 'history';
|
8
|
+
import '@testing-library/jest-dom/extend-expect';
|
9
|
+
|
10
|
+
jest.mock('@plone/volto/components/theme/Navigation/ContextNavigation', () => {
|
11
|
+
return {
|
12
|
+
__esModule: true,
|
13
|
+
default: ({ params }) => {
|
14
|
+
return <div>ConnectedContextNavigation {params.root_path}</div>;
|
15
|
+
},
|
16
|
+
};
|
17
|
+
});
|
18
|
+
|
19
|
+
jest.mock('@plone/volto/helpers', () => ({
|
20
|
+
withBlockExtensions: jest.fn((Component) => Component),
|
21
|
+
emptyBlocksForm: jest.fn(),
|
22
|
+
getBlocksLayoutFieldname: () => 'blocks_layout',
|
23
|
+
flattenToAppURL: () => '',
|
24
|
+
}));
|
25
|
+
|
26
|
+
const mockStore = configureStore();
|
27
|
+
const store = mockStore({
|
28
|
+
intl: {
|
29
|
+
locale: 'en',
|
30
|
+
messages: {},
|
31
|
+
},
|
32
|
+
});
|
33
|
+
|
34
|
+
describe('ContextNavigationView', () => {
|
35
|
+
let history;
|
36
|
+
beforeEach(() => {
|
37
|
+
history = createMemoryHistory();
|
38
|
+
});
|
39
|
+
|
40
|
+
it('renders corectly', () => {
|
41
|
+
const { container } = render(
|
42
|
+
<Provider store={store}>
|
43
|
+
<Router history={history}>
|
44
|
+
<ContextNavigationView />
|
45
|
+
</Router>
|
46
|
+
</Provider>,
|
47
|
+
);
|
48
|
+
|
49
|
+
expect(container.firstChild).toHaveTextContent(
|
50
|
+
'ConnectedContextNavigation',
|
51
|
+
);
|
52
|
+
});
|
53
|
+
|
54
|
+
it('renders corectly', () => {
|
55
|
+
const { container } = render(
|
56
|
+
<Provider store={store}>
|
57
|
+
<Router history={history}>
|
58
|
+
<ContextNavigationView
|
59
|
+
data={{
|
60
|
+
navProps: { root_path: 'https://localhost:3000/test' },
|
61
|
+
root_node: [{ '@id': 'root_node' }],
|
62
|
+
}}
|
63
|
+
/>
|
64
|
+
</Router>
|
65
|
+
</Provider>,
|
66
|
+
);
|
67
|
+
expect(container.firstChild).toHaveTextContent(
|
68
|
+
'ConnectedContextNavigation',
|
69
|
+
);
|
70
|
+
});
|
71
|
+
});
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import codeSVG from '@plone/volto/icons/code.svg';
|
2
|
+
import ContextNavigationEdit from './ContextNavigationEdit';
|
3
|
+
import ContextNavigationView from './ContextNavigationView';
|
4
|
+
import BlockSettingsSchema from '@plone/volto/components/manage/Blocks/Block/Schema';
|
5
|
+
import variations from './variations';
|
6
|
+
|
7
|
+
const applyConfig = (config) => {
|
8
|
+
config.blocks.blocksConfig.contextNavigation = {
|
9
|
+
id: 'contextNavigation',
|
10
|
+
title: 'Navigation',
|
11
|
+
icon: codeSVG,
|
12
|
+
group: 'common',
|
13
|
+
view: ContextNavigationView,
|
14
|
+
edit: ContextNavigationEdit,
|
15
|
+
schema: BlockSettingsSchema,
|
16
|
+
restricted: false,
|
17
|
+
variations,
|
18
|
+
mostUsed: false,
|
19
|
+
blockHasOwnFocusManagement: true,
|
20
|
+
sidebarTab: 1,
|
21
|
+
security: {
|
22
|
+
addPermission: [],
|
23
|
+
view: [],
|
24
|
+
},
|
25
|
+
};
|
26
|
+
|
27
|
+
return config;
|
28
|
+
};
|
29
|
+
|
30
|
+
export default applyConfig;
|
@@ -0,0 +1,88 @@
|
|
1
|
+
export const EditSchema = ({ availableTypes }) => {
|
2
|
+
return {
|
3
|
+
title: 'Navigation',
|
4
|
+
fieldsets: [
|
5
|
+
{
|
6
|
+
id: 'default',
|
7
|
+
title: 'Default',
|
8
|
+
fields: [
|
9
|
+
'name',
|
10
|
+
'root_node',
|
11
|
+
'portal_type',
|
12
|
+
'includeTop',
|
13
|
+
'currentFolderOnly',
|
14
|
+
'topLevel',
|
15
|
+
'bottomLevel',
|
16
|
+
'no_icons',
|
17
|
+
'thumb_scale',
|
18
|
+
'no_thumbs',
|
19
|
+
],
|
20
|
+
},
|
21
|
+
],
|
22
|
+
required: [],
|
23
|
+
properties: {
|
24
|
+
name: {
|
25
|
+
title: 'Title',
|
26
|
+
description: 'The title of the navigation tree',
|
27
|
+
},
|
28
|
+
root_node: {
|
29
|
+
title: 'Root node',
|
30
|
+
description:
|
31
|
+
'You may search for and choose a folder to act as the root of the navigation tree. Leave blank to use the Plone site root.',
|
32
|
+
widget: 'object_browser',
|
33
|
+
// TODO: these don't work. Why?
|
34
|
+
mode: 'link',
|
35
|
+
selectedItemAttrs: ['Title', 'Description'],
|
36
|
+
},
|
37
|
+
portal_type: {
|
38
|
+
title: 'Filter children',
|
39
|
+
description: 'Only show child items of this content type',
|
40
|
+
choices: availableTypes,
|
41
|
+
isMulti: true,
|
42
|
+
},
|
43
|
+
includeTop: {
|
44
|
+
title: 'Include top node',
|
45
|
+
description:
|
46
|
+
"Whether or not to show the top, or 'root', node in the navigation tree. This is affected by the 'Start level' setting.",
|
47
|
+
type: 'boolean',
|
48
|
+
},
|
49
|
+
currentFolderOnly: {
|
50
|
+
title: 'Only show the contents of the current folder',
|
51
|
+
description:
|
52
|
+
'If selected, the navigation tree will only show the current folder and its children at all times.',
|
53
|
+
type: 'boolean',
|
54
|
+
},
|
55
|
+
|
56
|
+
topLevel: {
|
57
|
+
title: 'Start level',
|
58
|
+
description:
|
59
|
+
'An integer value that specifies the number of folder levels below the site root that must be exceeded before the navigation tree will display. 0 means that the navigation tree should be displayed everywhere including pages in the root of the site. 1 means the tree only shows up inside folders located in the root and downwards, never showing at the top level.',
|
60
|
+
type: 'number',
|
61
|
+
default: 1,
|
62
|
+
},
|
63
|
+
bottomLevel: {
|
64
|
+
title: 'Navigation tree depth',
|
65
|
+
description:
|
66
|
+
'How many folders should be included before the navigation tree stops. 0 means no limit. 1 only includes the root folder.',
|
67
|
+
type: 'number',
|
68
|
+
default: 0,
|
69
|
+
},
|
70
|
+
no_icons: {
|
71
|
+
title: 'Suppress icons',
|
72
|
+
description:
|
73
|
+
'If enabled, the portlet will not show document type icons.',
|
74
|
+
type: 'boolean',
|
75
|
+
},
|
76
|
+
thumb_scale: {
|
77
|
+
title: 'Override thumb scale',
|
78
|
+
description:
|
79
|
+
"Enter a valid scale name (see 'Image Handling' control panel) to override (e.g. icon, tile, thumb, mini, preview, ... ). Leave empty to use default (see 'Site' control panel).",
|
80
|
+
},
|
81
|
+
no_thumbs: {
|
82
|
+
title: 'Suppress thumbs',
|
83
|
+
type: 'boolean',
|
84
|
+
description: 'If enabled, the portlet will not show thumbs.',
|
85
|
+
},
|
86
|
+
},
|
87
|
+
};
|
88
|
+
};
|
@@ -0,0 +1,179 @@
|
|
1
|
+
import cx from 'classnames';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import React from 'react';
|
4
|
+
import { defineMessages, useIntl } from 'react-intl';
|
5
|
+
import { withRouter } from 'react-router';
|
6
|
+
import { compose } from 'redux';
|
7
|
+
import { Accordion } from 'semantic-ui-react';
|
8
|
+
|
9
|
+
import Slugger from 'github-slugger';
|
10
|
+
|
11
|
+
import { Icon, UniversalLink } from '@plone/volto/components';
|
12
|
+
import { withContentNavigation } from '@plone/volto/components/theme/Navigation/withContentNavigation';
|
13
|
+
import withEEASideMenu from '@eeacms/volto-block-toc/hocs/withEEASideMenu';
|
14
|
+
import { flattenToAppURL } from '@plone/volto/helpers';
|
15
|
+
|
16
|
+
import downIcon from '@plone/volto/icons/down-key.svg';
|
17
|
+
import upIcon from '@plone/volto/icons/up-key.svg';
|
18
|
+
|
19
|
+
const messages = defineMessages({
|
20
|
+
navigation: {
|
21
|
+
id: 'Navigation',
|
22
|
+
defaultMessage: 'Navigation',
|
23
|
+
},
|
24
|
+
});
|
25
|
+
|
26
|
+
const AccordionNavigation = ({
|
27
|
+
navigation = {},
|
28
|
+
device,
|
29
|
+
isMenuOpenOnOutsideClick,
|
30
|
+
}) => {
|
31
|
+
const { items = [], title, has_custom_name } = navigation;
|
32
|
+
const intl = useIntl();
|
33
|
+
const navOpen = ['mobile', 'tablet'].includes(device) ? false : true;
|
34
|
+
const [isNavOpen, setIsNavOpen] = React.useState(navOpen);
|
35
|
+
const [activeItems, setActiveItems] = React.useState({});
|
36
|
+
|
37
|
+
const onClickSummary = React.useCallback((e) => {
|
38
|
+
e.preventDefault();
|
39
|
+
setIsNavOpen((prev) => !prev);
|
40
|
+
}, []);
|
41
|
+
|
42
|
+
React.useEffect(() => {
|
43
|
+
if (isMenuOpenOnOutsideClick === false) setIsNavOpen(false);
|
44
|
+
}, [isMenuOpenOnOutsideClick]);
|
45
|
+
|
46
|
+
const onKeyDownSummary = React.useCallback(
|
47
|
+
(e) => {
|
48
|
+
if (e.keyCode === 13 || e.keyCode === 32) {
|
49
|
+
e.preventDefault();
|
50
|
+
onClickSummary(e);
|
51
|
+
}
|
52
|
+
},
|
53
|
+
[onClickSummary],
|
54
|
+
);
|
55
|
+
|
56
|
+
const renderItems = ({ item, level = 0 }) => {
|
57
|
+
const {
|
58
|
+
title,
|
59
|
+
href,
|
60
|
+
is_current,
|
61
|
+
is_in_path,
|
62
|
+
items: childItems,
|
63
|
+
type,
|
64
|
+
} = item;
|
65
|
+
const hasChildItems = childItems && childItems.length > 0;
|
66
|
+
const normalizedTitle = Slugger.slug(title);
|
67
|
+
|
68
|
+
const checkIfActive = () => {
|
69
|
+
return activeItems[href] !== undefined ? activeItems[href] : is_in_path;
|
70
|
+
};
|
71
|
+
|
72
|
+
const isActive = checkIfActive();
|
73
|
+
|
74
|
+
const handleTitleClick = () => {
|
75
|
+
setActiveItems((prev) => ({ ...prev, [href]: !isActive }));
|
76
|
+
};
|
77
|
+
|
78
|
+
return (
|
79
|
+
<li
|
80
|
+
className={cx({
|
81
|
+
is_in_path,
|
82
|
+
'accordion-list-title': !hasChildItems,
|
83
|
+
'accordion-list-item': hasChildItems,
|
84
|
+
})}
|
85
|
+
key={href}
|
86
|
+
>
|
87
|
+
{hasChildItems ? (
|
88
|
+
<Accordion className="default">
|
89
|
+
<Accordion.Title
|
90
|
+
active={isActive}
|
91
|
+
as={'button'}
|
92
|
+
aria-expanded={isActive}
|
93
|
+
onClick={handleTitleClick}
|
94
|
+
aria-controls={`accordion-content-${normalizedTitle}`}
|
95
|
+
id={`accordion-title-${normalizedTitle}`}
|
96
|
+
>
|
97
|
+
<span className="title-text">{title}</span>
|
98
|
+
<Icon name={isActive ? upIcon : downIcon} size="32px" />
|
99
|
+
</Accordion.Title>
|
100
|
+
<Accordion.Content
|
101
|
+
active={isActive}
|
102
|
+
id={`accordion-content-${normalizedTitle}`}
|
103
|
+
aria-labelledby={`accordion-title-${normalizedTitle}`}
|
104
|
+
role="region"
|
105
|
+
>
|
106
|
+
<ul className="accordion-list">
|
107
|
+
{childItems.map((child) =>
|
108
|
+
renderItems({ item: child, level: level + 1 }),
|
109
|
+
)}
|
110
|
+
</ul>
|
111
|
+
</Accordion.Content>
|
112
|
+
</Accordion>
|
113
|
+
) : (
|
114
|
+
<UniversalLink
|
115
|
+
href={flattenToAppURL(href)}
|
116
|
+
className={cx(`title-link contenttype-${type}`, {
|
117
|
+
current: is_current,
|
118
|
+
in_path: is_in_path,
|
119
|
+
})}
|
120
|
+
>
|
121
|
+
{title}
|
122
|
+
</UniversalLink>
|
123
|
+
)}
|
124
|
+
</li>
|
125
|
+
);
|
126
|
+
};
|
127
|
+
|
128
|
+
return items.length ? (
|
129
|
+
<>
|
130
|
+
<nav className="context-navigation">
|
131
|
+
<details open={isNavOpen}>
|
132
|
+
{/* eslint-disable-next-line */}
|
133
|
+
<summary
|
134
|
+
className="context-navigation-header accordion-header"
|
135
|
+
onClick={onClickSummary}
|
136
|
+
onKeyDown={onKeyDownSummary}
|
137
|
+
>
|
138
|
+
{has_custom_name ? title : intl.formatMessage(messages.navigation)}
|
139
|
+
<Icon name={isNavOpen ? upIcon : downIcon} size="40px" />
|
140
|
+
</summary>
|
141
|
+
<ul className="context-navigation-list accordion-list">
|
142
|
+
{items.map((item) => renderItems({ item }))}
|
143
|
+
</ul>
|
144
|
+
</details>
|
145
|
+
</nav>
|
146
|
+
</>
|
147
|
+
) : null;
|
148
|
+
};
|
149
|
+
|
150
|
+
AccordionNavigation.propTypes = {
|
151
|
+
/**
|
152
|
+
* Navigation tree returned from @contextnavigation restapi endpoint
|
153
|
+
*/
|
154
|
+
navigation: PropTypes.shape({
|
155
|
+
items: PropTypes.arrayOf(
|
156
|
+
PropTypes.shape({
|
157
|
+
title: PropTypes.string,
|
158
|
+
url: PropTypes.string,
|
159
|
+
href: PropTypes.string,
|
160
|
+
is_current: PropTypes.bool,
|
161
|
+
is_in_path: PropTypes.bool,
|
162
|
+
items: PropTypes.array,
|
163
|
+
type: PropTypes.string,
|
164
|
+
}),
|
165
|
+
),
|
166
|
+
has_custom_name: PropTypes.bool,
|
167
|
+
title: PropTypes.string,
|
168
|
+
}),
|
169
|
+
};
|
170
|
+
|
171
|
+
export default compose(
|
172
|
+
withRouter,
|
173
|
+
withContentNavigation,
|
174
|
+
(WrappedComponent) => (props) =>
|
175
|
+
withEEASideMenu(WrappedComponent)({
|
176
|
+
...props,
|
177
|
+
shouldRender: props.navigation?.items?.length > 0,
|
178
|
+
}),
|
179
|
+
)(AccordionNavigation);
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import ConnectedContextNavigation from '@plone/volto/components/theme/Navigation/ContextNavigation';
|
3
|
+
|
4
|
+
const Default = (props) => {
|
5
|
+
const { params } = props;
|
6
|
+
return <ConnectedContextNavigation params={params} />;
|
7
|
+
};
|
8
|
+
|
9
|
+
export default Default;
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import Accordion from './Accordion';
|
2
|
+
import Default from './Default';
|
3
|
+
|
4
|
+
const contextBlockVariations = [
|
5
|
+
{
|
6
|
+
id: 'default',
|
7
|
+
title: 'Listing (default)',
|
8
|
+
view: Default,
|
9
|
+
isDefault: true,
|
10
|
+
},
|
11
|
+
{
|
12
|
+
id: 'accordion',
|
13
|
+
title: 'Accordion',
|
14
|
+
view: Accordion,
|
15
|
+
},
|
16
|
+
];
|
17
|
+
|
18
|
+
export default contextBlockVariations;
|
@@ -11,8 +11,8 @@ import { ReactEditor, Editable, Slate, withReact } from 'slate-react';
|
|
11
11
|
import config from '@plone/volto/registry';
|
12
12
|
import { SidebarPortal } from '@plone/volto/components';
|
13
13
|
import { BodyClass } from '@plone/volto/helpers';
|
14
|
-
import
|
15
|
-
import
|
14
|
+
import View from '@eeacms/volto-eea-website-theme/components/manage/Blocks/Title/View';
|
15
|
+
import BlockDataForm from '@plone/volto/components/manage/Form/BlockDataForm';
|
16
16
|
import schema from './schema';
|
17
17
|
|
18
18
|
const messages = defineMessages({
|
@@ -165,8 +165,9 @@ export const TitleBlockEdit = (props) => {
|
|
165
165
|
return (
|
166
166
|
<React.Fragment>
|
167
167
|
<BodyClass className="with-title-block" />
|
168
|
-
<
|
168
|
+
<View
|
169
169
|
{...props}
|
170
|
+
isEditMode={true}
|
170
171
|
banner={{
|
171
172
|
title: {
|
172
173
|
view: (
|
@@ -185,7 +186,7 @@ export const TitleBlockEdit = (props) => {
|
|
185
186
|
fluid
|
186
187
|
/>
|
187
188
|
<SidebarPortal selected={props.selected}>
|
188
|
-
<
|
189
|
+
<BlockDataForm
|
189
190
|
schema={schema}
|
190
191
|
title={schema.title}
|
191
192
|
onChangeField={(id, value) => {
|
@@ -194,7 +195,9 @@ export const TitleBlockEdit = (props) => {
|
|
194
195
|
[id]: value,
|
195
196
|
});
|
196
197
|
}}
|
198
|
+
onChangeBlock={props.onChangeBlock}
|
197
199
|
formData={props.data}
|
200
|
+
block={props.block}
|
198
201
|
/>
|
199
202
|
</SidebarPortal>
|
200
203
|
</React.Fragment>
|