@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
@@ -4,36 +4,26 @@
|
|
4
4
|
*/
|
5
5
|
|
6
6
|
import React from 'react';
|
7
|
-
import { Portal } from 'react-portal';
|
8
|
-
import PropTypes from 'prop-types';
|
9
|
-
import { BodyClass } from '@plone/volto/helpers';
|
10
|
-
|
11
|
-
import BannerView from '@eeacms/volto-eea-website-theme/components/theme/Banner/View';
|
12
7
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
return isClient ? (
|
18
|
-
<Portal node={document.getElementById('page-header')}>{children}</Portal>
|
19
|
-
) : (
|
20
|
-
children
|
21
|
-
);
|
22
|
-
}
|
8
|
+
import PropTypes from 'prop-types';
|
9
|
+
import { withBlockExtensions, BodyClass } from '@plone/volto/helpers';
|
10
|
+
import DefaultTemplate from './variations/Default';
|
23
11
|
|
24
12
|
/**
|
25
13
|
* View title block class.
|
26
14
|
* @class View
|
27
15
|
* @extends Component
|
28
16
|
*/
|
29
|
-
const View = (props) =>
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
17
|
+
const View = (props = {}) => {
|
18
|
+
const { variation } = props;
|
19
|
+
const Renderer = variation?.view ?? DefaultTemplate;
|
20
|
+
return (
|
21
|
+
<>
|
22
|
+
<BodyClass className="with-title-block" />
|
23
|
+
<Renderer {...props} />
|
24
|
+
</>
|
25
|
+
);
|
26
|
+
};
|
37
27
|
|
38
28
|
/**
|
39
29
|
* Property types.
|
@@ -44,4 +34,4 @@ View.propTypes = {
|
|
44
34
|
properties: PropTypes.objectOf(PropTypes.any).isRequired,
|
45
35
|
};
|
46
36
|
|
47
|
-
export default View;
|
37
|
+
export default withBlockExtensions(View);
|
@@ -1,11 +1,63 @@
|
|
1
1
|
import Edit from './Edit';
|
2
2
|
import View from './View';
|
3
|
+
import DefaultTemplate from './variations/Default';
|
4
|
+
import WebReport from './variations/WebReport';
|
5
|
+
import WebReportPage from './variations/WebReportPage';
|
6
|
+
import './variations/styles.less';
|
3
7
|
|
4
8
|
const applyConfig = (config) => {
|
5
9
|
config.blocks.blocksConfig.title = {
|
6
10
|
...config.blocks.blocksConfig.title,
|
7
11
|
edit: Edit,
|
8
12
|
view: View,
|
13
|
+
variations: [
|
14
|
+
{
|
15
|
+
id: 'default',
|
16
|
+
title: 'Default',
|
17
|
+
view: DefaultTemplate,
|
18
|
+
isDefault: true,
|
19
|
+
},
|
20
|
+
{
|
21
|
+
id: 'web_report',
|
22
|
+
title: 'Web Report',
|
23
|
+
view: WebReport,
|
24
|
+
schemaEnhancer: ({ schema }) => {
|
25
|
+
const fields = schema.fieldsets[0].fields;
|
26
|
+
schema.fieldsets[0].fields = [
|
27
|
+
...fields,
|
28
|
+
'content_type',
|
29
|
+
'hero_header',
|
30
|
+
];
|
31
|
+
|
32
|
+
schema.properties.content_type = {
|
33
|
+
title: 'Content type name',
|
34
|
+
description:
|
35
|
+
'Add a custom content-type name, leave empty for default',
|
36
|
+
};
|
37
|
+
schema.properties.hero_header = {
|
38
|
+
title: 'Hero header size',
|
39
|
+
type: 'boolean',
|
40
|
+
};
|
41
|
+
return schema;
|
42
|
+
},
|
43
|
+
},
|
44
|
+
{
|
45
|
+
id: 'web_report_page',
|
46
|
+
title: 'Web Report Page',
|
47
|
+
view: WebReportPage,
|
48
|
+
schemaEnhancer: ({ schema }) => {
|
49
|
+
const fields = schema.fieldsets[0].fields;
|
50
|
+
schema.fieldsets[0].fields = [...fields, 'content_type'];
|
51
|
+
|
52
|
+
schema.properties.content_type = {
|
53
|
+
title: 'Content type name',
|
54
|
+
description:
|
55
|
+
'Add a custom content-type name, leave empty for default',
|
56
|
+
};
|
57
|
+
return schema;
|
58
|
+
},
|
59
|
+
},
|
60
|
+
],
|
9
61
|
copyrightPrefix: 'Image',
|
10
62
|
sidebarTab: 1,
|
11
63
|
};
|
@@ -0,0 +1,43 @@
|
|
1
|
+
/**
|
2
|
+
* View title block.
|
3
|
+
* @module components/manage/Blocks/Title/View
|
4
|
+
*/
|
5
|
+
|
6
|
+
import React from 'react';
|
7
|
+
import { Portal } from 'react-portal';
|
8
|
+
import PropTypes from 'prop-types';
|
9
|
+
|
10
|
+
import BannerView from '@eeacms/volto-eea-website-theme/components/theme/Banner/View';
|
11
|
+
|
12
|
+
function IsomorphicPortal({ children }) {
|
13
|
+
const [isClient, setIsClient] = React.useState();
|
14
|
+
React.useEffect(() => setIsClient(true), []);
|
15
|
+
|
16
|
+
return isClient ? (
|
17
|
+
<Portal node={document.getElementById('page-header')}>{children}</Portal>
|
18
|
+
) : (
|
19
|
+
children
|
20
|
+
);
|
21
|
+
}
|
22
|
+
|
23
|
+
const DefaultTemplate = (props) =>
|
24
|
+
props.isEditMode ? (
|
25
|
+
<BannerView {...props} />
|
26
|
+
) : (
|
27
|
+
<React.Fragment>
|
28
|
+
<IsomorphicPortal>
|
29
|
+
<BannerView {...props} />
|
30
|
+
</IsomorphicPortal>
|
31
|
+
</React.Fragment>
|
32
|
+
);
|
33
|
+
|
34
|
+
/**
|
35
|
+
* Property types.
|
36
|
+
* @property {Object} propTypes Property types.
|
37
|
+
* @static
|
38
|
+
*/
|
39
|
+
DefaultTemplate.propTypes = {
|
40
|
+
properties: PropTypes.objectOf(PropTypes.any).isRequired,
|
41
|
+
};
|
42
|
+
|
43
|
+
export default DefaultTemplate;
|
@@ -0,0 +1,69 @@
|
|
1
|
+
/**
|
2
|
+
* Web Report title block variation.
|
3
|
+
* @module components/manage/Blocks/Title/variations/WebReport
|
4
|
+
*/
|
5
|
+
|
6
|
+
import React from 'react';
|
7
|
+
import { Portal } from 'react-portal';
|
8
|
+
import PropTypes from 'prop-types';
|
9
|
+
|
10
|
+
import { MaybeWrap } from '@plone/volto/components';
|
11
|
+
import BannerView from '@eeacms/volto-eea-website-theme/components/theme/Banner/View';
|
12
|
+
import Banner from '@eeacms/volto-eea-design-system/ui/Banner/Banner';
|
13
|
+
import clsx from 'clsx';
|
14
|
+
|
15
|
+
import { BodyClass } from '@plone/volto/helpers';
|
16
|
+
|
17
|
+
function IsomorphicPortal({ children }) {
|
18
|
+
const [isClient, setIsClient] = React.useState();
|
19
|
+
React.useEffect(() => setIsClient(true), []);
|
20
|
+
|
21
|
+
return isClient ? (
|
22
|
+
<Portal node={document.querySelector('.eea.header')}>{children}</Portal>
|
23
|
+
) : (
|
24
|
+
children
|
25
|
+
);
|
26
|
+
}
|
27
|
+
|
28
|
+
const WebReport = (props) => {
|
29
|
+
return (
|
30
|
+
<MaybeWrap condition={!props.isEditMode} as={IsomorphicPortal}>
|
31
|
+
<BodyClass
|
32
|
+
className={clsx(
|
33
|
+
'homepage-inverse homepage-header light-header',
|
34
|
+
props.data.hero_header ? 'hero-header' : '',
|
35
|
+
)}
|
36
|
+
/>
|
37
|
+
<BannerView
|
38
|
+
{...props}
|
39
|
+
data={{
|
40
|
+
...props.data,
|
41
|
+
hideContentType: true,
|
42
|
+
aboveTitle: (
|
43
|
+
<div className="content-type">
|
44
|
+
{props.data.content_type || props.properties.type_title}
|
45
|
+
</div>
|
46
|
+
),
|
47
|
+
belowTitle: (
|
48
|
+
<>
|
49
|
+
<Banner.Subtitle>
|
50
|
+
<span className="subtitle-light">{props.data.subtitle}</span>
|
51
|
+
</Banner.Subtitle>
|
52
|
+
</>
|
53
|
+
),
|
54
|
+
}}
|
55
|
+
/>
|
56
|
+
</MaybeWrap>
|
57
|
+
);
|
58
|
+
};
|
59
|
+
|
60
|
+
/**
|
61
|
+
* Property types.
|
62
|
+
* @property {Object} propTypes Property types.
|
63
|
+
* @static
|
64
|
+
*/
|
65
|
+
WebReport.propTypes = {
|
66
|
+
properties: PropTypes.objectOf(PropTypes.any).isRequired,
|
67
|
+
};
|
68
|
+
|
69
|
+
export default WebReport;
|
@@ -0,0 +1,59 @@
|
|
1
|
+
/**
|
2
|
+
* Web Report Page title block variation.
|
3
|
+
* @module components/manage/Title/variations/WebReport
|
4
|
+
*/
|
5
|
+
|
6
|
+
import React from 'react';
|
7
|
+
import { Portal } from 'react-portal';
|
8
|
+
import PropTypes from 'prop-types';
|
9
|
+
|
10
|
+
import { MaybeWrap } from '@plone/volto/components';
|
11
|
+
import BannerView from '@eeacms/volto-eea-website-theme/components/theme/Banner/View';
|
12
|
+
import clsx from 'clsx';
|
13
|
+
|
14
|
+
import { BodyClass } from '@plone/volto/helpers';
|
15
|
+
|
16
|
+
function IsomorphicPortal({ children }) {
|
17
|
+
const [isClient, setIsClient] = React.useState();
|
18
|
+
React.useEffect(() => setIsClient(true), []);
|
19
|
+
|
20
|
+
return isClient ? (
|
21
|
+
<Portal node={document.querySelector('.eea.header')}>{children}</Portal>
|
22
|
+
) : (
|
23
|
+
children
|
24
|
+
);
|
25
|
+
}
|
26
|
+
|
27
|
+
const WebReportPage = (props) => {
|
28
|
+
return (
|
29
|
+
<MaybeWrap condition={!props.isEditMode} as={IsomorphicPortal}>
|
30
|
+
<BodyClass className={clsx('homepage-inverse light-header')} />
|
31
|
+
<BannerView
|
32
|
+
{...props}
|
33
|
+
data={{
|
34
|
+
...props.data,
|
35
|
+
hideContentType: true,
|
36
|
+
aboveTitle: (
|
37
|
+
<>
|
38
|
+
<div className="content-type">
|
39
|
+
{props.data.content_type || props.properties.type_title}
|
40
|
+
</div>
|
41
|
+
<div className="subtitle">{props.data.subtitle}</div>
|
42
|
+
</>
|
43
|
+
),
|
44
|
+
}}
|
45
|
+
/>
|
46
|
+
</MaybeWrap>
|
47
|
+
);
|
48
|
+
};
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Property types.
|
52
|
+
* @property {Object} propTypes Property types.
|
53
|
+
* @static
|
54
|
+
*/
|
55
|
+
WebReportPage.propTypes = {
|
56
|
+
properties: PropTypes.objectOf(PropTypes.any).isRequired,
|
57
|
+
};
|
58
|
+
|
59
|
+
export default WebReportPage;
|
@@ -0,0 +1,28 @@
|
|
1
|
+
.view-viewview.light-header .main.bar {
|
2
|
+
position: relative;
|
3
|
+
z-index: 1;
|
4
|
+
width: 100%;
|
5
|
+
margin-bottom: -160px;
|
6
|
+
}
|
7
|
+
//Gradient styles for web report
|
8
|
+
.light-header .gradient {
|
9
|
+
background: linear-gradient(
|
10
|
+
0deg,
|
11
|
+
#ffffff,
|
12
|
+
rgba(255, 255, 255, 0.9) 30%,
|
13
|
+
rgba(46, 82, 114, 0.7) 70%,
|
14
|
+
rgba(14, 21, 26, 0.8) 100%
|
15
|
+
) !important;
|
16
|
+
}
|
17
|
+
|
18
|
+
.ui.block.title .eea.banner .content {
|
19
|
+
padding-right: 1rem;
|
20
|
+
padding-left: 1rem;
|
21
|
+
}
|
22
|
+
|
23
|
+
.share-popup {
|
24
|
+
.actions {
|
25
|
+
display: flex;
|
26
|
+
flex-flow: row;
|
27
|
+
}
|
28
|
+
}
|
@@ -291,8 +291,12 @@ const View = (props) => {
|
|
291
291
|
</>
|
292
292
|
}
|
293
293
|
>
|
294
|
-
{subtitle &&
|
294
|
+
{!props.data.aboveTitle && subtitle && (
|
295
|
+
<Banner.Subtitle>{subtitle}</Banner.Subtitle>
|
296
|
+
)}
|
297
|
+
{props.data.aboveTitle}
|
295
298
|
<Title config={banner.title} properties={metadata} />
|
299
|
+
{props.data.belowTitle}
|
296
300
|
<Banner.Metadata>
|
297
301
|
<Banner.MetadataField
|
298
302
|
type="type"
|
@@ -14,8 +14,10 @@ const SubsiteClass = () => {
|
|
14
14
|
|
15
15
|
return (
|
16
16
|
<BodyClass
|
17
|
-
className={cx('subsite',
|
17
|
+
className={cx('subsite', {
|
18
18
|
'subsite-root': isSubsiteRoot(location.pathname, subsite),
|
19
|
+
[`subsite-${subsite.subsite_css_class?.token}`]:
|
20
|
+
subsite.subsite_css_class?.token,
|
19
21
|
})}
|
20
22
|
/>
|
21
23
|
);
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import React, { useEffect } from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { useHistory } from 'react-router-dom';
|
4
|
+
import { isInternalURL, flattenToAppURL } from '@plone/volto/helpers';
|
5
|
+
import { DefaultView } from '@plone/volto/components/';
|
6
|
+
import { Redirect } from 'react-router-dom';
|
7
|
+
|
8
|
+
const WebReportSectionView = (props) => {
|
9
|
+
const { content, token } = props;
|
10
|
+
const history = useHistory();
|
11
|
+
const redirectUrl = React.useMemo(() => {
|
12
|
+
if (content) {
|
13
|
+
const items = content.items;
|
14
|
+
const firstItem = items?.[0];
|
15
|
+
return firstItem?.['@id'];
|
16
|
+
}
|
17
|
+
}, [content]);
|
18
|
+
|
19
|
+
useEffect(() => {
|
20
|
+
if (!token) {
|
21
|
+
if (isInternalURL(redirectUrl)) {
|
22
|
+
history.replace(flattenToAppURL(redirectUrl));
|
23
|
+
} else if (!__SERVER__ && redirectUrl) {
|
24
|
+
window.location.href = flattenToAppURL(redirectUrl);
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}, [history, content, redirectUrl, token]);
|
28
|
+
|
29
|
+
if (__SERVER__ && redirectUrl && !token) {
|
30
|
+
return <Redirect to={redirectUrl} />;
|
31
|
+
}
|
32
|
+
return <DefaultView {...props} />;
|
33
|
+
};
|
34
|
+
|
35
|
+
WebReportSectionView.propTypes = {
|
36
|
+
content: PropTypes.shape({
|
37
|
+
items: PropTypes.arrayOf(
|
38
|
+
PropTypes.shape({
|
39
|
+
'@id': PropTypes.string,
|
40
|
+
}),
|
41
|
+
),
|
42
|
+
}),
|
43
|
+
};
|
44
|
+
|
45
|
+
WebReportSectionView.defaultProps = {
|
46
|
+
content: null,
|
47
|
+
};
|
48
|
+
|
49
|
+
export default WebReportSectionView;
|
@@ -3,7 +3,7 @@
|
|
3
3
|
* @module components/theme/Breadcrumbs/Breadcrumbs
|
4
4
|
*/
|
5
5
|
|
6
|
-
import React, { useEffect } from 'react';
|
6
|
+
import React, { useEffect, useMemo } from 'react';
|
7
7
|
import { useDispatch, useSelector } from 'react-redux';
|
8
8
|
|
9
9
|
import { useLocation } from 'react-router';
|
@@ -32,10 +32,23 @@ const isContentRoute = (pathname) => {
|
|
32
32
|
const Breadcrumbs = (props) => {
|
33
33
|
const dispatch = useDispatch();
|
34
34
|
const { items = [], root = '/' } = useSelector((state) => state?.breadcrumbs);
|
35
|
+
const content = useSelector((state) => state?.content?.data);
|
36
|
+
|
35
37
|
// const pathname = useSelector((state) => state.location.pathname);
|
36
38
|
const location = useLocation();
|
37
39
|
const { pathname } = location;
|
38
40
|
|
41
|
+
const linkLevels = useMemo(() => {
|
42
|
+
if (content) {
|
43
|
+
const type = content['@type'];
|
44
|
+
const isContentTypesToAvoid =
|
45
|
+
config.settings.contentTypeToAvoidAsLinks || {};
|
46
|
+
if (isContentTypesToAvoid[type]) {
|
47
|
+
return isContentTypesToAvoid[type];
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}, [content]);
|
51
|
+
|
39
52
|
const sections = items.map((item) => ({
|
40
53
|
title: item.title,
|
41
54
|
href: item.url,
|
@@ -54,7 +67,12 @@ const Breadcrumbs = (props) => {
|
|
54
67
|
return (
|
55
68
|
<React.Fragment>
|
56
69
|
<div id="page-header" />
|
57
|
-
<EEABreadcrumbs
|
70
|
+
<EEABreadcrumbs
|
71
|
+
pathname={pathname}
|
72
|
+
sections={sections}
|
73
|
+
root={root}
|
74
|
+
linkLevels={linkLevels}
|
75
|
+
/>
|
58
76
|
</React.Fragment>
|
59
77
|
);
|
60
78
|
};
|
@@ -17,7 +17,6 @@ import eeaFlag from '@eeacms/volto-eea-design-system/../theme/themes/eea/assets/
|
|
17
17
|
|
18
18
|
import config from '@plone/volto/registry';
|
19
19
|
import { compose } from 'recompose';
|
20
|
-
import { BodyClass } from '@plone/volto/helpers';
|
21
20
|
|
22
21
|
import cx from 'classnames';
|
23
22
|
import loadable from '@loadable/component';
|
@@ -43,10 +42,12 @@ const EEAHeader = ({ pathname, token, items, history, subsite }) => {
|
|
43
42
|
const has_home_layout =
|
44
43
|
layout === 'homepage_inverse_view' ||
|
45
44
|
(__CLIENT__ && document.body.classList.contains('homepage-inverse'));
|
45
|
+
|
46
46
|
return (
|
47
47
|
has_home_layout &&
|
48
48
|
(removeTrailingSlash(pathname) === router_pathname ||
|
49
|
-
router_pathname.endsWith('/edit')
|
49
|
+
router_pathname.endsWith('/edit') ||
|
50
|
+
router_pathname.endsWith('/add'))
|
50
51
|
);
|
51
52
|
});
|
52
53
|
|
@@ -75,7 +76,6 @@ const EEAHeader = ({ pathname, token, items, history, subsite }) => {
|
|
75
76
|
|
76
77
|
return (
|
77
78
|
<Header menuItems={items}>
|
78
|
-
{isHomePageInverse && <BodyClass className="homepage" />}
|
79
79
|
<Header.TopHeader>
|
80
80
|
<Header.TopItem className="official-union">
|
81
81
|
<Image src={eeaFlag} alt="European Union flag"></Image>
|
@@ -0,0 +1,190 @@
|
|
1
|
+
/**
|
2
|
+
* Document view component.
|
3
|
+
* @module components/theme/View/DefaultView
|
4
|
+
*/
|
5
|
+
|
6
|
+
import React from 'react';
|
7
|
+
import PropTypes from 'prop-types';
|
8
|
+
|
9
|
+
import {
|
10
|
+
Container as SemanticContainer,
|
11
|
+
Segment,
|
12
|
+
Grid,
|
13
|
+
Label,
|
14
|
+
} from 'semantic-ui-react';
|
15
|
+
import config from '@plone/volto/registry';
|
16
|
+
import { getSchema } from '@plone/volto/actions';
|
17
|
+
import { getWidget } from '@plone/volto/helpers/Widget/utils';
|
18
|
+
import { RenderBlocks } from '@plone/volto/components';
|
19
|
+
|
20
|
+
import { hasBlocksData, getBaseUrl } from '@plone/volto/helpers';
|
21
|
+
import { useDispatch, shallowEqual, useSelector } from 'react-redux';
|
22
|
+
|
23
|
+
import isEqual from 'lodash/isEqual';
|
24
|
+
import AccordionContextNavigation from '@eeacms/volto-eea-website-theme/components/manage/Blocks/ContextNavigation/variations/Accordion';
|
25
|
+
|
26
|
+
/**
|
27
|
+
* Component to display the default view.
|
28
|
+
* @function DefaultView
|
29
|
+
* @param {Object} content Content object.
|
30
|
+
* @returns {string} Markup of the component.
|
31
|
+
*/
|
32
|
+
const DefaultView = (props) => {
|
33
|
+
const { content, location } = props;
|
34
|
+
const [hasLightLayout, setHasLightLayout] = React.useState(false);
|
35
|
+
|
36
|
+
React.useEffect(() => {
|
37
|
+
const updateLightLayout = () => {
|
38
|
+
if (__CLIENT__) {
|
39
|
+
setHasLightLayout(document.body.classList.contains('light-header'));
|
40
|
+
}
|
41
|
+
};
|
42
|
+
|
43
|
+
updateLightLayout();
|
44
|
+
|
45
|
+
if (__CLIENT__) {
|
46
|
+
const observer = new MutationObserver(updateLightLayout);
|
47
|
+
observer.observe(document.body, {
|
48
|
+
attributes: true,
|
49
|
+
attributeFilter: ['class'],
|
50
|
+
});
|
51
|
+
|
52
|
+
return () => observer.disconnect();
|
53
|
+
}
|
54
|
+
}, []);
|
55
|
+
|
56
|
+
const { contextNavigationActions } = useSelector(
|
57
|
+
(state) => ({
|
58
|
+
contextNavigationActions: state.actions?.actions?.context_navigation,
|
59
|
+
}),
|
60
|
+
shallowEqual,
|
61
|
+
);
|
62
|
+
|
63
|
+
const navigation_paths = contextNavigationActions || [];
|
64
|
+
const path = getBaseUrl(location?.pathname || '');
|
65
|
+
const dispatch = useDispatch();
|
66
|
+
const { views } = config.widgets;
|
67
|
+
const contentSchema = useSelector((state) => state.schema?.schema);
|
68
|
+
const fieldsetsToExclude = [
|
69
|
+
'categorization',
|
70
|
+
'dates',
|
71
|
+
'ownership',
|
72
|
+
'settings',
|
73
|
+
];
|
74
|
+
const fieldsets = contentSchema?.fieldsets.filter(
|
75
|
+
(fs) => !fieldsetsToExclude.includes(fs.id),
|
76
|
+
);
|
77
|
+
|
78
|
+
// TL;DR: There is a flash of the non block-based view because of the reset
|
79
|
+
// of the content on route change. Subscribing to the content change at this
|
80
|
+
// level has nasty implications, so we can't watch the Redux state for loaded
|
81
|
+
// content flag here (because it forces an additional component update)
|
82
|
+
// Instead, we can watch if the content is "empty", but this has a drawback
|
83
|
+
// since the locking mechanism inserts a `lock` key before the content is there.
|
84
|
+
// So "empty" means `content` is present, but only with a `lock` key, thus the next
|
85
|
+
// ugly condition comes to life
|
86
|
+
const contentLoaded = content && !isEqual(Object.keys(content), ['lock']);
|
87
|
+
|
88
|
+
React.useEffect(() => {
|
89
|
+
content?.['@type'] &&
|
90
|
+
!hasBlocksData(content) &&
|
91
|
+
dispatch(getSchema(content['@type'], location.pathname));
|
92
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
93
|
+
}, []);
|
94
|
+
|
95
|
+
const Container =
|
96
|
+
config.getComponent({ name: 'Container' }).component || SemanticContainer;
|
97
|
+
const matchingNavigationPath = navigation_paths.find((navPath) =>
|
98
|
+
path.includes(navPath.url),
|
99
|
+
);
|
100
|
+
|
101
|
+
// If the content is not yet loaded, then do not show anything
|
102
|
+
return contentLoaded ? (
|
103
|
+
hasBlocksData(content) ? (
|
104
|
+
<>
|
105
|
+
<Container id="page-document">
|
106
|
+
<RenderBlocks {...props} path={path} />
|
107
|
+
</Container>
|
108
|
+
{hasLightLayout && matchingNavigationPath && (
|
109
|
+
<AccordionContextNavigation
|
110
|
+
params={{
|
111
|
+
name: matchingNavigationPath.title,
|
112
|
+
no_thumbs: matchingNavigationPath.no_thumbs || true,
|
113
|
+
no_icons: matchingNavigationPath.no_icons || true,
|
114
|
+
root_path: matchingNavigationPath.url,
|
115
|
+
includeTop: matchingNavigationPath.includeTop || true,
|
116
|
+
bottomLevel: matchingNavigationPath.bottomLevel || 3,
|
117
|
+
topLevel: matchingNavigationPath.topLevel || 1,
|
118
|
+
currentFolderOnly:
|
119
|
+
matchingNavigationPath.currentFolderOnly || false,
|
120
|
+
}}
|
121
|
+
/>
|
122
|
+
)}
|
123
|
+
</>
|
124
|
+
) : (
|
125
|
+
<Container id="page-document">
|
126
|
+
{fieldsets?.map((fs) => {
|
127
|
+
return (
|
128
|
+
<div className="fieldset" key={fs.id}>
|
129
|
+
{fs.id !== 'default' && <h2>{fs.title}</h2>}
|
130
|
+
{fs.fields?.map((f, key) => {
|
131
|
+
let field = {
|
132
|
+
...contentSchema?.properties[f],
|
133
|
+
id: f,
|
134
|
+
widget: getWidget(f, contentSchema?.properties[f]),
|
135
|
+
};
|
136
|
+
let Widget = views?.getWidget(field);
|
137
|
+
return f !== 'title' ? (
|
138
|
+
<Grid celled="internally" key={key}>
|
139
|
+
<Grid.Row>
|
140
|
+
<Label title={field.id}>{field.title}:</Label>
|
141
|
+
</Grid.Row>
|
142
|
+
<Grid.Row>
|
143
|
+
<Segment basic>
|
144
|
+
<Widget value={content[f]} />
|
145
|
+
</Segment>
|
146
|
+
</Grid.Row>
|
147
|
+
</Grid>
|
148
|
+
) : (
|
149
|
+
<Widget key={key} value={content[f]} />
|
150
|
+
);
|
151
|
+
})}
|
152
|
+
</div>
|
153
|
+
);
|
154
|
+
})}
|
155
|
+
</Container>
|
156
|
+
)
|
157
|
+
) : null;
|
158
|
+
};
|
159
|
+
|
160
|
+
/**
|
161
|
+
* Property types.
|
162
|
+
* @property {Object} propTypes Property types.
|
163
|
+
* @static
|
164
|
+
*/
|
165
|
+
DefaultView.propTypes = {
|
166
|
+
/**
|
167
|
+
* Content of the object
|
168
|
+
*/
|
169
|
+
content: PropTypes.shape({
|
170
|
+
/**
|
171
|
+
* Title of the object
|
172
|
+
*/
|
173
|
+
title: PropTypes.string,
|
174
|
+
/**
|
175
|
+
* Description of the object
|
176
|
+
*/
|
177
|
+
description: PropTypes.string,
|
178
|
+
/**
|
179
|
+
* Text of the object
|
180
|
+
*/
|
181
|
+
text: PropTypes.shape({
|
182
|
+
/**
|
183
|
+
* Data of the text of the object
|
184
|
+
*/
|
185
|
+
data: PropTypes.string,
|
186
|
+
}),
|
187
|
+
}).isRequired,
|
188
|
+
};
|
189
|
+
|
190
|
+
export default DefaultView;
|