Trio Icon
Trio v6.1.0

The Trio Blog

  1. Latest
  2. Releases
  3. News
  4. Tutorials

Advanced Page Composition With Fragment Front Matter

a web page composition abstract

Prerequisites

Before proceeding with this tutorial, please familiarize yourself with Trio's Core Concepts, Tag-Based Callbacks, and Metadata.

Intention Of This Tutorial

In this tutorial we will explore Trio's advanced page composition. Unlike basic page composition, which was the subject of the previous tutorial, Basic Page Composition With Templates, Fragments And Includes, advanced page composition does require the use of tag-based Node callback modules.

Our use case for this tutorial is again trivial and is the same as it was for the previous tutorial. We want Trio to generate an HTML page that contains a page header and a list containing the names of artist and their relevant information. If we were to hand code this HTML page, this is what it would look like:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hand Coded</title>
</head>

<body>
    <header>Artists Registry</header>
    <main>
        <h2>Artists</h2>
        <ul>
            <li>Billie Noble</li>
            <ul>
                <li>Medium: Oil</li>
                <li>Style: Post-Impressionism</li>
            </ul>

            <li>Blair Gordonlist</li>
            <ul>
                <li>Medium: Oil</li>
                <li>Style: Pop Art</li>
            </ul>

            <li>Caden Ray</li>
            <ul>
                <li>Medium: Watercolor</li>
                <li>Style: Art Nouveau</li>
            </ul>

            <li>Danni Powell</li>
            <ul>
                <li>Medium: Watercolor</li>
                <li>Style: Pop Art</li>
            </ul>

            <li>Glen Miller</li>
            <ul>
                <li>Medium: Watercolor</li>
                <li>Style: Impressionism</li>
            </ul>

            <li>Kris Jay</li>
            <ul>
                <li>Medium: Oil</li>
                <li>Style: Pop Art</li>
            </ul>

            <li>Riley Webb</li>
            <ul>
                <li>Medium: Oil</li>
                <li>Style: Cubism</li>
            </ul>

            <li>Steff Hammer</li>
            <ul>
                <li>Medium: Oil</li>
                <li>Style: Impressionism</li>
            </ul>

            <li>Terry Shannon</li>
            <ul>
                <li>Medium: Oil</li>
                <li>Style: Impressionism</li>
            </ul>

            <li>Vic Christy</li>
            <ul>
                <li>Medium: Oil</li>
                <li>Style: Art Deco</li>
            </ul>
        </ul>
    </main>
</body>

</html>

Create A New Project

In your terminal application, run the following command (please replace "path/to/new/project" with the actual path you would prefer for the location of your new project) to create a new project:

trio new path/to/new/project

Create The Template Project Asset

In the project's root/source/templates folder, create a new template file named default.html and copy and paste the following markup into that file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="/css/main.4b032a8bb77734ada3ae34e1a6cf849f.css">
</head>
<body>
    <header data-trio-include="header.md"></header>
    <main data-trio-fragment></main>
</body>
</html>

Please notice that the above template project asset contains a single tag (in this case, a "main" tag) that is decorated with the data-trio-fragment attribute. When Trio finds such a tag decorated with this attribute in a template it will target it with any content it finds in the associated fragment. This isn't required if the fragment isn't contributing any content of its own.

Create The Fragment Project Asset

In the project's root/source/fragments folder, create a new fragment file named index.html and copy and paste the following into that:

<!--
template: default
title: Coded Using Front Matter & Tag-based Callback
appendToTarget: true
artists:
- name: Terry Shannon
  medium: Oil
  style: Impressionism
- name: Glen Miller
  medium: Watercolor
  style: Impressionism
- name: Kris Jay
  medium: Oil
  style: Pop Art
- name: Riley Webb
  medium: Oil
  style: Cubism
- name: Vic Christy
  medium: Oil
  style: Art Deco
- name: Caden Ray
  medium: Watercolor
  style: Art Nouveau
- name: Steff Hammer
  medium: Oil
  style: Impressionism
- name: Billie Noble
  medium: Oil
  style: Post-Impressionism
- name: Danni Powell
  medium: Watercolor
  style: Pop Art
- name: Blair Gordonlist
  medium: Oil
  style: Pop Art
-->

<h2>Artists</h2>
<ul data-trio-callback="artistlistfromfrontmatter"></ul>

Please notice how the above fragment project asset declares front matter at the very top of the file, in which it defines:

  1. The required front matter property template with the name of the template file it is associated with and
  2. The required front matter property title with the title to be assigned to the generated document's title tag and
  3. The optional front matter property appendToTarget which Trio uses to determine if it should append to or replace the tag in the template that is decorated with the data-trio-fragment attribute with the fragment's content. By assigning true, Trio will append whatever content it finds in the associated fragment to this tag.
  4. The front matter property artists, which is an array of artists and their relevant data.

