@eeacms/volto-eea-website-policy 0.2.5 → 0.3.1

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 CHANGED
@@ -4,8 +4,31 @@ 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
+ #### [0.3.1](https://github.com/eea/volto-eea-website-policy/compare/0.3.0...0.3.1)
8
+
9
+ - feature(navigation): addde context navigation block [`2b0b6f6`](https://github.com/eea/volto-eea-website-policy/commit/2b0b6f616adf85ab41365a7cf6ee6e690ff9fd0c)
10
+
11
+ #### [0.3.0](https://github.com/eea/volto-eea-website-policy/compare/0.2.6...0.3.0)
12
+
13
+ > 6 July 2022
14
+
15
+ - change(teaser): enabled theming for icon and text color [`#13`](https://github.com/eea/volto-eea-website-policy/pull/13)
16
+ - change(package): bump release version [`1b00439`](https://github.com/eea/volto-eea-website-policy/commit/1b0043933442bb73c1042dce644a2c09e5f210f4)
17
+ - change(item): enable theming for icon and text color and added tertiary option [`58c2d28`](https://github.com/eea/volto-eea-website-policy/commit/58c2d2864fe94c9e7808064b61d3b6c4e6fccbb1)
18
+ - change(item): commented sizes too small for item icons and enabled tertiary theme [`0f02d7d`](https://github.com/eea/volto-eea-website-policy/commit/0f02d7d6204b068b78c3f977a561782a19b6f79e)
19
+
20
+ #### [0.2.6](https://github.com/eea/volto-eea-website-policy/compare/0.2.5...0.2.6)
21
+
22
+ > 1 July 2022
23
+
24
+ - Fix Cannot read properties of undefined (reading 'translations') [`8e7b8b8`](https://github.com/eea/volto-eea-website-policy/commit/8e7b8b8533b14f173d77783fe2d0b517c29c5937)
25
+ - Customize Toolbar.jsx - copied unchanged from @plone/volto 16.0.0.alpha.11 [`b7add4f`](https://github.com/eea/volto-eea-website-policy/commit/b7add4faa8ef2dde7d77489fc8bc431cbb023314)
26
+
7
27
  #### [0.2.5](https://github.com/eea/volto-eea-website-policy/compare/0.2.4...0.2.5)
8
28
 
29
+ > 23 June 2022
30
+
31
+ - Rounded Card variation and disable ImageCards block [`#11`](https://github.com/eea/volto-eea-website-policy/pull/11)
9
32
  - Rounded card via style wrapper [`6728684`](https://github.com/eea/volto-eea-website-policy/commit/67286844b00902aa4c6b316b50be35db95c531f0)
10
33
  - Revert "Rounded Card variation - refs #148723" [`0168a86`](https://github.com/eea/volto-eea-website-policy/commit/0168a86fa644a9b848e37c7f5054eb4308c36784)
11
34
  - Disable Image Cards block [`3ed8dc3`](https://github.com/eea/volto-eea-website-policy/commit/3ed8dc311cad8e30a8c918ecec7b21cc99260c50)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-eea-website-policy",
3
- "version": "0.2.5",
3
+ "version": "0.3.1",
4
4
  "description": "@eeacms/volto-eea-website-policy: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import { EditSchema } from './schema';
3
+ import { InlineForm, SidebarPortal } from '@plone/volto/components';
4
+ import ContextNavigationView from './ContextNavigationView';
5
+
6
+ const ContextNavigationFillView = (props) => {
7
+ const schema = EditSchema();
8
+ return (
9
+ <>
10
+ <h3>Context navigation</h3>
11
+ <ContextNavigationView {...props} />{' '}
12
+ <SidebarPortal selected={props.selected}>
13
+ {props.selected && (
14
+ <InlineForm
15
+ title={schema.title}
16
+ schema={schema}
17
+ formData={props.data}
18
+ onChangeField={(id, value) => {
19
+ props.onChangeBlock(props.block, {
20
+ ...props.data,
21
+ [id]: value,
22
+ });
23
+ }}
24
+ />
25
+ )}
26
+ </SidebarPortal>
27
+ </>
28
+ );
29
+ };
30
+
31
+ export default ContextNavigationFillView;
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import ConnectedContextNavigation from '@plone/volto/components/theme/Navigation/ContextNavigation';
3
+ import { flattenToAppURL } from '@plone/volto/helpers';
4
+
5
+ const ContextNavigationView = ({ data = {} }) => {
6
+ const navProps = { ...data };
7
+ const root_path = data?.root_node?.[0]?.['@id'];
8
+ if (root_path) navProps['root_path'] = flattenToAppURL(root_path);
9
+
10
+ return (
11
+ <>
12
+ <ConnectedContextNavigation params={navProps} />
13
+ </>
14
+ );
15
+ };
16
+
17
+ export default ContextNavigationView;
@@ -0,0 +1,26 @@
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
+
6
+ export default (config) => {
7
+ config.blocks.blocksConfig.contextNavigation = {
8
+ id: 'contextNavigation',
9
+ title: 'Navigation',
10
+ icon: codeSVG,
11
+ group: 'site',
12
+ view: ContextNavigationView,
13
+ edit: ContextNavigationEdit,
14
+ schema: BlockSettingsSchema,
15
+ restricted: false,
16
+ mostUsed: true,
17
+ blockHasOwnFocusManagement: true,
18
+ sidebarTab: 1,
19
+ security: {
20
+ addPermission: [],
21
+ view: [],
22
+ },
23
+ };
24
+
25
+ return config;
26
+ };
@@ -0,0 +1,81 @@
1
+ export const EditSchema = () => {
2
+ return {
3
+ title: 'Navigation',
4
+ fieldsets: [
5
+ {
6
+ id: 'default',
7
+ title: 'Default',
8
+ fields: [
9
+ 'name',
10
+ 'root_node',
11
+ 'includeTop',
12
+ 'currentFolderOnly',
13
+ 'topLevel',
14
+ 'bottomLevel',
15
+ 'no_icons',
16
+ 'thumb_scale',
17
+ 'no_thumbs',
18
+ ],
19
+ },
20
+ ],
21
+ required: [],
22
+ properties: {
23
+ name: {
24
+ title: 'Title',
25
+ description: 'The title of the navigation tree',
26
+ },
27
+ root_node: {
28
+ title: 'Root node',
29
+ description:
30
+ '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.',
31
+ widget: 'object_browser',
32
+ // TODO: these don't work. Why?
33
+ mode: 'link',
34
+ selectedItemAttrs: ['Title', 'Description'],
35
+ },
36
+ includeTop: {
37
+ title: 'Include top node',
38
+ description:
39
+ "Whether or not to show the top, or 'root', node in the navigation tree. This is affected by the 'Start level' setting.",
40
+ type: 'boolean',
41
+ },
42
+ currentFolderOnly: {
43
+ title: 'Only show the contents of the current folder',
44
+ description:
45
+ 'If selected, the navigation tree will only show the current folder and its children at all times.',
46
+ type: 'boolean',
47
+ },
48
+
49
+ topLevel: {
50
+ title: 'Start level',
51
+ description:
52
+ '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.',
53
+ type: 'number',
54
+ default: 1,
55
+ },
56
+ bottomLevel: {
57
+ title: 'Navigation tree depth',
58
+ description:
59
+ 'How many folders should be included before the navigation tree stops. 0 means no limit. 1 only includes the root folder.',
60
+ type: 'number',
61
+ default: 0,
62
+ },
63
+ no_icons: {
64
+ title: 'Supress icons',
65
+ description:
66
+ 'If enabled, the portlet will not show document type icons.',
67
+ type: 'boolean',
68
+ },
69
+ thumb_scale: {
70
+ title: 'Override thumb scale',
71
+ description:
72
+ "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).",
73
+ },
74
+ no_thumbs: {
75
+ title: 'Supress thumbs',
76
+ type: 'boolean',
77
+ description: 'If enabled, the portlet will not show thumbs.',
78
+ },
79
+ },
80
+ };
81
+ };
@@ -12,7 +12,13 @@ export default ({ data }) => {
12
12
  ? [{ id: 'image', title: 'Image', fields: ['image', 'imageSize'] }]
13
13
  : []),
14
14
  ...(assetType === 'icon'
15
- ? [{ id: 'icon', title: 'Icon', fields: ['icon', 'iconSize'] }]
15
+ ? [
16
+ {
17
+ id: 'icon',
18
+ title: 'Icon',
19
+ fields: ['icon', 'iconSize', 'iconTheme'],
20
+ },
21
+ ]
16
22
  : []),
17
23
  ],
18
24
  properties: {
@@ -31,10 +37,11 @@ export default ({ data }) => {
31
37
  imageSize: {
32
38
  title: 'Image size',
33
39
  choices: [
34
- ['mini', 'Mini'],
35
- ['tile', 'Tile'],
36
- ['tiny', 'Tiny'],
37
- ['small', 'Small'],
40
+ // commented as they were too small to use as item icons
41
+ // ['mini', 'Mini'],
42
+ // ['tile', 'Tile'],
43
+ // ['tiny', 'Tiny'],
44
+ // ['small', 'Small'],
38
45
  ['large', 'Large'],
39
46
  ['big', 'Big'],
40
47
  ['huge', 'Huge'],
@@ -63,6 +70,7 @@ export default ({ data }) => {
63
70
  choices: [
64
71
  ['primary', 'Primary'],
65
72
  ['secondary', 'Secondary'],
73
+ ['tertiary', 'Tertiary'],
66
74
  ],
67
75
  },
68
76
  },
@@ -86,6 +94,7 @@ export const stylingSchema = ({ intl }) => ({
86
94
  choices: [
87
95
  ['primary', 'Primary'],
88
96
  ['secondary', 'Secondary'],
97
+ ['tertiary', 'Tertiary'],
89
98
  ],
90
99
  },
91
100
  verticalAlign: {
@@ -0,0 +1,589 @@
1
+ /**
2
+ * Toolbar component.
3
+ * @module components/manage/Toolbar/Toolbar
4
+ */
5
+
6
+ import React, { Component } from 'react';
7
+ import { defineMessages, injectIntl } from 'react-intl';
8
+ import PropTypes from 'prop-types';
9
+ import { Link } from 'react-router-dom';
10
+ import jwtDecode from 'jwt-decode';
11
+ import { connect } from 'react-redux';
12
+ import { compose } from 'redux';
13
+ import { doesNodeContainClick } from 'semantic-ui-react/dist/commonjs/lib';
14
+ import { withCookies } from 'react-cookie';
15
+ import { filter, find } from 'lodash';
16
+ import cx from 'classnames';
17
+ import config from '@plone/volto/registry';
18
+
19
+ import More from '@plone/volto/components/manage/Toolbar/More';
20
+ import PersonalTools from '@plone/volto/components/manage/Toolbar/PersonalTools';
21
+ import Types from '@plone/volto/components/manage/Toolbar/Types';
22
+ import PersonalInformation from '@plone/volto/components/manage/Preferences/PersonalInformation';
23
+ import PersonalPreferences from '@plone/volto/components/manage/Preferences/PersonalPreferences';
24
+ import StandardWrapper from '@plone/volto/components/manage/Toolbar/StandardWrapper';
25
+ import {
26
+ getTypes,
27
+ listActions,
28
+ setExpandedToolbar,
29
+ unlockContent,
30
+ } from '@plone/volto/actions';
31
+ import { Icon } from '@plone/volto/components';
32
+ import { BodyClass, getBaseUrl, getCookieOptions } from '@plone/volto/helpers';
33
+ import { Pluggable } from '@plone/volto/components/manage/Pluggable';
34
+
35
+ import penSVG from '@plone/volto/icons/pen.svg';
36
+ import unlockSVG from '@plone/volto/icons/unlock.svg';
37
+ import folderSVG from '@plone/volto/icons/folder.svg';
38
+ import addSVG from '@plone/volto/icons/add-document.svg';
39
+ import moreSVG from '@plone/volto/icons/more.svg';
40
+ import userSVG from '@plone/volto/icons/user.svg';
41
+ import clearSVG from '@plone/volto/icons/clear.svg';
42
+
43
+ const messages = defineMessages({
44
+ edit: {
45
+ id: 'Edit',
46
+ defaultMessage: 'Edit',
47
+ },
48
+ contents: {
49
+ id: 'Contents',
50
+ defaultMessage: 'Contents',
51
+ },
52
+ add: {
53
+ id: 'Add',
54
+ defaultMessage: 'Add',
55
+ },
56
+ more: {
57
+ id: 'More',
58
+ defaultMessage: 'More',
59
+ },
60
+ personalTools: {
61
+ id: 'Personal tools',
62
+ defaultMessage: 'Personal tools',
63
+ },
64
+ shrinkToolbar: {
65
+ id: 'Shrink toolbar',
66
+ defaultMessage: 'Shrink toolbar',
67
+ },
68
+ personalInformation: {
69
+ id: 'Personal Information',
70
+ defaultMessage: 'Personal Information',
71
+ },
72
+ personalPreferences: {
73
+ id: 'Personal Preferences',
74
+ defaultMessage: 'Personal Preferences',
75
+ },
76
+ collection: {
77
+ id: 'Collection',
78
+ defaultMessage: 'Collection',
79
+ },
80
+ file: {
81
+ id: 'File',
82
+ defaultMessage: 'File',
83
+ },
84
+ link: {
85
+ id: 'Link',
86
+ defaultMessage: 'Link',
87
+ },
88
+ newsItem: {
89
+ id: 'News Item',
90
+ defaultMessage: 'News Item',
91
+ },
92
+ page: {
93
+ id: 'Page',
94
+ defaultMessage: 'Page',
95
+ },
96
+ back: {
97
+ id: 'Back',
98
+ defaultMessage: 'Back',
99
+ },
100
+ unlock: {
101
+ id: 'Unlock',
102
+ defaultMessage: 'Unlock',
103
+ },
104
+ });
105
+
106
+ const toolbarComponents = {
107
+ personalTools: { component: PersonalTools, wrapper: null },
108
+ more: { component: More, wrapper: null },
109
+ types: { component: Types, wrapper: null, contentAsProps: true },
110
+ profile: {
111
+ component: PersonalInformation,
112
+ wrapper: StandardWrapper,
113
+ wrapperTitle: messages.personalInformation,
114
+ hideToolbarBody: true,
115
+ },
116
+ preferences: {
117
+ component: PersonalPreferences,
118
+ wrapper: StandardWrapper,
119
+ wrapperTitle: messages.personalPreferences,
120
+ hideToolbarBody: true,
121
+ },
122
+ };
123
+
124
+ /**
125
+ * Toolbar container class.
126
+ * @class Toolbar
127
+ * @extends Component
128
+ */
129
+ class Toolbar extends Component {
130
+ /**
131
+ * Property types.
132
+ * @property {Object} propTypes Property types.
133
+ * @static
134
+ */
135
+ static propTypes = {
136
+ actions: PropTypes.shape({
137
+ object: PropTypes.arrayOf(PropTypes.object),
138
+ object_buttons: PropTypes.arrayOf(PropTypes.object),
139
+ user: PropTypes.arrayOf(PropTypes.object),
140
+ }),
141
+ token: PropTypes.string,
142
+ userId: PropTypes.string,
143
+ pathname: PropTypes.string.isRequired,
144
+ content: PropTypes.shape({
145
+ '@type': PropTypes.string,
146
+ is_folderish: PropTypes.bool,
147
+ review_state: PropTypes.string,
148
+ }),
149
+ getTypes: PropTypes.func.isRequired,
150
+ types: PropTypes.arrayOf(
151
+ PropTypes.shape({
152
+ '@id': PropTypes.string,
153
+ addable: PropTypes.bool,
154
+ title: PropTypes.string,
155
+ }),
156
+ ),
157
+ listActions: PropTypes.func.isRequired,
158
+ unlockContent: PropTypes.func,
159
+ unlockRequest: PropTypes.objectOf(PropTypes.any),
160
+ inner: PropTypes.element.isRequired,
161
+ hideDefaultViewButtons: PropTypes.bool,
162
+ };
163
+
164
+ /**
165
+ * Default properties.
166
+ * @property {Object} defaultProps Default properties.
167
+ * @static
168
+ */
169
+ static defaultProps = {
170
+ actions: null,
171
+ token: null,
172
+ userId: null,
173
+ content: null,
174
+ hideDefaultViewButtons: false,
175
+ types: [],
176
+ };
177
+
178
+ toolbarWindow = React.createRef();
179
+
180
+ constructor(props) {
181
+ super(props);
182
+ const { cookies } = props;
183
+ this.state = {
184
+ expanded: cookies.get('toolbar_expanded') !== 'false',
185
+ showMenu: false,
186
+ menuStyle: {},
187
+ menuComponents: [],
188
+ loadedComponents: [],
189
+ hideToolbarBody: false,
190
+ };
191
+ }
192
+
193
+ /**
194
+ * Component will mount
195
+ * @method componentDidMount
196
+ * @returns {undefined}
197
+ */
198
+ componentDidMount() {
199
+ this.props.listActions(getBaseUrl(this.props.pathname));
200
+ this.props.getTypes(getBaseUrl(this.props.pathname));
201
+ this.props.setExpandedToolbar(this.state.expanded);
202
+ document.addEventListener('mousedown', this.handleClickOutside, false);
203
+ }
204
+
205
+ /**
206
+ * Component will receive props
207
+ * @method componentWillReceiveProps
208
+ * @param {Object} nextProps Next properties
209
+ * @returns {undefined}
210
+ */
211
+ UNSAFE_componentWillReceiveProps(nextProps) {
212
+ if (nextProps.pathname !== this.props.pathname) {
213
+ this.props.listActions(getBaseUrl(nextProps.pathname));
214
+ this.props.getTypes(getBaseUrl(nextProps.pathname));
215
+ }
216
+
217
+ // Unlock
218
+ if (this.props.unlockRequest.loading && nextProps.unlockRequest.loaded) {
219
+ this.props.listActions(getBaseUrl(nextProps.pathname));
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Component will receive props
225
+ * @method componentWillUnmount
226
+ * @returns {undefined}
227
+ */
228
+ componentWillUnmount() {
229
+ document.removeEventListener('mousedown', this.handleClickOutside, false);
230
+ }
231
+
232
+ handleShrink = () => {
233
+ const { cookies } = this.props;
234
+ cookies.set('toolbar_expanded', !this.state.expanded, getCookieOptions());
235
+ this.setState(
236
+ (state) => ({ expanded: !state.expanded }),
237
+ () => this.props.setExpandedToolbar(this.state.expanded),
238
+ );
239
+ };
240
+
241
+ closeMenu = () =>
242
+ this.setState(() => ({ showMenu: false, loadedComponents: [] }));
243
+
244
+ loadComponent = (type) => {
245
+ const { loadedComponents } = this.state;
246
+ if (!this.state.loadedComponents.includes(type)) {
247
+ this.setState({
248
+ loadedComponents: [...loadedComponents, type],
249
+ hideToolbarBody: toolbarComponents[type].hideToolbarBody || false,
250
+ });
251
+ }
252
+ };
253
+
254
+ unloadComponent = () => {
255
+ this.setState((state) => ({
256
+ loadedComponents: state.loadedComponents.slice(0, -1),
257
+ hideToolbarBody:
258
+ toolbarComponents[
259
+ state.loadedComponents[state.loadedComponents.length - 2]
260
+ ].hideToolbarBody || false,
261
+ }));
262
+ };
263
+
264
+ toggleMenu = (e, selector) => {
265
+ if (this.state.showMenu) {
266
+ this.closeMenu();
267
+ return;
268
+ }
269
+ // PersonalTools always shows at bottom
270
+ if (selector === 'personalTools') {
271
+ this.setState((state) => ({
272
+ showMenu: !state.showMenu,
273
+ menuStyle: { bottom: 0 },
274
+ }));
275
+ } else {
276
+ this.setState((state) => ({
277
+ showMenu: !state.showMenu,
278
+ menuStyle: { top: 0 },
279
+ }));
280
+ }
281
+ this.loadComponent(selector);
282
+ };
283
+
284
+ handleClickOutside = (e) => {
285
+ if (this.pusher && doesNodeContainClick(this.pusher, e)) return;
286
+ this.closeMenu();
287
+ };
288
+
289
+ unlock = (e) => {
290
+ this.props.unlockContent(getBaseUrl(this.props.pathname), true);
291
+ };
292
+
293
+ /**
294
+ * Render method.
295
+ * @method render
296
+ * @returns {string} Markup for the component.
297
+ */
298
+ render() {
299
+ const path = getBaseUrl(this.props.pathname);
300
+ const lock = this.props.content?.lock;
301
+ const unlockAction =
302
+ lock?.locked && lock?.stealable && lock?.creator !== this.props.userId;
303
+ const editAction =
304
+ !unlockAction && find(this.props.actions.object, { id: 'edit' });
305
+ const folderContentsAction = find(this.props.actions.object, {
306
+ id: 'folderContents',
307
+ });
308
+ const { expanded } = this.state;
309
+
310
+ return (
311
+ this.props.token && (
312
+ <>
313
+ <BodyClass
314
+ className={expanded ? 'has-toolbar' : 'has-toolbar-collapsed'}
315
+ />
316
+ <div
317
+ style={this.state.menuStyle}
318
+ className={
319
+ this.state.showMenu ? 'toolbar-content show' : 'toolbar-content'
320
+ }
321
+ ref={this.toolbarWindow}
322
+ >
323
+ {this.state.showMenu && (
324
+ // This sets the scroll locker in the body tag in mobile
325
+ <BodyClass className="has-toolbar-menu-open" />
326
+ )}
327
+ <div
328
+ className="pusher-puller"
329
+ ref={(node) => (this.pusher = node)}
330
+ style={{
331
+ transform: this.toolbarWindow.current
332
+ ? `translateX(-${
333
+ (this.state.loadedComponents.length - 1) *
334
+ this.toolbarWindow.current.getBoundingClientRect().width
335
+ }px)`
336
+ : null,
337
+ }}
338
+ >
339
+ {this.state.loadedComponents.map((component, index) =>
340
+ (() => {
341
+ const ToolbarComponent =
342
+ toolbarComponents[component].component;
343
+ const WrapperComponent = toolbarComponents[component].wrapper;
344
+ const haveActions =
345
+ toolbarComponents[component].hideToolbarBody;
346
+ const title =
347
+ toolbarComponents[component].wrapperTitle &&
348
+ this.props.intl.formatMessage(
349
+ toolbarComponents[component].wrapperTitle,
350
+ );
351
+ if (WrapperComponent) {
352
+ return (
353
+ <WrapperComponent
354
+ componentName={component}
355
+ componentTitle={title}
356
+ pathname={this.props.pathname}
357
+ loadComponent={this.loadComponent}
358
+ unloadComponent={this.unloadComponent}
359
+ componentIndex={index}
360
+ theToolbar={this.toolbarWindow}
361
+ key={`personalToolsComponent-${index}`}
362
+ closeMenu={this.closeMenu}
363
+ hasActions={haveActions}
364
+ >
365
+ <ToolbarComponent
366
+ pathname={this.props.pathname}
367
+ loadComponent={this.loadComponent}
368
+ unloadComponent={this.unloadComponent}
369
+ componentIndex={index}
370
+ theToolbar={this.toolbarWindow}
371
+ closeMenu={this.closeMenu}
372
+ isToolbarEmbedded
373
+ />
374
+ </WrapperComponent>
375
+ );
376
+ } else {
377
+ return (
378
+ <ToolbarComponent
379
+ pathname={this.props.pathname}
380
+ loadComponent={this.loadComponent}
381
+ unloadComponent={this.unloadComponent}
382
+ componentIndex={index}
383
+ theToolbar={this.toolbarWindow}
384
+ key={`personalToolsComponent-${index}`}
385
+ closeMenu={this.closeMenu}
386
+ content={
387
+ toolbarComponents[component].contentAsProps
388
+ ? this.props.content
389
+ : null
390
+ }
391
+ />
392
+ );
393
+ }
394
+ })(),
395
+ )}
396
+ </div>
397
+ </div>
398
+ <div className={this.state.expanded ? 'toolbar expanded' : 'toolbar'}>
399
+ <div className="toolbar-body">
400
+ <div className="toolbar-actions">
401
+ {this.props.hideDefaultViewButtons && this.props.inner && (
402
+ <>{this.props.inner}</>
403
+ )}
404
+ {!this.props.hideDefaultViewButtons && (
405
+ <>
406
+ {unlockAction && (
407
+ <button
408
+ aria-label={this.props.intl.formatMessage(
409
+ messages.unlock,
410
+ )}
411
+ className="unlock"
412
+ onClick={(e) => this.unlock(e)}
413
+ tabIndex={0}
414
+ >
415
+ <Icon
416
+ name={unlockSVG}
417
+ size="30px"
418
+ className="unlock"
419
+ title={this.props.intl.formatMessage(messages.unlock)}
420
+ />
421
+ </button>
422
+ )}
423
+
424
+ {editAction && (
425
+ <Link
426
+ aria-label={this.props.intl.formatMessage(
427
+ messages.edit,
428
+ )}
429
+ className="edit"
430
+ to={`${path}/edit`}
431
+ >
432
+ <Icon
433
+ name={penSVG}
434
+ size="30px"
435
+ className="circled"
436
+ title={this.props.intl.formatMessage(messages.edit)}
437
+ />
438
+ </Link>
439
+ )}
440
+ {this.props.content &&
441
+ this.props.content.is_folderish &&
442
+ folderContentsAction &&
443
+ !this.props.pathname.endsWith('/contents') && (
444
+ <Link
445
+ aria-label={this.props.intl.formatMessage(
446
+ messages.contents,
447
+ )}
448
+ to={`${path}/contents`}
449
+ >
450
+ <Icon
451
+ name={folderSVG}
452
+ size="30px"
453
+ title={this.props.intl.formatMessage(
454
+ messages.contents,
455
+ )}
456
+ />
457
+ </Link>
458
+ )}
459
+ {this.props.content &&
460
+ this.props.content.is_folderish &&
461
+ folderContentsAction &&
462
+ this.props.pathname.endsWith('/contents') && (
463
+ <Link
464
+ to={`${path}`}
465
+ aria-label={this.props.intl.formatMessage(
466
+ messages.back,
467
+ )}
468
+ >
469
+ <Icon
470
+ name={clearSVG}
471
+ className="contents circled"
472
+ size="30px"
473
+ title={this.props.intl.formatMessage(messages.back)}
474
+ />
475
+ </Link>
476
+ )}
477
+ {this.props.content &&
478
+ ((this.props.content.is_folderish &&
479
+ this.props.types.length > 0) ||
480
+ (config.settings.isMultilingual &&
481
+ this.props.content['@components']?.translations)) && (
482
+ <button
483
+ className="add"
484
+ aria-label={this.props.intl.formatMessage(
485
+ messages.add,
486
+ )}
487
+ onClick={(e) => this.toggleMenu(e, 'types')}
488
+ tabIndex={0}
489
+ id="toolbar-add"
490
+ >
491
+ <Icon
492
+ name={addSVG}
493
+ size="30px"
494
+ title={this.props.intl.formatMessage(messages.add)}
495
+ />
496
+ </button>
497
+ )}
498
+ <div className="toolbar-button-spacer" />
499
+ <button
500
+ className="more"
501
+ aria-label={this.props.intl.formatMessage(messages.more)}
502
+ onClick={(e) => this.toggleMenu(e, 'more')}
503
+ tabIndex={0}
504
+ id="toolbar-more"
505
+ >
506
+ <Icon
507
+ className="mobile hidden"
508
+ name={moreSVG}
509
+ size="30px"
510
+ title={this.props.intl.formatMessage(messages.more)}
511
+ />
512
+ {this.state.showMenu ? (
513
+ <Icon
514
+ className="mobile only"
515
+ name={clearSVG}
516
+ size="30px"
517
+ />
518
+ ) : (
519
+ <Icon
520
+ className="mobile only"
521
+ name={moreSVG}
522
+ size="30px"
523
+ />
524
+ )}
525
+ </button>
526
+ </>
527
+ )}
528
+ </div>
529
+ <div className="toolbar-bottom">
530
+ <Pluggable name="main.toolbar.bottom" />
531
+ {!this.props.hideDefaultViewButtons && (
532
+ <button
533
+ className="user"
534
+ aria-label={this.props.intl.formatMessage(
535
+ messages.personalTools,
536
+ )}
537
+ onClick={(e) => this.toggleMenu(e, 'personalTools')}
538
+ tabIndex={0}
539
+ id="toolbar-personal"
540
+ >
541
+ <Icon
542
+ name={userSVG}
543
+ size="30px"
544
+ title={this.props.intl.formatMessage(
545
+ messages.personalTools,
546
+ )}
547
+ />
548
+ </button>
549
+ )}
550
+ </div>
551
+ </div>
552
+ <div className="toolbar-handler">
553
+ <button
554
+ aria-label={this.props.intl.formatMessage(
555
+ messages.shrinkToolbar,
556
+ )}
557
+ className={cx({
558
+ [this.props.content?.review_state]: this.props.content
559
+ ?.review_state,
560
+ })}
561
+ onClick={this.handleShrink}
562
+ />
563
+ </div>
564
+ </div>
565
+ <div className="pusher" />
566
+ </>
567
+ )
568
+ );
569
+ }
570
+ }
571
+
572
+ export default compose(
573
+ injectIntl,
574
+ withCookies,
575
+ connect(
576
+ (state, props) => ({
577
+ actions: state.actions.actions,
578
+ token: state.userSession.token,
579
+ userId: state.userSession.token
580
+ ? jwtDecode(state.userSession.token).sub
581
+ : '',
582
+ content: state.content.data,
583
+ pathname: props.pathname,
584
+ types: filter(state.types.types, 'addable'),
585
+ unlockRequest: state.content.unlock,
586
+ }),
587
+ { getTypes, listActions, setExpandedToolbar, unlockContent },
588
+ ),
589
+ )(Toolbar);
package/src/index.js CHANGED
@@ -2,6 +2,7 @@ import { runtimeConfig } from '@plone/volto/runtime_config';
2
2
  import installCallout from 'volto-slate/editor/plugins/Callout';
3
3
  import installItemBlock from '@eeacms/volto-eea-website-policy/components/Blocks/Item';
4
4
  import customizeTeaserBlock from '@eeacms/volto-eea-website-policy/components/Blocks/Teaser';
5
+ import installContextNavigationBlock from '@eeacms/volto-eea-website-policy/components/Blocks/ContextNavigation';
5
6
 
6
7
  const applyConfig = (config) => {
7
8
  // if (process.env.NODE_ENV === 'production') {
@@ -99,10 +100,11 @@ const applyConfig = (config) => {
99
100
  }
100
101
 
101
102
  // Custom blocks
102
- config = [installItemBlock, customizeTeaserBlock].reduce(
103
- (acc, apply) => apply(acc),
104
- config,
105
- );
103
+ config = [
104
+ installItemBlock,
105
+ installContextNavigationBlock,
106
+ customizeTeaserBlock,
107
+ ].reduce((acc, apply) => apply(acc), config);
106
108
  config.blocks.blocksConfig.item.mostUsed = true;
107
109
 
108
110
  // Disable some blocks