@kitconcept/volto-light-theme 3.0.0-alpha.3 → 3.0.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.
@@ -141,58 +141,48 @@ const Navigation = ({ pathname }) => {
141
141
  {item.items &&
142
142
  item.items.length > 0 &&
143
143
  item.items.map((subitem) => (
144
- <div
145
- className="subitem-wrapper"
146
- key={subitem.url}
147
- >
148
- <li key={subitem.url}>
149
- <NavLink
150
- to={subitem.url}
151
- onClick={() => closeMenu()}
152
- className={cx({
153
- current: isActive(subitem.url),
154
- })}
155
- >
156
- <span className="left-arrow">&#8212;</span>
157
- <span>
158
- {subitem.nav_title || subitem.title}
159
- </span>
160
- </NavLink>
161
- </li>
144
+ <li className="subitem-wrapper" key={subitem.url}>
145
+ <NavLink
146
+ to={subitem.url}
147
+ onClick={() => closeMenu()}
148
+ className={cx({
149
+ current: isActive(subitem.url),
150
+ })}
151
+ >
152
+ <span className="left-arrow">&#8212;</span>
153
+ <span>
154
+ {subitem.nav_title || subitem.title}
155
+ </span>
156
+ </NavLink>
162
157
  <div className="sub-submenu">
163
158
  <ul>
164
159
  {subitem.items &&
165
160
  subitem.items.length > 0 &&
166
161
  subitem.items.map((subsubitem) => (
167
- <div
162
+ <li
168
163
  className="subsubitem-wrapper"
169
164
  key={subsubitem.url}
170
165
  >
171
- <li key={subsubitem.url}>
172
- <NavLink
173
- to={subsubitem.url}
174
- onClick={() => closeMenu()}
175
- className={cx({
176
- current: isActive(
177
- subsubitem.url,
178
- ),
179
- })}
180
- >
181
- <span className="left-arrow">
182
- &#8212;
183
- </span>
184
-
185
- <span>
186
- {subsubitem.nav_title ||
187
- subsubitem.title}
188
- </span>
189
- </NavLink>
190
- </li>
191
- </div>
166
+ <NavLink
167
+ to={subsubitem.url}
168
+ onClick={() => closeMenu()}
169
+ className={cx({
170
+ current: isActive(subsubitem.url),
171
+ })}
172
+ >
173
+ <span className="left-arrow">
174
+ &#8212;
175
+ </span>
176
+ <span>
177
+ {subsubitem.nav_title ||
178
+ subsubitem.title}
179
+ </span>
180
+ </NavLink>
181
+ </li>
192
182
  ))}
193
183
  </ul>
194
184
  </div>
195
- </div>
185
+ </li>
196
186
  ))}
197
187
  </ul>
198
188
  </div>
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Intranet Search Widget component.
3
+ * @module components/SearchWidget
4
+ */
5
+
6
+ import React, { Component } from 'react';
7
+ import { withRouter } from 'react-router-dom';
8
+ import { Form, Input } from 'semantic-ui-react';
9
+ import { compose } from 'redux';
10
+ import { PropTypes } from 'prop-types';
11
+ import { defineMessages, injectIntl } from 'react-intl';
12
+
13
+ import { Icon } from '@plone/volto/components';
14
+ import zoomSVG from '@plone/volto/icons/zoom.svg';
15
+
16
+ const messages = defineMessages({
17
+ search: {
18
+ id: 'Search',
19
+ defaultMessage: 'Search',
20
+ },
21
+ searchSite: {
22
+ id: 'Search Site',
23
+ defaultMessage: 'Search Site',
24
+ },
25
+ placeholder: {
26
+ id: 'Search for People, E-Mail Address, Phone Number, ...',
27
+ defaultMessage: 'Search for People, E-Mail Address, Phone Number, ...',
28
+ },
29
+ });
30
+
31
+ /**
32
+ * IntranetSearchWidget component class.
33
+ * @class IntranetSearchWidget
34
+ * @extends Component
35
+ */
36
+ class IntranetSearchWidget extends Component {
37
+ /**
38
+ * Property types.
39
+ * @property {Object} propTypes Property types.
40
+ * @static
41
+ */
42
+ static propTypes = {
43
+ pathname: PropTypes.string,
44
+ };
45
+
46
+ /**
47
+ * Constructor
48
+ * @method constructor
49
+ * @param {Object} props Component properties
50
+ * @constructs WysiwygEditor
51
+ */
52
+ constructor(props) {
53
+ super(props);
54
+ this.onChangeText = this.onChangeText.bind(this);
55
+ this.onSubmit = this.onSubmit.bind(this);
56
+ this.state = {
57
+ text: '',
58
+ };
59
+ }
60
+
61
+ /**
62
+ * On change text
63
+ * @method onChangeText
64
+ * @param {object} event Event object.
65
+ * @param {string} value Text value.
66
+ * @returns {undefined}
67
+ */
68
+ onChangeText(event, { value }) {
69
+ this.setState({
70
+ text: value,
71
+ });
72
+ }
73
+
74
+ /**
75
+ * Submit handler
76
+ * @method onSubmit
77
+ * @param {event} event Event object.
78
+ * @returns {undefined}
79
+ */
80
+ onSubmit(event) {
81
+ const path =
82
+ this.props.pathname?.length > 0
83
+ ? `&path=${encodeURIComponent(this.props.pathname)}`
84
+ : '';
85
+ this.props.history.push(
86
+ `/search?SearchableText=${encodeURIComponent(this.state.text)}${path}`,
87
+ );
88
+ // reset input value
89
+ this.setState({
90
+ text: '',
91
+ });
92
+ event.preventDefault();
93
+ }
94
+
95
+ /**
96
+ * Render method.
97
+ * @method render
98
+ * @returns {string} Markup for the component.
99
+ */
100
+ render() {
101
+ const { intl } = this.props;
102
+ return (
103
+ <Form action="/search" onSubmit={this.onSubmit}>
104
+ <Form.Field className="searchbox">
105
+ <Input
106
+ aria-label={intl.formatMessage(messages.search)}
107
+ onChange={this.onChangeText}
108
+ name="SearchableText"
109
+ value={this.state.text}
110
+ transparent
111
+ autoComplete="off"
112
+ placeholder={intl.formatMessage(messages.placeholder)}
113
+ title={intl.formatMessage(messages.search)}
114
+ />
115
+ <button aria-label={intl.formatMessage(messages.search)}>
116
+ <Icon name={zoomSVG} size="37px" />
117
+ </button>
118
+ </Form.Field>
119
+ </Form>
120
+ );
121
+ }
122
+ }
123
+
124
+ export default compose(withRouter, injectIntl)(IntranetSearchWidget);
@@ -5,46 +5,42 @@
5
5
 
6
6
  import React from 'react';
7
7
  import PropTypes from 'prop-types';
8
- import {
9
- hasBlocksData,
10
- flattenHTMLToAppURL,
11
- expandToBackendURL,
12
- } from '@plone/volto/helpers';
13
- import {
14
- Image,
15
- Grid,
16
- Button,
17
- Container as SemanticContainer,
18
- } from 'semantic-ui-react';
8
+ import { hasBlocksData, flattenHTMLToAppURL } from '@plone/volto/helpers';
9
+ import { Container as SemanticContainer } from 'semantic-ui-react';
19
10
  import RenderBlocks from '@plone/volto/components/theme/View/RenderBlocks';
20
11
 
21
12
  import { FormattedDate } from '@plone/volto/components';
22
13
  import config from '@plone/volto/registry';
23
- import { UniversalLink } from '@plone/volto/components';
24
14
  import { FormattedMessage, injectIntl } from 'react-intl';
25
15
 
26
- const EventTextfieldView = ({ content }) => (
27
- <React.Fragment>
28
- {content.title && <h1 className="documentFirstHeading">{content.title}</h1>}
29
- {content.description && (
30
- <p className="documentDescription">{content.description}</p>
31
- )}
32
- {content.image && (
33
- <Image
34
- className="document-image"
35
- src={content.image.scales.thumb.download}
36
- floated="right"
37
- />
38
- )}
39
- {content.text && (
40
- <div
41
- dangerouslySetInnerHTML={{
42
- __html: flattenHTMLToAppURL(content.text.data),
43
- }}
44
- />
45
- )}
46
- </React.Fragment>
47
- );
16
+ const EventTextfieldView = ({ content }) => {
17
+ const Image = config.getComponent({ name: 'Image' }).component;
18
+ return (
19
+ <React.Fragment>
20
+ {content.title && (
21
+ <h1 className="documentFirstHeading">{content.title}</h1>
22
+ )}
23
+ {content.description && (
24
+ <p className="documentDescription">{content.description}</p>
25
+ )}
26
+ {content.preview_image && (
27
+ <Image
28
+ className="document-image ui right floated image"
29
+ item={content}
30
+ imageField="preview_image"
31
+ alt=""
32
+ />
33
+ )}
34
+ {content.text && (
35
+ <div
36
+ dangerouslySetInnerHTML={{
37
+ __html: flattenHTMLToAppURL(content.text.data),
38
+ }}
39
+ />
40
+ )}
41
+ </React.Fragment>
42
+ );
43
+ };
48
44
 
49
45
  /**
50
46
  * EventView view component class.
@@ -91,148 +87,7 @@ const EventView = (props) => {
91
87
  </div>
92
88
  {hasBlocksData(content) ? (
93
89
  <>
94
- <RenderBlocks
95
- {...props}
96
- content={{
97
- ...content,
98
- blocks_layout: {
99
- items: props.content.blocks_layout.items.slice(0, 1),
100
- },
101
- }}
102
- />
103
- <Grid stackable className="details-container">
104
- <Grid.Row columns={2}>
105
- <Grid.Column>
106
- <div>
107
- <div className="event-title">
108
- <span className="event-heading">
109
- <FormattedMessage id="Start" defaultMessage="Start" />
110
- </span>
111
- <div className="event-detail">
112
- {' '}
113
- <FormattedDate
114
- date={content?.start}
115
- format={dateOptions}
116
- />{' '}
117
- {props.intl.locale === 'de' ? ' Uhr' : ''}
118
- </div>
119
- <div className="separator"></div>
120
- </div>
121
- <div className="event-title">
122
- <span className="event-heading">
123
- {' '}
124
- <FormattedMessage id="End" defaultMessage="End" />
125
- </span>
126
- <div className="event-detail">
127
- {' '}
128
- <FormattedDate
129
- date={content?.end}
130
- format={dateOptions}
131
- />{' '}
132
- {props.intl.locale === 'de' ? ' Uhr' : ''}
133
- </div>
134
- <div className="separator"></div>
135
- </div>
136
- {content?.location && (
137
- <div className="event-title">
138
- <span className="event-heading">
139
- <FormattedMessage
140
- id="Location"
141
- defaultMessage="Location"
142
- />
143
- </span>
144
- <div className="event-detail">{content?.location}</div>
145
- </div>
146
- )}
147
- </div>
148
- </Grid.Column>
149
- <Grid.Column>
150
- <div>
151
- {content?.event_url && (
152
- <div className="event-title">
153
- <span className="event-heading">
154
- <FormattedMessage
155
- id="Website"
156
- defaultMessage="Website"
157
- />
158
- </span>
159
- <div className="event-detail">
160
- <UniversalLink
161
- className="event-url"
162
- href={content.event_url}
163
- >
164
- {content.event_url}
165
- </UniversalLink>
166
- </div>
167
- <div className="separator"></div>
168
- </div>
169
- )}
170
-
171
- {(content?.contact_name ||
172
- content?.contact_email ||
173
- content?.contact_email) && (
174
- <div className="event-title">
175
- <span className="event-heading">
176
- <FormattedMessage
177
- id="Contact"
178
- defaultMessage="Contact"
179
- />
180
- </span>
181
- <div className="event-detail">
182
- <div>
183
- {content?.contact_name && (
184
- <p>{content.contact_name}</p>
185
- )}
186
- {content?.contact_email && (
187
- <p>
188
- <a href={`mailto:${content.contact_email}`}>
189
- {content.contact_email}
190
- </a>
191
- </p>
192
- )}
193
- {content?.contact_phone && (
194
- <p>
195
- <FormattedMessage
196
- id="Phone"
197
- defaultMessage="Phone"
198
- />{' '}
199
- <a href={`tel:${content.contact_phone}`}>
200
- {content.contact_phone}
201
- </a>
202
- </p>
203
- )}
204
- </div>
205
- </div>
206
- </div>
207
- )}
208
- </div>
209
- </Grid.Column>
210
- <div className="event-button">
211
- <a
212
- className="ics-download"
213
- target="_blank"
214
- rel="noreferrer"
215
- href={`${expandToBackendURL(content['@id'])}/ics_view`}
216
- >
217
- <Button className="event-btn">
218
- <FormattedMessage
219
- id="ICS-Download"
220
- defaultMessage="ICS Download"
221
- />
222
- </Button>
223
- </a>
224
- </div>
225
- </Grid.Row>
226
- </Grid>
227
- <RenderBlocks
228
- {...props}
229
- content={{
230
- ...content,
231
- blocks_layout: {
232
- items: props.content.blocks_layout.items.slice(1),
233
- },
234
- }}
235
- />
90
+ <RenderBlocks {...props} />
236
91
  </>
237
92
  ) : (
238
93
  <EventTextfieldView {...props} />
package/src/index.js CHANGED
@@ -10,6 +10,7 @@ import { videoBlockSchemaEnhancer } from './components/Blocks/Video/schema';
10
10
  import { gridTeaserDisableStylingSchema } from '@plone/volto/components/manage/Blocks/Teaser/schema';
11
11
  import { gridImageDisableSizeAndPositionHandlersSchema } from '@plone/volto/components/manage/Blocks/Image/schema';
12
12
  import { disableBgColorSchema } from './components/Blocks/disableBgColorSchema';
13
+ import BlockSettingsSchema from '@plone/volto/components/manage/Blocks/Block/Schema';
13
14
 
14
15
  import ContainerQueriesPolyfill from './components/CQPolyfill';
15
16
  import Container from './components/Atoms/Container/Container';
@@ -27,10 +28,12 @@ import { searchBlockSchemaEnhancer } from './components/Blocks/Search/schema';
27
28
 
28
29
  import gridSVG from './icons/block_icn_grid.svg';
29
30
  import accordionSVG from './icons/block_icn_accordion.svg';
31
+ import descriptionSVG from '@plone/volto/icons/description.svg';
30
32
  import EventView from './components/Theme/EventView';
31
33
  import { tocBlockSchemaEnhancer } from './components/Blocks/Toc/schema';
32
34
  import { mapsBlockSchemaEnhancer } from './components/Blocks/Maps/schema';
33
35
  import { sliderBlockSchemaEnhancer } from './components/Blocks/Slider/schema';
36
+ import EventMetadataView from './components/Blocks/EventMetadata/View';
34
37
 
35
38
  const BG_COLORS = [
36
39
  { name: 'transparent', label: 'Transparent' },
@@ -55,11 +58,26 @@ const applyConfig = (config) => {
55
58
  config.settings.slate.useLinkedHeadings = false;
56
59
  config.settings.contentMetadataTagsImageField = 'preview_image';
57
60
 
61
+ // Initial block for event content type
62
+ config.blocks.initialBlocks = {
63
+ Event: [
64
+ { '@type': 'title' },
65
+ { '@type': 'eventMetadata', fixed: true, required: true },
66
+ { '@type': 'slate' },
67
+ ],
68
+ };
69
+
70
+ config.settings.siteLabel = '';
71
+ config.settings.intranetHeader = false;
72
+
58
73
  // Remove Hero Block
59
74
  config.blocks.blocksConfig.hero.restricted = true;
60
75
 
61
76
  // No required blocks (eg. Title)
62
- config.blocks.requiredBlocks = [];
77
+ config.blocks.requiredBlocks = [
78
+ ...config.blocks.requiredBlocks,
79
+ 'eventMetadata',
80
+ ];
63
81
 
64
82
  // Register custom Container component
65
83
  config.registerComponent({
@@ -296,6 +314,20 @@ const applyConfig = (config) => {
296
314
  colors: BG_COLORS,
297
315
  };
298
316
 
317
+ config.blocks.blocksConfig.eventMetadata = {
318
+ id: 'eventMetadata',
319
+ title: 'EventMetadata',
320
+ icon: descriptionSVG,
321
+ group: 'common',
322
+ view: EventMetadataView,
323
+ edit: EventMetadataView,
324
+ schema: BlockSettingsSchema,
325
+ restricted: ({ properties, block }) =>
326
+ properties['@type'] === 'Event' ? false : true,
327
+ mostUsed: false,
328
+ sidebarTab: 0,
329
+ };
330
+
299
331
  // Check if the separator is present before enhancing it
300
332
  if (config.blocks.blocksConfig?.separator?.id) {
301
333
  config.blocks.blocksConfig.separator = {
@@ -96,6 +96,7 @@
96
96
  border: none;
97
97
  border-radius: 50%;
98
98
  background-color: transparent;
99
+ color: $black;
99
100
  transition:
100
101
  background-color 200ms ease-in-out,
101
102
  color 300ms ease-in-out;
@@ -220,8 +221,25 @@
220
221
  .tools-wrapper {
221
222
  display: flex;
222
223
  flex-direction: row-reverse;
224
+ justify-content: space-between;
223
225
  padding-top: 16px;
224
226
 
227
+ .intranet {
228
+ padding: 10px $spacing-small;
229
+ margin-top: -16px;
230
+ margin-left: 213px;
231
+ background-color: $secondary-grey;
232
+ @media only screen and (max-width: $narrow-container-width) {
233
+ margin-left: 0px;
234
+ }
235
+
236
+ p {
237
+ @include marginal-title();
238
+ font-weight: 400;
239
+ text-transform: capitalize;
240
+ }
241
+ }
242
+
225
243
  .language-selector {
226
244
  padding-left: 40px;
227
245
  }
@@ -265,6 +283,99 @@
265
283
  }
266
284
  }
267
285
 
286
+ // Intranet Header
287
+
288
+ .header-wrapper.intranet-header {
289
+ .header {
290
+ flex-direction: column;
291
+
292
+ .logo-nav-wrapper {
293
+ flex-wrap: wrap;
294
+ justify-content: flex-start;
295
+
296
+ .logo {
297
+ flex: 0 1 auto;
298
+ }
299
+
300
+ @media only screen and (max-width: $narrow-container-width) {
301
+ position: relative;
302
+ }
303
+
304
+ .mobile-nav.mobile.only {
305
+ @media only screen and (max-width: $narrow-container-width) {
306
+ position: absolute;
307
+ top: 19px;
308
+ right: 0;
309
+ }
310
+
311
+ .menu-drawer {
312
+ @media only screen and (max-width: $computer-breakpoint) {
313
+ top: 210px;
314
+ }
315
+ }
316
+ }
317
+ .navigation {
318
+ flex-basis: 100%;
319
+ margin: 29px auto 0 auto;
320
+ }
321
+ }
322
+
323
+ .search-wrapper {
324
+ flex: 0 1 auto;
325
+ align-self: center;
326
+ margin-left: 209px;
327
+ @media only screen and (max-width: $narrow-container-width) {
328
+ width: 100%;
329
+ margin-left: 0%;
330
+ }
331
+
332
+ .search {
333
+ width: 100%;
334
+ border-bottom: 2px solid $secondary-grey;
335
+ .field.searchbox {
336
+ border: none;
337
+
338
+ .ui.input input {
339
+ width: 500px;
340
+
341
+ &::placeholder {
342
+ color: #808080;
343
+ @include body-text();
344
+ }
345
+ @media only screen and (max-width: $narrow-container-width) {
346
+ width: 100%;
347
+ }
348
+ }
349
+
350
+ button {
351
+ @media only screen and (max-width: $narrow-container-width) {
352
+ padding-left: 9px;
353
+ }
354
+ &:hover {
355
+ background-color: transparent;
356
+ color: $black;
357
+ cursor: pointer;
358
+ }
359
+ }
360
+ }
361
+ }
362
+ }
363
+
364
+ .tools-wrapper {
365
+ justify-content: space-between;
366
+ @media only screen and (max-width: $narrow-container-width) {
367
+ flex-direction: row;
368
+ }
369
+
370
+ .tools {
371
+ @media only screen and (max-width: $narrow-container-width) {
372
+ display: none;
373
+ }
374
+ }
375
+ }
376
+ }
377
+ }
378
+
268
379
  /* we have to align the search hide with desktop naviation hide.
269
380
  And destktop navigation uses different breakpoint for different mode and it is coming
270
381
  from volto core */
@@ -409,6 +520,7 @@ body.has-toolbar.has-sidebar {
409
520
  color: $white;
410
521
 
411
522
  a {
523
+ padding-bottom: 0;
412
524
  font-size: 14px;
413
525
  font-weight: 400;
414
526
  line-height: 18px;
@@ -490,12 +602,7 @@ body.has-toolbar.has-sidebar {
490
602
  }
491
603
  }
492
604
 
493
- li {
494
- position: relative;
495
- padding-top: 0;
496
- }
497
-
498
- li a.current {
605
+ a.current {
499
606
  .left-arrow {
500
607
  visibility: visible;
501
608
  }
@@ -513,14 +620,13 @@ body.has-toolbar.has-sidebar {
513
620
  display: flex;
514
621
  }
515
622
 
516
- li {
517
- padding: 8px 0;
518
- }
519
-
520
- li a {
623
+ a {
624
+ position: relative;
521
625
  display: inline-flex;
522
626
  align-items: flex-start;
627
+ padding-bottom: 8px;
523
628
  color: $black;
629
+
524
630
  @include body-text-bold();
525
631
 
526
632
  span {