Also, please notice that the fragment's markup contains an unordered list tag decorated with the data-trio-callback attribute and that it is assigned the name of the tag-based callback (see below) which is located in the root/source/callbacks folder.

<ul data-trio-callback="artistlistfromfrontmatter"></ul>

Notice also that the file type of the tag-based callback is always assumed to be '.js' and can be omitted.

Tags decorated with the data-trio-callback attribute direct Trio to call the tag-based callbacks that they name, which in this case is root/source/callbacks/artistlistfromfrontmatter.js.

Create The Tag-Based Callback

In the project's root/source/callbacks folder, create a new javascript file named artistlistfromfrontmatter.js and copy and paste the following into that:

module.exports = ({ $tag, asset }) => {
    // get a reference to the artists array from the fragment's front matter
    const artists = asset.matter.data.artists;
    // sort the list by the artist's name
    artists.sort((a, b) => a.name.localeCompare(b.name)).forEach(artist => {
        // append each artist's name and relevant data to $tag
        $tag.append(`
            <li>${artist.name}</li>
            <ul>
                <li>Medium: ${artist.medium}</li>
                <li>Style: ${artist.style}</li>
            </ul>
        `);
    });
};

This _tag-based callback does the following:

  1. It accesses the array of artists declared in the fragments front matter using:
const artists = asset.matter.data.artists;
  1. Then sorts the artists array by artist name using:
artists.sort((a, b) => a.name.localeCompare(b.name))
  1. Then appends each artist's data to the tag that was decorated with the data-trio-callback attribute using:
forEach(artist => {
    $tag.append(`
        <li>${artist.name}</li>
        <ul>
            <li>Medium: ${artist.medium}</li>
            <li>Style: ${artist.style}</li>
        </ul>
    `);
});

How Trio Calls Your Tag-Based Callbacks

When Trio encounters a tag decorated with the data-trio-callback attribute, it calls the named callback passing it a single object which contains the following properties:

  1. $tag: A cheerio wrapper for the tag which was decorated with the data-trio-callback attribute. It can be used to target the tag with dynamic content, such as it was used in this example.
  2. $page: A cheerio function. It is equivalent to jQuery's $ and jQuery() functions and can be used to return a collection of matched tags in the composite when you are targeting tags other than $tag. We will examine $page's usage in a future tutorial in this series on composition.
  3. asset: Exposes the metadata specific to the fragment, including its front matter. Its catalogs - relatedArticlesByCategory, relatedArticlesByTag, relatedArticlesByTagFlattened - as well as its other properties can be used to augment your composites with dynamic content.
  4. site: Exposes the organized collection of metadata that Trio creates from your project's assets. Its catalogs - frags, articlesCatalog, categoriesCatalog, tagsCatalog, dataCatalog - as well as its other properties can be used to augment your composites with dynamic content. We will examine site's usage in future tutorial in this series on composition.
  5. cheerio: A cheerio constructor function that can be used to load and manipulate dynamic tag structures, such as:
const $ = cheerio.load('<h2 class="title">Hello world</h2>');

$('h2.title').text('Hello there!');
$('h2').addClass('welcome');

$.html();
//=> <html><head></head><body><h2 class="title welcome">Hello there!</h2></body></html>

Create The Include Project Asset

In the project's source/includes folder, create a new include file named header.md and copy and paste the following into that:

<!--
appendToTarget: true
-->

# Artists Registry

Please notice how the above include project asset declares front matter at the very top of the file which defines the optional boolean front matter property appendToTarget, which Trio uses to determine if it should append to or replace the tag in the template that is decorated with the data-trio-include="header.md" attribute with the include's content. By assigning true, Trio will append whatever content it finds in the include to this tag.

Build And Run The Project

Now that we have composed our intended page using a template, a fragment, and an include we are ready to build our site and render the page in the browser. In your terminal application, please run the following commands from the root folder of your project:

trio build; trio serve

If you prefer, you can use the abbreviated forms of these commands instead:

trio b; trio s

The build command instructs Trio to do a one-off build of your site for development and to place the site's generated output into the project's public/ folder. The serve command instructs Trio to serve the project's public/ folder's content in the browser.

When rendered in the browser the page that you created, public/index.html, should look like the following:

image

You can also view the content of the generated HTML document, which resides in public/index.html, by simply opening it in your editor of choice or by running cat public/index.html from the root of your project in the terminal. Let's take a look at it now:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Coded Using Front Matter &amp; Tag-based Callback</title>
    <link rel="stylesheet" href="/css/main.4b032a8bb77734ada3ae34e1a6cf849f.css">
