@plone/volto 17.0.0-alpha.25 → 17.0.0-alpha.26
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/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +52 -5
- package/README.md +8 -7
- package/cypress/support/commands.js +12 -9
- package/cypress.config.js +1 -0
- package/locales/ca/LC_MESSAGES/volto.po +36 -15
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +36 -15
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +35 -14
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +65 -44
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +35 -14
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +35 -14
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +36 -15
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +35 -14
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +35 -14
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +36 -15
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +36 -15
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +35 -14
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +36 -15
- package/locales/ro.json +1 -1
- package/locales/volto.pot +35 -14
- package/locales/zh_CN/LC_MESSAGES/volto.po +36 -15
- package/locales/zh_CN.json +1 -1
- package/package.json +4 -4
- package/packages/volto-slate/package.json +1 -1
- package/packages/volto-slate/src/editor/render.jsx +2 -3
- package/src/actions/index.js +3 -0
- package/src/actions/navroot/navroot.js +16 -0
- package/src/actions/navroot/navroot.test.js +15 -0
- package/src/actions/site/site.js +16 -0
- package/src/actions/site/site.test.js +15 -0
- package/src/actions/userSession/userSession.js +17 -1
- package/src/components/manage/Blocks/Block/Settings.jsx +2 -0
- package/src/components/manage/Blocks/Block/Settings.test.jsx +90 -0
- package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +1 -1
- package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +42 -25
- package/src/components/manage/Blocks/ToC/View.jsx +75 -13
- package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.jsx +2 -12
- package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +65 -38
- package/src/components/manage/Controlpanels/Rules/AddRule.jsx +1 -1
- package/src/components/manage/Controlpanels/Rules/EditRule.jsx +1 -1
- package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +95 -5
- package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +116 -103
- package/src/components/manage/Form/BlockDataForm.jsx +3 -2
- package/src/components/manage/Form/BlockDataForm.test.jsx +34 -2
- package/src/components/manage/LinksToItem/LinksToItem.test.jsx +4 -1
- package/src/components/manage/Messages/Messages.jsx +32 -99
- package/src/components/manage/Messages/Messages.test.jsx +0 -1
- package/src/components/manage/Sharing/Sharing.jsx +39 -16
- package/src/components/manage/UniversalLink/UniversalLink.jsx +4 -6
- package/src/components/manage/Widgets/ArrayWidget.jsx +3 -1
- package/src/components/manage/Widgets/ArrayWidget.test.jsx +45 -1
- package/src/components/manage/Widgets/RegistryImageWidget.jsx +210 -0
- package/src/components/manage/Widgets/RegistryImageWidget.test.jsx +91 -0
- package/src/components/manage/Widgets/SelectWidget.jsx +15 -1
- package/src/components/manage/Widgets/SelectWidget.test.jsx +45 -1
- package/src/components/theme/ContentMetadataTags/ContentMetadataTags.jsx +37 -3
- package/src/components/theme/Login/Login.jsx +159 -241
- package/src/components/theme/Logo/Logo.Multilingual.test.jsx +131 -1
- package/src/components/theme/Logo/Logo.jsx +35 -29
- package/src/components/theme/Logo/Logo.test.jsx +135 -1
- package/src/components/theme/Logout/Logout.jsx +1 -1
- package/src/components/theme/Navigation/Navigation.jsx +86 -171
- package/src/components/theme/SearchWidget/SearchWidget.jsx +15 -3
- package/src/components/theme/SearchWidget/SearchWidget.test.jsx +8 -0
- package/src/components/theme/View/View.jsx +2 -0
- package/src/config/ControlPanels.js +0 -1
- package/src/config/Widgets.jsx +2 -0
- package/src/config/index.js +15 -3
- package/src/constants/ActionTypes.js +3 -0
- package/src/express-middleware/images.js +1 -0
- package/src/helpers/MessageLabels/MessageLabels.js +26 -4
- package/src/helpers/Site/index.js +21 -0
- package/src/helpers/index.js +1 -0
- package/src/reducers/index.js +4 -0
- package/src/reducers/navroot/navroot.js +79 -0
- package/src/reducers/navroot/navroot.test.js +110 -0
- package/src/reducers/site/site.js +51 -0
- package/src/reducers/site/site.test.js +67 -0
- package/src/reducers/userSession/userSession.js +15 -1
- package/test-setup-config.js +1 -0
- package/theme/themes/pastanaga/elements/input.overrides +5 -1
- package/theme/themes/pastanaga/extras/login.less +3 -0
- package/webpack-plugins/webpack-less-plugin.js +19 -0
|
@@ -2,25 +2,18 @@
|
|
|
2
2
|
* Logo component.
|
|
3
3
|
* @module components/theme/Logo/Logo
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
import { defineMessages, useIntl } from 'react-intl';
|
|
5
|
+
import { useEffect } from 'react';
|
|
7
6
|
import { Image } from 'semantic-ui-react';
|
|
8
|
-
import {
|
|
9
|
-
import config from '@plone/volto/registry';
|
|
10
|
-
import { UniversalLink } from '@plone/volto/components';
|
|
11
|
-
import { toBackendLang } from '@plone/volto/helpers';
|
|
7
|
+
import { ConditionalLink } from '@plone/volto/components';
|
|
12
8
|
import LogoImage from '@plone/volto/components/theme/Logo/Logo.svg';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
defaultMessage: 'Plone Site',
|
|
22
|
-
},
|
|
23
|
-
});
|
|
9
|
+
import { useSelector, useDispatch } from 'react-redux';
|
|
10
|
+
import { getNavroot } from '@plone/volto/actions';
|
|
11
|
+
import {
|
|
12
|
+
flattenToAppURL,
|
|
13
|
+
hasApiExpander,
|
|
14
|
+
getBaseUrl,
|
|
15
|
+
toPublicURL,
|
|
16
|
+
} from '@plone/volto/helpers';
|
|
24
17
|
|
|
25
18
|
/**
|
|
26
19
|
* Logo component class.
|
|
@@ -29,23 +22,36 @@ const messages = defineMessages({
|
|
|
29
22
|
* @returns {string} Markup of the component.
|
|
30
23
|
*/
|
|
31
24
|
const Logo = () => {
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
const
|
|
25
|
+
const pathname = useSelector((state) => state.router.location.pathname);
|
|
26
|
+
const site = useSelector((state) => state.site.data);
|
|
27
|
+
const navroot = useSelector((state) => state.navroot.data);
|
|
28
|
+
const dispatch = useDispatch();
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (pathname && !hasApiExpander('navroot', getBaseUrl(pathname))) {
|
|
32
|
+
dispatch(getNavroot(getBaseUrl(pathname)));
|
|
33
|
+
}
|
|
34
|
+
}, [dispatch, pathname]);
|
|
35
|
+
|
|
36
|
+
// remove trailing slash
|
|
37
|
+
const currentURL = toPublicURL(pathname).replace(/\/$/, '');
|
|
35
38
|
|
|
36
39
|
return (
|
|
37
|
-
<
|
|
38
|
-
href={
|
|
39
|
-
title={
|
|
40
|
+
<ConditionalLink
|
|
41
|
+
href={navroot?.navroot?.['@id']}
|
|
42
|
+
title={navroot?.navroot?.title}
|
|
43
|
+
condition={currentURL !== navroot?.navroot?.['@id']}
|
|
40
44
|
>
|
|
41
45
|
<Image
|
|
42
|
-
src={
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
src={
|
|
47
|
+
site['plone.site_logo']
|
|
48
|
+
? flattenToAppURL(site['plone.site_logo'])
|
|
49
|
+
: LogoImage
|
|
50
|
+
}
|
|
51
|
+
alt={navroot?.navroot?.title}
|
|
52
|
+
title={navroot?.navroot?.title}
|
|
47
53
|
/>
|
|
48
|
-
</
|
|
54
|
+
</ConditionalLink>
|
|
49
55
|
);
|
|
50
56
|
};
|
|
51
57
|
|
|
@@ -4,17 +4,151 @@ import configureStore from 'redux-mock-store';
|
|
|
4
4
|
import { Provider } from 'react-intl-redux';
|
|
5
5
|
import { MemoryRouter } from 'react-router-dom';
|
|
6
6
|
|
|
7
|
+
import config from '@plone/volto/registry';
|
|
8
|
+
|
|
7
9
|
import Logo from './Logo';
|
|
8
10
|
|
|
9
11
|
const mockStore = configureStore();
|
|
10
12
|
|
|
13
|
+
beforeAll(() => {
|
|
14
|
+
config.settings.publicURL = 'http://localhost:3000';
|
|
15
|
+
});
|
|
16
|
+
|
|
11
17
|
describe('Logo', () => {
|
|
12
|
-
it('renders a logo component', () => {
|
|
18
|
+
it('renders a logo component with default config', () => {
|
|
19
|
+
const store = mockStore({
|
|
20
|
+
intl: {
|
|
21
|
+
locale: 'en',
|
|
22
|
+
messages: {},
|
|
23
|
+
},
|
|
24
|
+
navroot: {
|
|
25
|
+
data: {
|
|
26
|
+
id: 'http://localhost:3000/@navroot',
|
|
27
|
+
navroot: {
|
|
28
|
+
'@id': 'http://localhost:3000',
|
|
29
|
+
title: 'Plone Site',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
router: {
|
|
34
|
+
location: {
|
|
35
|
+
pathname: '/',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
site: {
|
|
39
|
+
data: {},
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
const component = renderer.create(
|
|
43
|
+
<Provider store={store}>
|
|
44
|
+
<MemoryRouter>
|
|
45
|
+
<Logo />
|
|
46
|
+
</MemoryRouter>
|
|
47
|
+
</Provider>,
|
|
48
|
+
);
|
|
49
|
+
const json = component.toJSON();
|
|
50
|
+
expect(json).toMatchSnapshot();
|
|
51
|
+
});
|
|
52
|
+
it('renders a logo component with a custom logo', () => {
|
|
13
53
|
const store = mockStore({
|
|
14
54
|
intl: {
|
|
15
55
|
locale: 'en',
|
|
16
56
|
messages: {},
|
|
17
57
|
},
|
|
58
|
+
navroot: {
|
|
59
|
+
data: {
|
|
60
|
+
id: 'http://localhost:3000/@navroot',
|
|
61
|
+
navroot: {
|
|
62
|
+
'@id': 'http://localhost:3000',
|
|
63
|
+
title: 'Plone Site',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
router: {
|
|
68
|
+
location: {
|
|
69
|
+
pathname: '/',
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
site: {
|
|
73
|
+
data: {
|
|
74
|
+
'plone.site_logo':
|
|
75
|
+
'http://localhost:3000/@@site-logo/logo.cab945d8.svg',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
const component = renderer.create(
|
|
80
|
+
<Provider store={store}>
|
|
81
|
+
<MemoryRouter>
|
|
82
|
+
<Logo />
|
|
83
|
+
</MemoryRouter>
|
|
84
|
+
</Provider>,
|
|
85
|
+
);
|
|
86
|
+
const json = component.toJSON();
|
|
87
|
+
expect(json).toMatchSnapshot();
|
|
88
|
+
});
|
|
89
|
+
it('renders a logo component with default config in a non-root url', () => {
|
|
90
|
+
const store = mockStore({
|
|
91
|
+
intl: {
|
|
92
|
+
locale: 'en',
|
|
93
|
+
messages: {},
|
|
94
|
+
},
|
|
95
|
+
navroot: {
|
|
96
|
+
data: {
|
|
97
|
+
id: 'http://localhost:3000/@navroot',
|
|
98
|
+
navroot: {
|
|
99
|
+
'@id': 'http://localhost:3000',
|
|
100
|
+
title: 'Plone Site',
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
router: {
|
|
105
|
+
location: {
|
|
106
|
+
pathname: '/some-page',
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
site: {
|
|
110
|
+
data: {
|
|
111
|
+
'plone.site_logo':
|
|
112
|
+
'http://localhost:3000/@@site-logo/logo.cab945d8.svg',
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
const component = renderer.create(
|
|
117
|
+
<Provider store={store}>
|
|
118
|
+
<MemoryRouter>
|
|
119
|
+
<Logo />
|
|
120
|
+
</MemoryRouter>
|
|
121
|
+
</Provider>,
|
|
122
|
+
);
|
|
123
|
+
const json = component.toJSON();
|
|
124
|
+
expect(json).toMatchSnapshot();
|
|
125
|
+
});
|
|
126
|
+
it('renders a logo component with a custom logo in a non-root url', () => {
|
|
127
|
+
const store = mockStore({
|
|
128
|
+
intl: {
|
|
129
|
+
locale: 'en',
|
|
130
|
+
messages: {},
|
|
131
|
+
},
|
|
132
|
+
navroot: {
|
|
133
|
+
data: {
|
|
134
|
+
id: 'http://localhost:3000/@navroot',
|
|
135
|
+
navroot: {
|
|
136
|
+
'@id': 'http://localhost:3000',
|
|
137
|
+
title: 'Plone Site',
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
router: {
|
|
142
|
+
location: {
|
|
143
|
+
pathname: '/some-page',
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
site: {
|
|
147
|
+
data: {
|
|
148
|
+
'plone.site_logo':
|
|
149
|
+
'http://localhost:3000/@@site-logo/logo.cab945d8.svg',
|
|
150
|
+
},
|
|
151
|
+
},
|
|
18
152
|
});
|
|
19
153
|
const component = renderer.create(
|
|
20
154
|
<Provider store={store}>
|
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
* Navigation components.
|
|
3
|
-
* @module components/theme/Navigation/Navigation
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import React, { Component } from 'react';
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
7
2
|
import PropTypes from 'prop-types';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { defineMessages, injectIntl } from 'react-intl';
|
|
3
|
+
import { useDispatch, useSelector, shallowEqual } from 'react-redux';
|
|
4
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
11
5
|
import { Menu } from 'semantic-ui-react';
|
|
6
|
+
|
|
12
7
|
import cx from 'classnames';
|
|
13
8
|
import { BodyClass, getBaseUrl, hasApiExpander } from '@plone/volto/helpers';
|
|
14
9
|
import config from '@plone/volto/registry';
|
|
@@ -27,176 +22,96 @@ const messages = defineMessages({
|
|
|
27
22
|
},
|
|
28
23
|
});
|
|
29
24
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
* @property {Object} propTypes Property types.
|
|
39
|
-
* @static
|
|
40
|
-
*/
|
|
41
|
-
static propTypes = {
|
|
42
|
-
getNavigation: PropTypes.func.isRequired,
|
|
43
|
-
pathname: PropTypes.string.isRequired,
|
|
44
|
-
items: PropTypes.arrayOf(
|
|
45
|
-
PropTypes.shape({
|
|
46
|
-
title: PropTypes.string,
|
|
47
|
-
url: PropTypes.string,
|
|
48
|
-
}),
|
|
49
|
-
).isRequired,
|
|
50
|
-
lang: PropTypes.string.isRequired,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
static defaultProps = {
|
|
54
|
-
token: null,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Constructor
|
|
59
|
-
* @method constructor
|
|
60
|
-
* @param {Object} props Component properties
|
|
61
|
-
* @constructs Navigation
|
|
62
|
-
*/
|
|
63
|
-
constructor(props) {
|
|
64
|
-
super(props);
|
|
65
|
-
this.toggleMobileMenu = this.toggleMobileMenu.bind(this);
|
|
66
|
-
this.closeMobileMenu = this.closeMobileMenu.bind(this);
|
|
67
|
-
this.state = {
|
|
68
|
-
isMobileMenuOpen: false,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
25
|
+
const Navigation = (props) => {
|
|
26
|
+
const intl = useIntl();
|
|
27
|
+
const dispatch = useDispatch();
|
|
28
|
+
const { pathname, type } = props;
|
|
29
|
+
const [isMobileMenuOpen, setisMobileMenuOpen] = useState(false);
|
|
30
|
+
const token = useSelector((state) => state.userSession.token, shallowEqual);
|
|
31
|
+
const items = useSelector((state) => state.navigation.items, shallowEqual);
|
|
32
|
+
const lang = useSelector((state) => state.intl.locale);
|
|
71
33
|
|
|
72
|
-
|
|
34
|
+
useEffect(() => {
|
|
73
35
|
const { settings } = config;
|
|
74
|
-
if (!hasApiExpander('navigation', getBaseUrl(
|
|
75
|
-
|
|
76
|
-
getBaseUrl(this.props.pathname),
|
|
77
|
-
settings.navDepth,
|
|
78
|
-
);
|
|
36
|
+
if (!hasApiExpander('navigation', getBaseUrl(pathname))) {
|
|
37
|
+
dispatch(getNavigation(getBaseUrl(pathname), settings.navDepth));
|
|
79
38
|
}
|
|
80
|
-
}
|
|
39
|
+
}, [pathname, token, dispatch]);
|
|
81
40
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
* @param {Object} nextProps Next properties
|
|
86
|
-
* @returns {undefined}
|
|
87
|
-
*/
|
|
88
|
-
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
89
|
-
const { settings } = config;
|
|
90
|
-
if (
|
|
91
|
-
nextProps.pathname !== this.props.pathname ||
|
|
92
|
-
nextProps.token !== this.props.token
|
|
93
|
-
) {
|
|
94
|
-
if (!hasApiExpander('navigation', getBaseUrl(this.props.pathname))) {
|
|
95
|
-
this.props.getNavigation(
|
|
96
|
-
getBaseUrl(nextProps.pathname),
|
|
97
|
-
settings.navDepth,
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Toggle mobile menu's open state
|
|
105
|
-
* @method toggleMobileMenu
|
|
106
|
-
* @returns {undefined}
|
|
107
|
-
*/
|
|
108
|
-
toggleMobileMenu() {
|
|
109
|
-
this.setState({ isMobileMenuOpen: !this.state.isMobileMenuOpen });
|
|
110
|
-
}
|
|
41
|
+
const toggleMobileMenu = () => {
|
|
42
|
+
setisMobileMenuOpen(!isMobileMenuOpen);
|
|
43
|
+
};
|
|
111
44
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
* @method closeMobileMenu
|
|
115
|
-
* @returns {undefined}
|
|
116
|
-
*/
|
|
117
|
-
closeMobileMenu() {
|
|
118
|
-
if (!this.state.isMobileMenuOpen) {
|
|
45
|
+
const closeMobileMenu = () => {
|
|
46
|
+
if (!isMobileMenuOpen) {
|
|
119
47
|
return;
|
|
120
48
|
}
|
|
121
|
-
|
|
122
|
-
}
|
|
49
|
+
setisMobileMenuOpen(false);
|
|
50
|
+
};
|
|
123
51
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
: this.props.intl.formatMessage(messages.openMobileMenu, {
|
|
152
|
-
type: this.props.type,
|
|
153
|
-
})
|
|
154
|
-
}
|
|
155
|
-
type="button"
|
|
156
|
-
onClick={this.toggleMobileMenu}
|
|
157
|
-
>
|
|
158
|
-
<span className="hamburger-box">
|
|
159
|
-
<span className="hamburger-inner" />
|
|
160
|
-
</span>
|
|
161
|
-
</button>
|
|
162
|
-
</div>
|
|
163
|
-
<Menu
|
|
164
|
-
stackable
|
|
165
|
-
pointing
|
|
166
|
-
secondary
|
|
167
|
-
className="computer large screen widescreen only"
|
|
168
|
-
onClick={this.closeMobileMenu}
|
|
52
|
+
return (
|
|
53
|
+
<nav className="navigation" id="navigation" aria-label="navigation">
|
|
54
|
+
<div className="hamburger-wrapper mobile tablet only">
|
|
55
|
+
<button
|
|
56
|
+
className={cx('hamburger hamburger--spin', {
|
|
57
|
+
'is-active': isMobileMenuOpen,
|
|
58
|
+
})}
|
|
59
|
+
aria-label={
|
|
60
|
+
isMobileMenuOpen
|
|
61
|
+
? intl.formatMessage(messages.closeMobileMenu, {
|
|
62
|
+
type: type,
|
|
63
|
+
})
|
|
64
|
+
: intl.formatMessage(messages.openMobileMenu, {
|
|
65
|
+
type: type,
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
title={
|
|
69
|
+
isMobileMenuOpen
|
|
70
|
+
? intl.formatMessage(messages.closeMobileMenu, {
|
|
71
|
+
type: type,
|
|
72
|
+
})
|
|
73
|
+
: intl.formatMessage(messages.openMobileMenu, {
|
|
74
|
+
type: type,
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
type="button"
|
|
78
|
+
onClick={toggleMobileMenu}
|
|
169
79
|
>
|
|
170
|
-
<
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
80
|
+
<span className="hamburger-box">
|
|
81
|
+
<span className="hamburger-inner" />
|
|
82
|
+
</span>
|
|
83
|
+
</button>
|
|
84
|
+
</div>
|
|
85
|
+
<Menu
|
|
86
|
+
stackable
|
|
87
|
+
pointing
|
|
88
|
+
secondary
|
|
89
|
+
className="computer large screen widescreen only"
|
|
90
|
+
onClick={closeMobileMenu}
|
|
91
|
+
>
|
|
92
|
+
<NavItems items={items} lang={lang} />
|
|
93
|
+
</Menu>
|
|
94
|
+
<CSSTransition
|
|
95
|
+
in={isMobileMenuOpen}
|
|
96
|
+
timeout={500}
|
|
97
|
+
classNames="mobile-menu"
|
|
98
|
+
unmountOnExit
|
|
99
|
+
>
|
|
100
|
+
<div key="mobile-menu-key" className="mobile-menu">
|
|
101
|
+
<BodyClass className="has-mobile-menu-open" />
|
|
102
|
+
<div className="mobile-menu-nav">
|
|
103
|
+
<Menu stackable pointing secondary onClick={closeMobileMenu}>
|
|
104
|
+
<NavItems items={items} lang={lang} />
|
|
105
|
+
</Menu>
|
|
185
106
|
</div>
|
|
186
|
-
</
|
|
187
|
-
</
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
107
|
+
</div>
|
|
108
|
+
</CSSTransition>
|
|
109
|
+
</nav>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
Navigation.propTypes = {
|
|
114
|
+
pathname: PropTypes.string.isRequired,
|
|
115
|
+
};
|
|
191
116
|
|
|
192
|
-
export default
|
|
193
|
-
injectIntl,
|
|
194
|
-
connect(
|
|
195
|
-
(state) => ({
|
|
196
|
-
token: state.userSession.token,
|
|
197
|
-
items: state.navigation.items,
|
|
198
|
-
lang: state.intl.locale,
|
|
199
|
-
}),
|
|
200
|
-
{ getNavigation },
|
|
201
|
-
),
|
|
202
|
-
)(Navigation);
|
|
117
|
+
export default Navigation;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
2
|
import { useHistory } from 'react-router-dom';
|
|
3
3
|
import { Form, Input } from 'semantic-ui-react';
|
|
4
4
|
import { defineMessages, useIntl } from 'react-intl';
|
|
5
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
5
6
|
|
|
7
|
+
import { getNavroot } from '@plone/volto/actions';
|
|
8
|
+
import { hasApiExpander, getBaseUrl } from '@plone/volto/helpers';
|
|
6
9
|
import { Icon } from '@plone/volto/components';
|
|
7
10
|
import zoomSVG from '@plone/volto/icons/zoom.svg';
|
|
8
11
|
|
|
@@ -19,6 +22,8 @@ const messages = defineMessages({
|
|
|
19
22
|
|
|
20
23
|
const SearchWidget = (props) => {
|
|
21
24
|
const intl = useIntl();
|
|
25
|
+
const dispatch = useDispatch();
|
|
26
|
+
|
|
22
27
|
const [text, setText] = useState('');
|
|
23
28
|
const history = useHistory();
|
|
24
29
|
const onChangeText = (event, { value }) => {
|
|
@@ -29,14 +34,21 @@ const SearchWidget = (props) => {
|
|
|
29
34
|
const path =
|
|
30
35
|
pathname?.length > 0 ? `&path=${encodeURIComponent(pathname)}` : '';
|
|
31
36
|
|
|
32
|
-
history.push(
|
|
37
|
+
history.push(`./search?SearchableText=${encodeURIComponent(text)}${path}`);
|
|
33
38
|
// reset input value
|
|
34
39
|
setText('');
|
|
35
40
|
event.preventDefault();
|
|
36
41
|
};
|
|
37
42
|
|
|
43
|
+
const navroot = useSelector((state) => state.navroot?.data);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (!hasApiExpander('navroot', getBaseUrl(pathname))) {
|
|
46
|
+
dispatch(getNavroot(getBaseUrl(pathname)));
|
|
47
|
+
}
|
|
48
|
+
}, [dispatch, pathname]);
|
|
49
|
+
|
|
38
50
|
return (
|
|
39
|
-
<Form action=
|
|
51
|
+
<Form action={`${navroot?.navroot?.['@id']}/search`} onSubmit={onSubmit}>
|
|
40
52
|
<Form.Field className="searchbox">
|
|
41
53
|
<Input
|
|
42
54
|
aria-label={intl.formatMessage(messages.search)}
|
|
@@ -15,6 +15,14 @@ describe('SearchWidget', () => {
|
|
|
15
15
|
locale: 'en',
|
|
16
16
|
messages: {},
|
|
17
17
|
},
|
|
18
|
+
navroot: {
|
|
19
|
+
data: {
|
|
20
|
+
'@id': 'http://localhost:3000/@navroot',
|
|
21
|
+
navroot: {
|
|
22
|
+
'@id': 'http://localhost:3000',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
18
26
|
});
|
|
19
27
|
const component = renderer.create(
|
|
20
28
|
<Provider store={store}>
|
|
@@ -123,6 +123,7 @@ class View extends Component {
|
|
|
123
123
|
if (!hasApiExpander('actions', getBaseUrl(this.props.pathname))) {
|
|
124
124
|
this.props.listActions(getBaseUrl(this.props.pathname));
|
|
125
125
|
}
|
|
126
|
+
|
|
126
127
|
this.props.getContent(
|
|
127
128
|
getBaseUrl(this.props.pathname),
|
|
128
129
|
this.props.versionId,
|
|
@@ -142,6 +143,7 @@ class View extends Component {
|
|
|
142
143
|
if (!hasApiExpander('actions', getBaseUrl(nextProps.pathname))) {
|
|
143
144
|
this.props.listActions(getBaseUrl(nextProps.pathname));
|
|
144
145
|
}
|
|
146
|
+
|
|
145
147
|
this.props.getContent(
|
|
146
148
|
getBaseUrl(nextProps.pathname),
|
|
147
149
|
this.props.versionId,
|
package/src/config/Widgets.jsx
CHANGED
|
@@ -24,6 +24,7 @@ import InternalUrlWidget from '@plone/volto/components/manage/Widgets/InternalUr
|
|
|
24
24
|
import EmailWidget from '@plone/volto/components/manage/Widgets/EmailWidget';
|
|
25
25
|
import NumberWidget from '@plone/volto/components/manage/Widgets/NumberWidget';
|
|
26
26
|
import ImageSizeWidget from '@plone/volto/components/manage/Widgets/ImageSizeWidget';
|
|
27
|
+
import RegistryImageWidget from '@plone/volto/components/manage/Widgets/RegistryImageWidget';
|
|
27
28
|
|
|
28
29
|
import ReferenceWidget from '@plone/volto/components/manage/Widgets/ReferenceWidget';
|
|
29
30
|
import ObjectBrowserWidget from '@plone/volto/components/manage/Widgets/ObjectBrowserWidget';
|
|
@@ -72,6 +73,7 @@ export const widgetMapping = {
|
|
|
72
73
|
recurrence: RecurrenceWidget,
|
|
73
74
|
remoteUrl: UrlWidget,
|
|
74
75
|
id: IdWidget,
|
|
76
|
+
site_logo: RegistryImageWidget,
|
|
75
77
|
},
|
|
76
78
|
widget: {
|
|
77
79
|
richtext: WysiwygWidget,
|
package/src/config/index.js
CHANGED
|
@@ -37,6 +37,8 @@ import applyAddonConfiguration, { addonsInfo } from 'load-volto-addons';
|
|
|
37
37
|
|
|
38
38
|
import ConfigRegistry from '@plone/volto/registry';
|
|
39
39
|
|
|
40
|
+
import { getSiteAsyncPropExtender } from '@plone/volto/helpers';
|
|
41
|
+
|
|
40
42
|
const host = process.env.HOST || 'localhost';
|
|
41
43
|
const port = process.env.PORT || '3000';
|
|
42
44
|
|
|
@@ -83,7 +85,13 @@ let config = {
|
|
|
83
85
|
// https://6.docs.plone.org/volto/configuration/settings-reference.html#term-apiExpanders
|
|
84
86
|
// {
|
|
85
87
|
// match: '',
|
|
86
|
-
// GET_CONTENT: [
|
|
88
|
+
// GET_CONTENT: [
|
|
89
|
+
// 'breadcrumbs',
|
|
90
|
+
// 'navigation',
|
|
91
|
+
// 'actions',
|
|
92
|
+
// 'types',
|
|
93
|
+
// 'navroot',
|
|
94
|
+
// ],
|
|
87
95
|
// },
|
|
88
96
|
],
|
|
89
97
|
// Internal proxy to bypass CORS *while developing*. NOT intended for production use.
|
|
@@ -128,7 +136,7 @@ let config = {
|
|
|
128
136
|
useEmailAsLogin: false,
|
|
129
137
|
persistentReducers: ['blocksClipboard'],
|
|
130
138
|
initialReducersBlacklist: [], // reducers in this list won't be hydrated in windows.__data
|
|
131
|
-
asyncPropsExtenders: [], // per route asyncConnect customizers
|
|
139
|
+
asyncPropsExtenders: [getSiteAsyncPropExtender], // per route asyncConnect customizers
|
|
132
140
|
contentIcons: contentIcons,
|
|
133
141
|
loadables,
|
|
134
142
|
lazyBundles: {
|
|
@@ -188,6 +196,10 @@ let config = {
|
|
|
188
196
|
blockSettingsTabFieldsetsInitialStateOpen: true,
|
|
189
197
|
excludeLinksAndReferencesMenuItem: false,
|
|
190
198
|
containerBlockTypes: ['gridBlock'],
|
|
199
|
+
siteTitleFormat: {
|
|
200
|
+
includeSiteTitle: false,
|
|
201
|
+
titleAndSiteTitleSeparator: '-',
|
|
202
|
+
},
|
|
191
203
|
},
|
|
192
204
|
experimental: {
|
|
193
205
|
addBlockButton: {
|
|
@@ -223,7 +235,7 @@ config.settings.apiExpanders = [
|
|
|
223
235
|
...config.settings.apiExpanders,
|
|
224
236
|
{
|
|
225
237
|
match: '',
|
|
226
|
-
GET_CONTENT: ['breadcrumbs', 'actions', 'types'],
|
|
238
|
+
GET_CONTENT: ['breadcrumbs', 'actions', 'types', 'navroot'],
|
|
227
239
|
},
|
|
228
240
|
{
|
|
229
241
|
match: '',
|