Building a badges section with Metalsmith and Nunjucks

A badge section has many uses. It can be used to list features, customers, awards, etc. List items may be just an image or an icon, it may include a title and some prose and it may include a link to other resources. Today's corporate websites are full of examples.

In this post we'll build such a section for awards with Metalsmith with Nunjucks templating.

The context for this implementation is as follows: We have a several awards, all listed in a JSON file that is located in src/data/awards.json. These awards are available for display but we like to be in control of which one to list and in what order. We achieve that by using a select list in our sections object.

Badges section

- section: badges
    sectionClass: "example"
    animateSection: true
    inContainer: true
    hasBackground: false
    backgroundColor: ""
    backgroundIsDark: false
    marginTop: true
    marginBottom: true
    paddingTop: false
    paddingBottom: false
    text:
      title: Awards.
      header: "h2"
      subtitle: Look at how many awards we have won.
      prose: "We keep trying and they are piling up."
    list:
      source: awards
      selections:
        - title: "Award1"
        - title: "Award2" 
        - title: "Award3"
        - title: "Award4"
        - title: "Award5"
    hasCtas: true
    ctas:
      - url: "/base-components/"
        label: Check out our award winning products
        isExternal: false
        isButton: false
        buttonStyle: "primary"

Besides a common set of section properties, the section object is composed of the base components text, list and ctas. list provides the source and a list of awards we like to show. We only need to list the titles of the awards as all other awards info is available in awards.json.

The source property is the name of the metadata key under which we can access all awards information. We use the @metalsmith/metadata plugin to inject the awards.json file into the metalsmith metadata.

awards.json

[
  {
    "title": "Award1",
    "url": "https://www.youtube.com/watch?v=Cgl4jdI9zRg",
    "image": "",
    "icon": "feather",
    "description": "Morbi leo risus, porta ac consectetur ac, vestibulum at eros."
  },
  {
    "title": "Award2",
    "url": "",
    "image": "v1650325427/metalsmith-components/awards/award6_sono17.jpg",
    "description": "Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor."
  },
  {
    "title": "Award3",
    "url": "",
    "image": "v1650325427/metalsmith-components/awards/award3_ct4nrh.jpg",
    "description": "Fusce dapibus, tellus ac cursus commodo, tortor mauris."
  },
  {
    "title": "Award4",
    "url": "https://www.youtube.com/watch?v=EcHiDVv-2xw",
    "image": "v1650325427/metalsmith-components/awards/award1_s925ma.jpg",
    "description": "Maecenas faucibus mollis interdum."
  },
  {
    "title": "Award5",
    "url": "",
    "image": "v1650325427/metalsmith-components/awards/award4_oehdu3.jpg",
    "description": "Curabitur blandit tempus porttitor."
  },
  {
    "title": "Award6",
    "url": "",
    "image": "v1650325427/metalsmith-components/awards/award5_whkzuo.jpg",
    "description": "Praesent commodo cursus magna, vel scelerisque nisl consectetur et."
  }
]

badges.njk

{% from "../partials/ctas.njk" import ctas %}
{% from "../partials/text.njk" import text %}
{% from "../partials/list.njk" import list %}


{# this section receives props params and site #}

<section 
  class="section-badges {{ params.sectionClass }}{{ " paddingTop" if params.paddingTop }}{{ " paddingBottom" if params.paddingBottom }}">
  <div class="content">
    
    {{ text(params.text)}}

    {# list source is specified in the params. Source is metadata object that was built from data files #}
    {% if params.list.source === "awards" %}
      {% set source = awards | filterList(params.list.selections) %}
    {% endif %}
    {{ list(params.list, source, site)}}
        
    {% if params.hasCtas %}
      {{ ctas(params.ctas) }}
    {% endif %}
    
  </div>
</section>

Note that we use a Nunjucks filter to arrive at the awards to be displayed. In the above code section we filter the metadata objet awards with the selections object and set source with the resulting objects.

The Nunjucks filter is implemented like this:

const filterList = (list, selections) => {
  const filterredList = [];
  for (let i = 0; i < list.length; i++) {
    for (let j = 0; j < selections.length; j++) {
      if (list[i].title === selections[j].title) {
        filterredList.push(list[i]);
      }
    }
  }
  return filterredList;
};

list.njk

{% from "../partials/icon.njk" import icon %}

{% macro list(info, source, siteMeta) %}
  <ul class="badges-list {info.source}-list">
    {# filter the list with selection from frontmatter #}
    {% for item in source %}

      {% if item.show %}
      <li>
        {% if item.url %}
        <a href="{{ item.url }}">
          
          {% if item.image %}
          {% set imagesrc = siteMeta.imagePrefix ~ "w_100,c_fill,g_auto,f_auto/" ~ item.image %}
          <img src="{{ imagesrc }}" alt="{{ item.title }}">
          {% endif %}

          {% if item.icon %}
          {% set iconSource = item.icon %}
          {{ icon(iconSource) }}
          {% endif %}
          
          {% if item.title %}
          <h4>{{ item.title }}</h4>
          {% endif %}
          
          {% if item.description %}
          <div>{{ item.description | mdToHTML | safe }}</div>
          {% endif %}

        </a>

        {% else %}

        <span>
          
          {% if item.image %}
          {% set imagesrc = siteMeta.imagePrefix ~ "w_100,c_fill,g_auto,f_auto/" ~ item.image %}
          <img src="{{ imagesrc }}" alt="{{ item.title }}">
          {% endif %}

          {% if item.icon %}
          {% set iconSource = item.icon %}
          {{ icon(iconSource) }}
          {% endif %}
          
          {% if item.title %}
          <h4>{{ item.title }}</h4>
          {% endif %}
          
          {% if item.description %}
          <div>{{ item.description | mdToHTML | safe }}</div>
          {% endif %}

        </span>
        {% endif %}
      </li>
      {% endif %}
    {% endfor %}
  </ul>
{% endmacro %}

The result is a badges section as shown below.

Scroll to top