25. Search block variation#
In this part you will:
Create a search block variation to display also the talks event date, room, audience and speaker name
Topics covered:
block variation
Checkout volto-ploneconf
at tag "upgrade_steps":
git checkout upgrade_steps
The code at the end of the chapter:
git checkout listing_variation
More info in The code for the training
25.1. Create and register new block variation#
Each block can be enhanced with variations of its layout. We are writing a block variation for the search block.
First step is to create a new component packages/volto-ploneconf/src/components/variations/TalkListingBlockVariation.jsx
with the code of an existing block variation core/packages/volto/src/components/manage/Blocks/Listing/SummaryTemplate.jsx
.
We register our new variation on config.blocks.blocksConfig.listing.variations
, as listing blocks and search blocks share their variations via this setting.
registration packages/volto-ploneconf/src/index.js
:
1import { TalkView, TalkListingBlockVariation } from './components';
2
3const applyConfig = (config) => {
4 config.views = {
5 ...config.views,
6 contentTypesViews: {
7 ...config.views.contentTypesViews,
8 talk: TalkView,
9 },
10 };
11
12 config.blocks.blocksConfig.listing.variations = [
13 ...config.blocks.blocksConfig.listing.variations,
14 {
15 id: 'talks',
16 title: 'Talks',
17 template: TalkListingBlockVariation,
18 },
19 ];
20
21 return config;
22};
23
24export default applyConfig;
variation component packages/volto-ploneconf/src/components/variations/TalkListingBlockVariation.jsx
:
1import React from 'react';
2import PropTypes from 'prop-types';
3import { Label, Segment } from 'semantic-ui-react';
4import { ConditionalLink, Component } from '@plone/volto/components';
5import { When } from '@plone/volto/components/theme/View/EventDatesInfo';
6import { flattenToAppURL } from '@plone/volto/helpers';
7
8import { isInternalURL } from '@plone/volto/helpers/Url/Url';
9
10const TalkListingBlockVariation = ({
11 items,
12 linkTitle,
13 linkHref,
14 isEditMode,
15}) => {
16 let link = null;
17 let href = linkHref?.[0]?.['@id'] || '';
18 const color_mapping_audience = {
19 beginner: 'green',
20 advanced: 'yellow',
21 professional: 'purple',
22 };
23
24 if (isInternalURL(href)) {
25 link = (
26 <ConditionalLink to={flattenToAppURL(href)} condition={!isEditMode}>
27 {linkTitle || href}
28 </ConditionalLink>
29 );
30 } else if (href) {
31 link = <a href={href}>{linkTitle || href}</a>;
32 }
33
34 return (
35 <>
36 <div className="items">
37 {items.map((item) => (
38 <Segment>
39 <div className="listing-item" key={item['@id']}>
40 <ConditionalLink item={item} condition={!isEditMode}>
41 <Component componentName="PreviewImage" item={item} alt="" />
42 <div className="listing-body">
43 <When
44 start={item.start}
45 end={item.end}
46 whole_day={item.whole_day}
47 open_end={item.open_end}
48 />
49 <h3>{item.title || item.id}</h3>
50 <p>{item.speaker}</p>
51 <p>
52 {item.room && (
53 <>
54 <b>Room: </b>
55 {item.room}
56 <br />
57 </>
58 )}
59 {item.audience?.length > 0 && (
60 <>
61 <b>Audience:</b>
62 {item.audience?.map((audience) => {
63 let color =
64 color_mapping_audience[audience] || 'green';
65 return (
66 <Label key={audience} color={color}>
67 {audience}
68 </Label>
69 );
70 })}
71 </>
72 )}
73 </p>
74 <p>{item.description}</p>
75 </div>
76 </ConditionalLink>
77 </div>
78 </Segment>
79 ))}
80 </div>
81
82 {link && <div className="footer">{link}</div>}
83 </>
84 );
85};
86
87TalkListingBlockVariation.propTypes = {
88 items: PropTypes.arrayOf(PropTypes.any).isRequired,
89 linkMore: PropTypes.any,
90 isEditMode: PropTypes.bool,
91};
92
93export default TalkListingBlockVariation;
This is a basic block variation. Block variations can have variations: See Block extensions mechanism for advanced techniques.