Lesson 16 - Creating a work item page

Course
Learn Eleventy From Scratch
Module
Let’s build a website

Time to add a core page to the site and learn about linked content.


The first part of this lesson is another chance to apply what we’ve learned previously by creating our work item page.

We’ll then go one step further and learn how you can create relationships with content by linking team members to the items they worked on.

Adding our template permalink

Create a new file in your layouts folder called work-item.html and add the following to it:

Code language
HTML
{% extends "layouts/base.html" %}  

{% block content %}
<section class="work-item">
  <header class="hero">
    <div class="[ hero__inner ] [ wrapper ]">
      <div class="[ hero__content ] [ dot-shadow radius flow ] [ bg-dark-shade color-light flow-space-400 ]">
        <h1 class="[ headline ] [ measure-compact ]" data-highlight="quinary">
          {{ title }}
        </h1>
        <p class="measure-short">{{ summary }}</p>
      </div>
    </div>
    <img src="{{ hero.image }}" alt="{{ hero.imageAlt }}" class="hero__image" />
  </header>
  <article class="[ key-facts ] [ panel dot-shadow ] [ bg-primary-shade color-light ]">
    <div class="wrapper flow">
      <h2 class="headline" data-highlight="secondary">Key facts</h2>
      <div class="leading-flat font-sans weight-bold flow-space-700">
        <ol class="[ key-facts__list ] [ auto-grid ]">
          {% for item in keyFacts %}
            <li class="flow flow-space-300">
              <span class="text-700 lg:text-800 color-secondary-glare"
                >{{ item.primary }}</span
              >
              <span class="text-600 lg:text-700">{{ item.secondary }}</span>
            </li>
          {% endfor %}
        </ol>
      </div>
    </div>
  </article>
  <div class="wrapper">
    <article class="[ gallery ] [ flow flow-space-800 ]">
      {% for item in gallery %}
        <figure class="[ gallery__item ] [ flow ]">
          <div class="[ gallery__media ] [ frame ]" data-frame="primary">
            <img src="{{ item.image }}" alt="" aria-hidden="true" class="radius" />
          </div>
          <figcaption class="[ gallery__content ] [ flow ]">
            <h2 class="[ gallery__heading ] [ text-700 md:text-900 ]">
              {{ item.title }}
            </h2>
            <p class="[ gallery__summary ] [ measure-short flow-space-300 ]">
              {{ item.summary }}
            </p>
          </figcaption>
        </figure>
      {% endfor %}
    </article>
  </div>
</section>

{% include "partials/cta.html" %} 

{% endblock %}

This should be all pretty straightforward for you by now, because we’ve already covered a lot it in this course. We’re grabbing Front Matter and applying it on the page. The gallery and keyFacts are both arrays of objects that we loop through and generate collections of content.

The gallery uses <figure> elements for the same reason as we covered earlier in the course: they are contained pieces of content with media and flow content.

So far, so straightforward, right? Let’s turn up the heat a bit.

Let’s spend a second thinking about our site’s context. It’s a website for a design agency and this template we’re working on is used for a portfolio item. These items will have had team members working on them. If you open up eleventy-from-scratch/src/work/outgoings.md and scroll to the end of the Front Matter, you should see this:

Code language
Diff - don’t copy
team: [1, 4, 6]
---

These reference items from the people collection which each have a key in their Front Matter. This key is used like an ID field and is what the team section of the work item Front Matter is referencing.

To break it down, we’re saying that team members 1, 4 and 6 worked on this project together. We need to find those team members in the people collection and put them on the page. The first thing we’ll do is grab them by creating a handy helper function.

Open up eleventy-from-scratch/src/_data/helpers.js. At the bottom of the file, inside of the last };, add the following:

Code language
JavaScript
/**
 * Take an array of keys and return back items that match.
 * Note: items in the collection must have a key attribute in
 * Front Matter
 *
 * @param {Array} collection 11ty collection
 * @param {Array} keys collection of keys
 * @returns {Array} result collection or empty
 */
filterCollectionByKeys(collection, keys) {
  return collection.filter(x => keys.includes(x.data.key));
}

Remember to add a comma at the end of the function that comes before this new one. The closing bracket of the previous function looked like this: }. It should now look like this: },.

Without this, the JavaScript will break.

The documentation on that function explains what it does for us. It takes a passed collection and some keys (array of numbers) and then, using filter(), returns back items that belong in keys.

Let’s apply this helper to our template. Open up eleventy-from-scratch/src/_includes/layouts/work-item.html. Just before the {% block content %} part, add the following:

Code language
HTML
{% set peopleItems = helpers.filterCollectionByKeys(collections.people, team) %}

What we do here is grab the people collection and then pass in the team array that’s set in our Front Matter. This will then return 3 people that match that criteria, which is now available in peopleItems.

Now we have that data, let’s render it. At the bottom of work-item.html, just before the closing </section>: add the following:

Code language
HTML
{% if peopleItems %}
  <article class="[ no-js-hidden ] [ panel dot-shadow ] [ bg-light-glare ]">
    <div class="[ wrapper ] [ flow flow-space-700 ]">
      <h2 class="[ headline ] [ measure-micro color-quinary ]" data-highlight="dark">
        Meet the team behind this project
      </h2>
      {% include "partials/people.html" %}
    </div>
  </article>
{% endif %}

Remember how peopleItems provides the partials/people.html with data for us? Well now that we’ve loaded peopleItems, via our helper, we can render them with this existing code. The rest of the HTML is providing us with some semantics and structure.

Assigning our layout to our work items permalink

Now we have all the code written we need to instruct all work items to use our new layout—just like with the posts in previous lessons.

Create a new file in your work folder called work.json and add the following.

Code language
json
{
  "layout": "layouts/work-item.html"
}

If you open up your browser at http://localhost:8080/work/outgoings/ it should now look like this:

The work landing page, rendered with a title and large hero image

Wrapping up permalink

Relationships between content aren’t often mentioned in coverage about SSGs like Eleventy, and I wanted to change that in this course. Creating this sort of relationship is really useful for when you’re building large sites.

The beauty of using a consistent key item in Front Matter (it could also be id if you wanted) is that we can also create flexible helpers to grab content for us, too.

Right, let’s move onto the last lesson of this module 🎉


Comments

Next up: Lesson 17 - Meta info, RSS feeds and module recap

Let’s wrap up our HTML-only build of the website and recap on where we’ve got to.

Get started

Help! My version of this lesson isn’t working.

Don’t panic, you can download the working project here! Once they are downloaded: replace your project with these files and run npm install. You can read more information here.

Download project files

Hello, I’m Andy and I’ll help you build fast, accessible websites & design systems.

I’m a freelance CSS and design systems consultant, based in the UK. I specialise in design systems and creative web design, such as landing pages and campaign work.

I’m currently helping Google by refactoring the CSS and creating a design system for web.dev, but I have availability for projects such as small websites, landing pages and consultancy. I will have full availability for larger projects in January 2022.

Hire me