Events listing template#
One of the most used blocks in Volto is the listing block. It allows editors to automatically list contents on a page that fit a certain criteria (e.g. all pages of a specific content type). To always display content in the most visually useful way (you might want a list of upcoming events look different to a list of the latest projects of your company) the listing has the possibility to appear in different visual templates. In vanilla volto those are the default
, summary
and image gallery
templates. To learn how to create a new listing template we will recreate the Plone upcoming events listing from a bit further down the page.
create some dummy events to display#
At the moment of writing this training there were 2 Events "Plone Conf 2022" and "2022 Meeting of the Plone Foundation". To have some events to display in your listing, create at least 2 pages of the type event somewhere on the page with a title, date and location.
create the actual template#
Inside of your components/Blocks/
directory create a new folder called listing
and in there a file eventListingTemplate.jsx
. Before we create the proper template we will first create a simple mock like this:
import React from "react";
const eventListingTemplate = ({ items }) => {
return (
<div>
<h2>Events:</h2>
{items.map((item) => (
<ul>
<li>{item.title}</li>
</ul>
))}
</div>
);
};
export default eventListingTemplate;
Export the component from the index.js
as you already did with the Block View components and import it to your config.js
:
import {
HighlightBlockView,
HighlightBlockEdit,
DownloadLinkBlockEdit,
DownloadLinkBlockView,
eventListingTemplate,
}
After that you can add your template to the list of available listing templates by adding this to the applyConfig
function:
config.blocks.blocksConfig.listing.variations = [
...config.blocks.blocksConfig.listing.variations,
{
id: "eventListing",
title: "Events",
template: eventListingTemplate,
},
];
This should be enough to show make the "Events" template choosable when adding a listing Block. Add a listing Block to your page, and set it to filter for elements of the Type
Event
. Choose Events
as the template at the top of your block.
Style the template properly#
To style the template, replace the code from eventListingTemplate.jsx
with:
import React from "react";
import { Grid } from "semantic-ui-react";
import { UniversalLink } from "@plone/volto/components";
import moment from "moment";
const eventListingTemplate = ({ items }) => {
console.log(items);
return (
<Grid columns={3}>
<Grid.Column width={4}>
<div className="text-col">
<h2>
<UniversalLink href="/events">Upcoming events</UniversalLink>
</h2>
<p>
The Plone community regularly meets for sprints, conferences,
training classes, and symposia.
</p>
<UniversalLink href="/add?type=Event" className="ui button">
Add an event
</UniversalLink>
<br />
<UniversalLink href="/add?type=sprint" className="ui button">
Add a sprint
</UniversalLink>
<br />
<UniversalLink href="/add?type=News Item" className="ui button">
Add a news item
</UniversalLink>
<br />
<UniversalLink href="events" className="ui button">
All events
</UniversalLink>
</div>
</Grid.Column>
<Grid.Column width={8} className="listing-col">
<Grid columns={2}>
{items.map((item) => (
<Grid.Column width={5} className="item">
<UniversalLink href={item["@id"]}>
<div className="date">
{moment(item.start).format("MMMM D, YYYY")}
</div>
<div className="item-body">
<h3>{item.title}</h3>
<p className="location">{item.location}</p>
</div>
</UniversalLink>
</Grid.Column>
))}
</Grid>
</Grid.Column>
</Grid>
);
};
export default eventListingTemplate;
Note that the moment
js is imported into the component to properly format the dates of the events.
To finish the styling, now paste the provided CSS to your custom.overrides
:
.block.listing.eventListing {
background: #e8eef2;
.text-col {
background: #d8e2e9;
margin: 15px;
padding: 15px;
h2 {
font-size: 30px;
}
p {
font-size: 21px;
font-weight: 300;
}
a.ui.button {
color: @white;
font-weight: normal;
background-color: #00608b;
border: solid 1px #004767;
margin-bottom: 10px;
}
}
.listing-col {
.item {
background: @white;
padding: 0;
margin: 1em;
.date {
background: #1f1238;
color: @white;
text-transform: uppercase;
text-align: right;
padding: 5px 10px;
font-weight: 600;
font-size: 20px;
}
.item-body {
margin: 10px;
h3 {
font-size: 24px;
margin-bottom: 10px;
font-weight: bold;
}
.location {
color: @grey;
font-weight: bold;
}
}
}
}
}