@eeacms/volto-eea-website-theme 2.2.2 → 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 +26 -22
- 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/components/theme/Widgets/DateWidget.jsx +32 -0
- package/src/components/theme/Widgets/DateWidget.test.js +67 -0
- package/src/components/theme/Widgets/DatetimeWidget.jsx +45 -0
- package/src/components/theme/Widgets/DatetimeWidget.test.js +63 -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 +37 -14
- package/src/index.test.js +2 -0
@@ -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>
|
@@ -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;
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import cx from 'classnames';
|
3
|
+
import { useSelector } from 'react-redux';
|
4
|
+
import { toBackendLang } from '@plone/volto/helpers';
|
5
|
+
import { formatDate } from '@plone/volto/helpers/Utils/Date';
|
6
|
+
import config from '@plone/volto/registry';
|
7
|
+
|
8
|
+
export const DateWidget = ({ value, children, className }) => {
|
9
|
+
const lang = useSelector((state) => state.intl.locale);
|
10
|
+
const backendLang = toBackendLang(lang);
|
11
|
+
const locale =
|
12
|
+
backendLang === 'en' ? config.settings.dateLocale : backendLang;
|
13
|
+
const formatOptions = {
|
14
|
+
date: value,
|
15
|
+
format: {
|
16
|
+
year: 'numeric',
|
17
|
+
month: 'short',
|
18
|
+
day: '2-digit',
|
19
|
+
},
|
20
|
+
locale,
|
21
|
+
};
|
22
|
+
|
23
|
+
return value ? (
|
24
|
+
<span className={cx(className, 'date', 'widget')}>
|
25
|
+
{children
|
26
|
+
? children(formatDate(formatOptions))
|
27
|
+
: formatDate(formatOptions)}
|
28
|
+
</span>
|
29
|
+
) : (
|
30
|
+
''
|
31
|
+
);
|
32
|
+
};
|