Community websites with Eleventy
Update: I did a talk about this in THE Eleventy Meetup 20.2.2024, you can watch a recording in Youtube.
Eleventy is a great and powerful static site generator especially for event-organizing communities like meetups. Here’s my setup that I use with both turkufrontend.fi and archipylago.dev.
On the root, I have _data
folder with 5
JSON files: events.json
,
history.json
,
team.json
,
sponsors.json
and
speakers.json
.
Events
For event logs, I have two files. One keeps track of current calendar (usually one spring or fall at a time) and another one is a full history of previous events.
Calendar
events.json
has an array of objects with
three keys. Dates are in YYYY-MM-DD format.
[
{
"date": "YYYY-MM-DD",
"host": "[Sponsor name]",
"url": "[URL for registration / event info]"
}
]
With events.njk
partial, these get
rendered (with Nunjucks) into a list as
<section>
<h2>Fall 2023</h2>
<div class="event-container">
<ul id="events">
{% for event in events %}
<li>
{{ event.date | toLocalDate }} @
{% if event.url %}
<a href="{{ event.url }}">
{{ event.host }}
</a>
{% else %}
{{ event.host | formatHost }}
{% endif %}
</li>
{% endfor %}
</ul>
</div>
<div style="text-align: center">
<a href="{{ '/history' | url }}">full history</a>
</div>
</section>
Each event lists the date and host and if URL is present, it links to the event page.
Full timeline
For a full history of events,
history.json
has an array of objects
such as
{
"date": "YYYY-MM-DD",
"host": "[Sponsor name]",
"talks": [
{
"title": "[Talk title]",
"speaker": "[Speaker name]",
"description": "[Talk abstract]",
"url": "[URL to slides/recording/etc]"
}
]
}
These are rendered with
history.njk
partial as
<div class="timeline-event">
<div class="timeline-header">
<div class="timeline-date">
{{ event.date | toLocalDateYear }}
</div>
<div class="timeline-host">
{{ event.host | formatSponsorLogoNoLink | safe }}
</div>
</div>
<div class="timeline-talks">
<ul>
{% for talk in event.talks %}
<li>
<strong>{{ talk.title }}</strong> by {{ talk.speaker }}
</li>
{% endfor %}
</ul>
</div>
</div>
Speakers, Sponsors and Team
Speakers
For speakers, I store a list of names in an array
[
"First Last",
"Firstname Lastname"
]
and accompanied with that, in
assets/img/speakers/
I have portraits of
the speakers in file name format
firstname-lastname.png
.
To render them into our hall of fame, I have a partial of
<div class="gallery">
{% for name in speakers %}
{{ name | formatHallOfFame | safe }}
{% endfor %}
</div>
where the formatHallOfFame
filter looks
like
formatHallOfFame: function (name) {
return `<div class="speaker">
<img src="/assets/img/speakers/${slugify(name)}.png" alt="">
<p>${name}</p>
</div>`;
}
Sponsors
Sponsors work similarly but has extra attribute of URL:
{
"name": "[Sponsor name]",
"url": "[URL to sponsor website]"
}
and these are rendered with
<section>
<h2>We are working with</h2>
<div id="sponsors">
{% for sponsor in sponsors %}
{{ sponsor | formatSponsorLogo | safe }}
{% endfor %}
</div>
</section>
with the filter
formatSponsorLogo: function ({ name, url }) {
const filename = `/assets/img/sponsors/${slugify(name)}.png`;
return `<a href="${url}" target=_blank><img src="${filename}" alt="${name}"></a>`;
},
Team
And finally the team is stored in
team.json
with each organizing team
member in an array:
[
{
"name": "[name]",
"title": "[title]",
"links": [
{
"icon": "[icon-name]",
"url": "[url]"
}
]
}
]
where icon-name
maps to SVGs I have
stored. For example,
"icon": "mastodon"
renders
mastodon.svg
icon.
This is rendered with
<section>
<h2>Team</h2>
<div id="team">
{% for person in team %}
<div class="profile">
{{ person.name | nameToImage | safe }}
<div class="profile--inner">
<p class="profile--name">
{{ person.name }}
</p>
<p class="profile--title">
{{ person.title }}
</p>
<div class="profile--links">
{% for link in person.links %}
{{ link | linkToHTML | safe }}
{% endfor %}
</div>
</div>
</div>
{% endfor %}
</div>
</section>
Updating the website
Since all these are stored in data files and rendered from them, making updates becomes a process of adding images (in case of new speakers/sponsors) and updating JSON files.
And since all the partials are in the
_includes/
folder, they can be included in any part of the website, making them flexible
components which makes making changes to the layouts easier when everything is
generated.
Comments
Loading comments...
Continue discussion in Mastodon »