25. Search block variation – Mastering Plone 6 development

Search block variation

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

Frontend chapter

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

block variation for the search block to show more than title and description

block variation for the search block to show more than title and description#

Apply listing variation

Apply listing variation#

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.