</head>

<body>
    <header data-trio-include="header.md">
        <h1 id="artists-registry">Artists Registry</h1>
    </header>
    <main data-trio-fragment>
        <h2>Artists</h2>
        <ul data-trio-callback="artistlistfromfrontmatter">
            <li>Billie Noble</li>
            <ul>
                <li>Medium: Oil</li>
                <li>Style: Post-Impressionism</li>
            </ul>

            <li>Blair Gordonlist</li>
            <ul>
                <li>Medium: Oil</li>
                <li>Style: Pop Art</li>
            </ul>

            <li>Caden Ray</li>
            <ul>
                <li>Medium: Watercolor</li>
                <li>Style: Art Nouveau</li>
            </ul>

            <li>Danni Powell</li>
            <ul>
                <li>Medium: Watercolor</li>
                <li>Style: Pop Art</li>
            </ul>

            <li>Glen Miller</li>
            <ul>
                <li>Medium: Watercolor</li>
                <li>Style: Impressionism</li>
            </ul>

            <li>Kris Jay</li>
            <ul>
                <li>Medium: Oil</li>
                <li>Style: Pop Art</li>
            </ul>

            <li>Riley Webb</li>
            <ul>
                <li>Medium: Oil</li>
                <li>Style: Cubism</li>
            </ul>

            <li>Steff Hammer</li>
            <ul>
                <li>Medium: Oil</li>
                <li>Style: Impressionism</li>
            </ul>

            <li>Terry Shannon</li>
            <ul>
                <li>Medium: Oil</li>
                <li>Style: Impressionism</li>
            </ul>

            <li>Vic Christy</li>
            <ul>
                <li>Medium: Oil</li>
                <li>Style: Art Deco</li>
            </ul>
        </ul>
    </main>
</body>

</html>

From the above we can see that Trio in fact did as we had requested it to do by appending the fragment's content to the template's main tag that was decorated with the data-trio-fragment attribute and by appending the include's content to the template's header tag that was decorated with the data-trio-include="header.md" attribute.

Also note that because we built the project for development using Trio's build command, Trio preserved all the data-trio-* attributes. If we had instead built the project using Trio's release command, which is used to build your project prior to its release, Trio would have removed all the data-trio-* attributes from the generated pages.

And of course please note that the tag-based callback root/source/callbacks/artistlistfromfrontmatter.js declared by the <ul> tag that is decorated with the data-trio-callback attribute in the fragment

<ul data-trio-callback="artistlistfromfrontmatter"></ul>

was called and that it did dynamically generate list items from the artists array defined in the fragment's front matter and appended them as content to the <ul> tag.

Extra Credit

After each development build of your project, Trio persists most of the metadata that it collects to a file named root/trio.manifest.json. Please open this file now with your editor to view its contents. Please take note of this file's structure, particularly its top level keys and their associated values and how they relate to the project you created for this tutorial. Can you find the list of artists that you defined in the front matter of this project's fragment? What other keys and values do you see that match those of this tutorial's project?

The cool thing about this file is that you can reference it when you are coding your tag-based callbacks, like when you can't remember where to look for a particular piece of metadata that you are interested in.

Also, please refer to the Metadata doc page whenever you have a question about some aspect of Trio's collection of metadata.

Takeaways From This Tutorial

  1. Unlike basic page composition, Trio's advanced page composition allows you to incorporate dynamic content into you site's pages via Trio's tag-based callbacks, which can be declared multiple times throughout your project's template, fragment and include project assets.
  2. tag-based callbacks are declared by decorating tags with the data-trio-callback attribute and naming the callback which Trio expects to find in your project's root/source/callbacks folder.
  3. After having created your composite using basic page composition, Trio then acquires a list of all the tag-based callbacks declared in the composite and, if found, calls them in the order that they were declared, passing each callback a single object whose properties expose Trio's organized collection of metadata.
  4. Having access to the exposed metadata, your tag-based callbacks use cheerio's selector API to target specific tags in the composite to add dynamic content to.

Conclusion

This tutorial examined how you can use Trio's advanced page composition to add dynamic content contributed by a fragment's front matter to your site's HTML documents.

In the next tutorial in this series we will examine how you can add dynamic content contributed by JSON files located in the root/source/data folder of your project to your site's HTML documents.

Your Financial Support Of This Project Is Greatly Appreciated

Trio is an open source project and is therefore free of charge to use both for noncommercial and commercial use, but when you use Trio to create a new website, please consider donating a few bucks. It doesn't take very long, the process is secure, and it will allow us to continue to support the community and to maintain and enhance Trio going forward.

Show your ❤️, add your ★ to the Github repo.