It doesn’t matter what stage you’re at as a developer, the duties we full—whether or not massive or small—make a huge effect in our private {and professional} development. Sadly, these duties aren’t at all times acknowledged as a result of they’ll simply get misplaced within the sea of different issues that must get executed.

The unnoticed duties we do fall beneath what is named “invisible work,” an idea I stumbled throughout from a chat titled “Getting Credit score for Invisible Work” by Ryan T. Harter. Such a work seeps into the cracks as a result of our brains should not wired to recollect issues. But come evaluate time, we discover ourselves repeatedly caught when making an attempt to recall what we did over the previous 6 or 12 months.

To unravel this long-established drawback, Julia Evans wrote an article suggesting that we maintain our personal “brag doc.” A brag doc is strictly what it appears like. It’s a doc the place you give your self permission to brag about all the dear work you probably did. Whether or not or not it’s:

  • The way you contributed to a mission
  • Serving to others
  • Bettering present processes
  • Giving talks or working workshops
  • What you discovered
  • Further-curricular actions (e.g. running a blog, talks, private initiatives)
  • Awards and profession development

There isn’t any one option to write a brag doc, however that didn’t cease Jonny Burch and the crew at Development from constructing bragdocs.com.

Utilizing their web site to construct one is a superb concept, however what higher option to brag about your work than to create your personal brag doc from scratch?

Right this moment I wish to present you the way I re-created bragdocs.com utilizing the static web site generator Eleventy. With a bit of little bit of JavaScript and CSS, you will get your personal up and working!

What are we going to construct?

Under is the top results of following this tutorial. You could find the stay demo right here. It imitates bragdocs.com as a place to begin so that you can create one from scratch and make it your personal.

Necessities

  • Putting in packages in Node.js (model 10 or larger)
  • Common understanding of HTML and CSS
  • Markdown, Nunjucks templating, and JavaScript (all are non-obligatory, however useful)
  • Primary programming ideas, together with if statements, loops, and accessing variables in JSON

What’s Eleventy?

Eleventy is a static web site generator. Which means somewhat than constructing a full-stack web site (front-end and back-end), you’ve got flexibility to put in writing content material in any of the next templating languages accepted by Eleventy: HTML, Markdown, Liquid, Nunjucks, Mustache, and so forth. The content material is then processed (utilizing customized templates in case you like) to generate static HTML pages, prepared for internet hosting as a totally functioning web site.

Establishing our “Howdy, World!” Eleventy mission

On this tutorial, the repository I’ll be referring to is eleventy-bragdoc, and the ultimate product we’re working in direction of shall be known as a “bragdoc.”

With a GitHub repository created with a README.md and .gitignore file for Node, I began organising an Eleventy mission.

Creating a brand new mission

Inside eleventy-bragdoc, I started with the next recordsdata:

eleventy-bragdoc
├── README.md
└── .gitignore // .gitignore for node

With the terminal navigated within eleventy-bragdoc, I initialized the mission by working the next command:

npm init -y

This created a bundle.json file for my node packages.

eleventy-bragdoc
├── bundle.json // new file
├── README.md
└── .gitignore

Subsequent, I put in Eleventy.

npm set up @11ty/eleventy

This gave me the next listing of recordsdata and folders:

eleventy-bragdoc
├── node_modules  // new folder
├── bundle.json
├── package-lock.json  // new file
├── README.md
└── .gitignore

Configuring the Eleventy mission

With Eleventy put in, I up to date the scripts within the bundle.json file to incorporate the next instructions:

  • The begin command serves the mission throughout growth which runs Browsersync for warm reload.
  • The construct command creates manufacturing prepared HTML recordsdata in order that it may be hosted onto a server.
{
  // ...
  "scripts": {
    "begin": "eleventy --serve",
    "construct": "eleventy"
  },
 //  ...
}

Subsequent, I created the required configuration file referred to as .eleventy.js to specify the customized enter and output directories.

eleventy-bragdoc
├── .eleventy.js  // new file
├── node_modules
├── bundle.json
├── package-lock.json
├── README.md
└── .gitignore

Inside .eleventy.js, I informed Eleventy that it’s going to reference what’s within the src folder to construct the HTML recordsdata. The output is then saved inside a folder referred to as public:

module.exports = operate(eleventyConfig) {
  return {
    dir: {
      enter: "src",
      output: "public"
    }
  }
}

Creating front-facing content material

To make my first web page, I created the src folder that I declared because the enter listing in .eleventy.js . Inside it, I added my first web page, a Markdown file referred to as index.md

Eleventy works with many templating languages that you could combine and match: HTML, Markdown, Liquid, Nunjucks, JavaScript, Handlebars, Mustache, EJS, Haml, Pug.

eleventy-bragdoc
├── src
│   └── index.md  // new file
├── .eleventy.js
├── node_modules
├── bundle.json
├── package-lock.json
├── README.md
└── .gitignore

In Eleventy, any key worth pairs written between the dashes (---) above and beneath is taken into account entrance matter.

In index.md , I included a title property with the worth “11ty x Bragdocs” and a few take a look at content material beneath the entrance matter.

---
title: "11ty x Bragdocs"
---

That is the house web page.

Constructing templates

Subsequent, I created a folder which Eleventy expects, referred to as _includes within src. That is the place the templates, or what Eleventy refers to as layouts, should stay. Inside that folder, I created a subfolder referred to as layouts for my first template, base.njk

The .njk filetype refers back to the templating language Nunjucks.

eleventy-bragdoc
├── src
│   ├── _includes  // new folder
│   │   └── layouts  // new folder
│   │       └── base.njk  // new file
│   └── index.md
├── .eleventy.js
├── node_modules
├── bundle.json
├── package-lock.json
├── README.md
└── .gitignore

I added an HTML5 boilerplate inside base.njk:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta identify="viewport" content material="width=device-width, initial-scale=1.0">
  <title>Doc</title>
</head>
<physique>
    
</physique>
</html>

Creating pages with templates and entrance matter

In base.njk , between the <title> tags, I wished to drag within the title property outlined within the entrance matter of index.md, so I used double curly braces, i.e. {{title}}, to entry this variable. Equally, within the physique, I added <h1> tags and set it with the identical title property.

Subsequent, I introduced in the remainder of the physique content material from index.md utilizing the content material property. Utilizing the offered secure filter, I informed Eleventy to render as an alternative of escape any HTML that lives contained in the content material of the Markdown file.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta identify="viewport" content material="width=device-width, initial-scale=1.0">
  <title>{{ title }}</title>
</head>
<physique>
  <h1>{{ title }}</h1>
  { secure }
</physique>
</html>

I then jumped again to index.md and added a format property to the entrance matter and referenced base.njk

---
title: "11ty x Bragdocs"
format: "layouts/base.njk"
---

That is the house web page.

To present you an concept of what occurs after we run the construct, the template specified within the format entrance matter property is used to wrap the Markdown content material. On this instance, the compiled HTML will seem like what’s proven beneath:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta identify="viewport" content material="width=device-width, initial-scale=1.0">
  <title>11ty x Bragdocs</title>
</head>
<physique>
  <h1>11ty x Bragdocs</h1>
  <p>That is the house web page.</p>
</physique>
</html>

Connecting CSS and picture folders in construct

Whereas this half may not be crucial for all Eleventy initiatives, CSS and self-hosted pictures are at all times good options so as to add. So, I created two folders within the src listing: css and pictures.

eleventy-bragdoc
├── src
│   ├── css  // new folder
│   ├── pictures  // new folder
│   ├── _includes
│   │   └── layouts
│   │       └── base.njk
│   └── index.md
├── .eleventy.js
├── node_modules
├── bundle.json
├── package-lock.json
├── README.md
└── .gitignore

Then, in .eleventy.js, since I wished the content material inside these folders to be accessible when hosted, I referenced these folders by including the next configurations:

  • addWatchTarget tells Eleventy that it ought to recompile after we make a change to a file on this listing (e.g. kinds.css within the css folder).
  • addPassthroughCopy tells Eleventy that when the recordsdata are compiled, to take the contents of the listing and move it by means of to the public listing.

You may learn extra about how passthrough file copy works within the documentation.

Since I used to be utilizing the Nunjucks templating system, I added the markdownTemplateEngine property and set it to njk to ensure that it is aware of to undergo Nunjucks first earlier than the rest.

module.exports = operate(eleventyConfig) {
  eleventyConfig.addWatchTarget("./src/css/")
  eleventyConfig.addWatchTarget("./src/pictures/")
  eleventyConfig.addPassthroughCopy("./src/css/")
  eleventyConfig.addPassthroughCopy("./src/pictures/")

  return {
    dir: {
      enter: "src",
      output: "public"
    },
    markdownTemplateEngine: "njk"
  }
}

Then I created a kinds.css file within the css folder and gave it one thing to check with to ensure it labored.

* {
  coloration: teal;
}

Since I already configured the css and pictures folders in .eleventy.js, I used to be in a position to reference these recordsdata utilizing Eleventy’s URL filter.

To entry these self-hosted recordsdata I used Eleventy’s URL filters within the href and src property of the css and picture tags, respectively.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta identify="viewport" content material="width=device-width, initial-scale=1.0">
  <title>{{ title }}</title>

  <hyperlink rel="stylesheet" href="https://css-tricks.com/creating-your-own-bragdoc-with-eleventy/{ url }">

</head>
<physique>
  <h1>{{ title }}</h1>

  <img src="https://css-tricks.com/creating-your-own-bragdoc-with-eleventy/{ url }">

  { secure }
</physique>
</html>

Now I used to be able to serve my Eleventy mission.

Serving Eleventy in growth

Since I had already outlined the customized growth scripts in bundle.json, I used to be in a position to run the next command:

npm begin

This compiled index.md within the src listing and generated a HTML file within the public folder. Moreover, it launched a sizzling reload server by means of Browsersync the place I might see the end result at http://localhost:8080/

The end result thus far

With Eleventy working in growth, I might begin constructing the remainder of the bragdoc.

Constructing the bragdoc system

With a base Eleventy mission in a folder construction just like what’s proven beneath, I started constructing out my bragdoc.

eleventy-bragdoc
├── src
│   ├── css
│   │   └── kinds.css
│   ├── pictures
│   │   └── test_image.jpg
│   ├── _includes
│   │   └── layouts
│   │       └── base.njk
│   └── index.md
├── .eleventy.js
├── node_modules
├── bundle.json
├── package-lock.json
├── README.md
└── .gitignore

Creating a group for bragdoc entries

Eleventy has the power to create collections that group related content material collectively. Subsequently, I created a folder referred to as posts for my bragdoc entries. Inside that folder, I created a number of Markdown recordsdata to signify every entry.

The filenames post-1.md, post-2.md, post-3.md don’t have an effect on something that’s rendered on the webpage

eleventy-bragdoc
├── src
│   ├── posts
│   │   ├── post-1.md  // new file
│   │   ├── post-2.md  // new file
│   │   └── post-3.md  // new file
│   ├── css
│   │   └── kinds.css
│   ├── pictures
│   │   └── test_image.jpg
│   ├── _includes
│   │   └── layouts
│   │       └── base.njk
│   └── index.md
├── .eleventy.js
├── node_modules
├── bundle.json
├── package-lock.json
├── README.md
└── .gitignore

The customized properties that I believed can be helpful to incorporate:

  • Title
  • Date (by default, posts are sorted chronologically)
  • Classes (a listing of values to arrange entries)
  • Public / Non-public (a boolean worth—true or false—to find out whether or not you wish to present it on the bragdoc )
  • Icon (a Notion-inspired design ingredient to visually set up entries)

I made a decision that the outline for every entry can be the physique content material of the Markdown file, as this may give me freedom so as to add paragraphs, pictures, code blocks, and so forth. Moreover, I used to be not restricted to Markdown parts as I might additionally embody HTML and magnificence it utilizing CSS.

Under is an instance of a bragdoc entry in a Markdown file:

---
title: Construct my very own Bragdoc utilizing Eleventy
date: 2021-09-19
classes:
  - Studying
  - Eleventy
public: True
icon: 🎈
---

I discovered tips on how to use Eleventy to construct my very own bragdoc!

Some issues to notice:

  • Hyperlinks written in Markdown by default don’t open in a brand new clean window. So after some analysis, I stumbled upon a snippet by Mark Thomas Miller, which I added simply earlier than the closing <physique> tag in base.njk. This may not be your factor (it’s positively not Chris’ factor) however simply in case you want it:
<script>
// Making all exterior hyperlinks open in new tabs
// Snippet by Mark Thomas Miller

(operate () {
  const hyperlinks = doc.querySelectorAll("a[href^='https://'], a[href^='http://']")
  const host = window.location.hostname

  const isInternalLink = hyperlink => new URL(hyperlink).hostname === host

  hyperlinks.forEach(hyperlink => {
    if (isInternalLink(hyperlink)) return

    hyperlink.setAttribute("goal", "_blank")
    hyperlink.setAttribute("rel", "noopener")
  })
})()
</script>
  • The date entrance matter property have to be written in YYYY-MM-DD format.
  • You may assign as many customized entrance matter properties as you’d like. Simply ensure that in case you plan on accessing the property within the template, that the property exists in the entire Markdown recordsdata utilizing the identical template; in any other case it might break the construct.
  • Lists in entrance matter will be written in a number of methods (e.g. an array or single line).

Assigning entrance matter properties to a group

As an alternative of repeatedly assigning entrance matter properties with the identical worth in every Markdown file, I created a knowledge listing JSON file to assign the identical key-value pair solely as soon as throughout a group.

To create a knowledge listing file, it should have the identical identify as the gathering, i.e. posts.json. Moreover, the file should even be positioned inside the gathering folder, i.e. the posts folder.

eleventy-bragdoc
├── src
│   ├── posts
│   │   ├── posts.json  // new file
│   │   ├── post-1.md
│   │   ├── post-2.md
│   │   └── post-3.md
│   ├── css
│   │   └── kinds.css
│   ├── pictures
│   │   └── test_image.jpg
│   ├── _includes
│   │   └── layouts
│   │       └── base.njk
│   └── index.md
├── .eleventy.js
├── node_modules
├── bundle.json
├── package-lock.json
├── README.md
└── .gitignore

At this level, the posts for the bragdoc had not been outlined as a group but. To do that, I added the tags property in posts.json. Right here I assigned the worth “posts” to that property in order that I might entry the gathering by calling collections.posts

And since I didn’t want every put up to have its personal web page, i.e. http://localhost:8080/posts/post-1/, I switched off it’s auto-generated permalink.

{
  "tags": "posts",
  "permalink": false
}

Itemizing bragdoc entries

Merely put, the bragdoc is a web page made up of the entries within the posts assortment. To entry the entrance matter properties and physique content material of the Markdown recordsdata, the entries are looped by means of by way of Nunjucks.

To do that, I went again to index.md and adjusted the filetype from Markdown to Nunjucks, i.e. index.njk

eleventy-bragdoc
├── src
│   ├── posts
│   │   ├── posts.json
│   │   ├── post-1.md
│   │   ├── post-2.md
│   │   └── post-3.md
│   ├── css
│   │   └── kinds.css
│   ├── pictures
│   │   └── test_image.jpg
│   ├── _includes
│   │   └── layouts
│   │       └── base.njk
│   └── index.njk  // modified filetype
├── .eleventy.js
├── node_modules
├── bundle.json
├── package-lock.json
├── README.md
└── .gitignore

Subsequent, I changed the content material of index.njk with a Nunjucks for loop.

A Nunjucks operate (for loop, if assertion, and so forth.) should embody begin and finish tags.

For the reason that order of posts by default was in chronological order (oldest first), I added the reverse filter to point out the latest on the high.

To entry entrance matter and render it in HTML (such because the date and title of a put up), I needed to undergo one other “information” layer. Accessing properties in entrance matter requires double curly braces.

---
title: "11ty x Bragdocs"
format: "layouts/base.njk"
---

 reverse %
  <p>
    {{ put up.information.date }} - {{ put up.information.title }}
  </p>
{% endfor %}
Slightly extra progress

Filtering bragdoc entries

To filter sure entries, I used the entrance matter information to test if the public property was set to True. If the property was set to False, the entry didn’t seem within the bragdoc.

Equally, when accessing entrance matter properties, reminiscent of public by means of a Nunjucks operate, I once more wanted to undergo one other “information” layer.

---
title: "11ty x Bragdocs"
format: "layouts/base.njk"
---

 reverse %
  {% if put up.information.public %}
    <p>
      {{ put up.information.date }} - {{ put up.information.title }}
    </p>
  {% endif %}
{% endfor %}
The posts are ordered with the title.

Including customized information filters

By default, the date property renders one thing that we’re usually unfamiliar with. So, after some analysis, I discovered a customized filter written by Phil Hawksworth. To make use of the filter, I created a file referred to as dates.js and positioned it in a brand new folder referred to as _filters

eleventy-bragdoc
├── src
│   ├── _filters  // new folder
│   │   └── dates.js  // new file
│   ├── posts
│   │   ├── posts.json
│   │   ├── post-1.md
│   │   ├── post-2.md
│   │   └── post-3.md
│   ├── css
│   │   └── kinds.css
│   ├── pictures
│   │   └── test_image.jpg
│   ├── _includes
│   │   └── layouts
│   │       └── base.njk
│   └── index.njk
├── .eleventy.js
├── node_modules
├── bundle.json
├── package-lock.json
├── README.md
└── .gitignore

Then, inside dates.js, I added the next:

/*
A date formatter filter for Nunjucks 
Written by Phil Hawksworth
*/
module.exports = operate(date, half) {
  var d = new Date(date);
  if(half == '12 months') {
    return d.getUTCFullYear();
  }
  var month = [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December"
  ];
  var ordinal = {
    1 : "st",
    2 : "nd",
    3 : "rd",
    21 : "st",
    22 : "nd",
    23 : "rd",
    31 : "st"
  };
  return month[d.getMonth()] + " " + d.getDate() + (ordinal[d.getDate()] || "th") + " " +d.getUTCFullYear();
}

To entry the date filter within the mission, I added a brand new filter in .eleventy.js the place I can name it utilizing the customized identify dateDisplay

module.exports = operate (eleventyConfig) {

  // Add filter
  eleventyConfig.addFilter("dateDisplay", require("./src/_filters/dates.js") );
  
  eleventyConfig.addPassthroughCopy("./src/css/")
  eleventyConfig.addPassthroughCopy("./src/pictures/")
  eleventyConfig.addWatchTarget("./src/css/")
  eleventyConfig.addWatchTarget("./src/pictures/")

  return {
    dir: {
      enter: "src",
      output: "public"
    },
    markdownTemplateEngine: "njk"
  }
}

In index.njk, I assigned the dateDisplay filter to the date variable, rendering it in a human-readable format.

---
title: "11ty x Bragdocs"
format: "layouts/base.njk"
---

 reverse %
  {% if put up.information.public %}
    <p>
      { dateDisplay } - {{ put up.information.title }}
    </p>
  {% endif %}
{% endfor %}

The server must be restarted each time you modify one thing within the configuration file.

The posts with up to date date formatting.

To return the physique content material of a put up, I referred to as templateContent and added the secure filter in order that it rendered any HTML within the Markdown file somewhat than escaping it.

---
title: "11ty x Bragdocs"
format: "layouts/base.njk"
---

 reverse %
  {% if put up.information.public %}
    <p>
      { dateDisplay } - {{ put up.information.title }} 
      <br/>
      { secure }
    </p>
    <br/>
  {% endif %}
{% endfor %}
The posts with physique content material.

Lastly, I included one other for loop to listing the values within the classes entrance matter property.

---
title: "11ty x Bragdocs"
format: "layouts/base.njk"
---

 reverse %
  {% if put up.information.public %}
    <p>
      { dateDisplay } - {{ put up.information.title }}
      <br/>
      { secure }
      {% for class in put up.information.classes %}
        <span># {{class}}</span>
      {% endfor %}
    </p>
    <br/>
  {% endif %}
{% endfor %}

Having completed extracting information from the posts assortment, it was time to construct out the HTML construction.

Structuring the bragdoc

Partials in Eleventy permit us to repeatably use bits of HTML or templating. This additionally simplifies the code from one large template file to manageable items that match collectively.

Contained in the <physique> tags of base.njk , I eliminated every little thing besides the content material and snippet.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta identify="viewport" content material="width=device-width, initial-scale=1.0">
  <title>{{ title }}</title>

  <hyperlink rel="stylesheet" href="https://css-tricks.com/creating-your-own-bragdoc-with-eleventy/{ url }">
</head>
<physique>
  { secure }
  <script>
    (operate () {
      const hyperlinks = doc.querySelectorAll("a[href^='https://'], a[href^='http://']")
      const host = window.location.hostname

      const isInternalLink = hyperlink => new URL(hyperlink).hostname === host

      hyperlinks.forEach(hyperlink => {
        if (isInternalLink(hyperlink)) return

        hyperlink.setAttribute("goal", "_blank")
        hyperlink.setAttribute("rel", "noopener")
      })
    })()
  </script>
</physique>
</html>

Subsequent, I created bragdoc-entry.njk which lives inside a brand new folder referred to as partials

eleventy-bragdoc
├── src
│   ├── _filters
│   │   └── dates.js
│   ├── posts
│   │   ├── posts.json
│   │   ├── post-1.md
│   │   ├── post-2.md
│   │   └── post-3.md
│   ├── css
│   │   └── kinds.css
│   ├── pictures
│   │   └── test_image.jpg
│   ├── _includes
│   │   ├── partials  // new folder
│   │   │   └── bragdoc-entry.njk  // new file
│   │   └── layouts
│   │       └── base.njk
│   └── index.njk
├── .eleventy.js
├── node_modules
├── bundle.json
├── package-lock.json
├── README.md
└── .gitignore

Inside bragdoc-entry.njk, I introduced over the content material that make up the bragdoc entry, written in index.njk. Discover that it doesn’t require any entrance matter since it’s handled as a snippet.

Partials don’t prolong a template, so they don’t want any entrance matter.

<p>
  { dateDisplay } - {{ put up.information.title }}
  <br/>
  { secure }
  {% for class in put up.information.classes %}
      <span># {{class}}</span>
  {% endfor %}
</p>
<br/>

Then, between the if assertion in index.njk, I added an embody tag that references the bragdoc-entry.njk partial. By doing this, the content material inside bragdoc-entry.njk is repeatably added till the for loop finishes.

---
title: "11ty x Bragdocs"
format: "layouts/base.njk"
---

 reverse %
  {% if put up.information.public %}
    {% embody 'partials/bragdoc-entry.njk' %}
  {% endif %}
{% endfor %}

Subsequent, I wrapped the whole for loop with some customized HTML, together with a header, profile container and footer. At this level, I additionally included a profile image within the pictures folder and referenced it within the customized HTML utilizing Eleventy’s URL filter.

---
title: "11ty x Bragdocs"
format: "layouts/base.njk"
---

<div class="bragdoc__section" id="bragdoc__section">
<h1 class="bragdoc__header">{{ title }}</h1>
<div class="bragdoc__container">
  <div class="bragdoc__profile">
    <img class="bragdoc__photo" src="https://css-tricks.com/creating-your-own-bragdoc-with-eleventy/{ url }">
    <h1 class="bragdoc__name">Emily Y Leung</h1>
    <div class="function">Computational Designer</div>
  </div>
   reverse %
    {% if put up.information.public -%}
      {% embody 'partials/bragdoc-entry.njk' %}
    {% endif %}
  {% endfor %}
  </div>
  <footer>
    <div><a goal="_blank" href="https://www.bragdocs.com/">Bragdocs</a> impressed theme constructed with <a goal="_blank" href="https://www.11ty.dev/">11ty</a></div>
    <div>Made with ♥ by <a goal="_blank" href="https://emilyyleung.github.io/">Emily Y Leung</a></div>
  </footer>
</div>

Then, inside bragdoc-entry.njk, I up to date the HTML construction and included courses for styling:

<div class="bragdoc__entry">
  <div class="bragdoc__entry-milestone"></div>
  <div class="bragdoc__entry-block">
    <span class="bragdoc__entry-date">
      { dateDisplay }
    </span>
    <br/>
    <h2 class="bragdoc__entry-title"><span class="bragdoc__icon">{{ put up.information.icon }}</span> {{ put up.information.title }}</h2>
    <div class="bragdoc__entry-content">
        { secure }
    </div>
  </div>
  <div class="bragdoc__taglist">
  {% for class in put up.information.classes %}
    <span># {{class}}</span>
  {% endfor %}
  </div>
</div>

Accessing world information

A great way to grasp world information is to think about constructing a HTML template that somebody might use as a base for his or her web site. Fairly than looking for particular HTML tags to interchange the textual content, they solely want to interchange sure values in an exterior file which then updates the content material. This is likely one of the many issues a world information file can do for us.

Eleventy can entry world information recordsdata written in JSON when they’re positioned in a folder referred to as _data. So, I created a information.json file that’s accessible once I name {{information}} after which select no matter properties I had offered within the JSON object.

eleventy-bragdoc
├── src
│   ├── _data  // new folder
│   │   └── information.json  // new file
│   ├── _filters
│   │   └── dates.js
│   ├── posts
│   │   ├── posts.json
│   │   ├── post-1.md
│   │   ├── post-2.md
│   │   └── post-3.md
│   ├── css
│   │   └── kinds.css
│   ├── pictures
│   │   ├── profile_picture.jpg
│   │   └── test_image.jpg
│   ├── _includes
│   │   ├── partials
│   │   │   └── bragdoc-entry.njk
│   │   └── layouts
│   │       └── base.njk
│   └── index.njk
├── .eleventy.js
├── node_modules
├── bundle.json
├── package-lock.json
├── README.md
└── .gitignore

Inside information.json, I included properties that had been reused all through the mission:

{
  "mywebsite": "https://emilyyleung.github.io/",
  "myname": "Emily Y Leung",
  "myrole": "Computational Designer"
}

One nice use case was to interchange the content material within the profile and footer in index.njk

<!-- Profile -->
<div class="bragdoc__profile">
  <img class="bragdoc__photo" src="https://css-tricks.com/creating-your-own-bragdoc-with-eleventy/{ url }">
  <h1 class="bragdoc__name">{{ information.myname }}</h1>
  <div class="function">{{ information.myrole }}</div>
</div>
<!-- Footer -->
<footer>
  <div><a goal="_blank" href="https://www.bragdocs.com/">Bragdocs</a> impressed theme constructed with <a goal="_blank" href="https://www.11ty.dev/">11ty</a></div>
  <div>Made with ♥ by <a goal="_blank" href="https://css-tricks.com/creating-your-own-bragdoc-with-eleventy/{{ information.mywebsite }}">{{ information.myname }}</a></div>
</footer>

Styling the bragdoc

With the bragdoc construction accomplished, I up to date the styling in kinds.css

To mimic bragdocs.com, I chosen a few of their colours and saved them in a root variable.

Moreover, I wished to create a number of themes, so I added a customized data-theme property on high of the :root variable. On this case, the default coloration theme is “gentle” no matter whether or not data-theme is assigned to the <html> tag. However that additionally implies that if I wished to create a “darkish” theme, I might create a brand new selector html[data-theme="dark"] in my CSS, and assign various colours to the identical variables as laid out in :root

:root, html[data-theme="light"] {
  --logo: black;
  --name: black;
  --entry-title: black;
  --date: #BDBDBD;
  --text: #676a6c;
  --entry-line: #f1f1f1;
  --entry-circle: #ddd;
  --background: white;
  --text-code: gray;
  --code-block: rgba(0,0,0,0.05);
  --link-text: #676a6c;
  --link-hover: orange;
  --quote-block-edge: rgba(255, 165, 0, 0.5);
  --quote-block-text: #676a6c;
  --table-border: #676a6c;
  --footer: #BDBDBD;
  --tag: #BDBDBD;
}

To reference root variables, name var() the place the argument is the identify of the property.

Right here is an instance of how we are able to use root variables to model the colour of textual content in a <p> tag:

:root {
  --text: teal;
}

p {
  coloration: var(--text)
}

For enjoyable, I added a darkish model impressed by Google Materials.

html[data-theme="dark"] {
  --logo: #FFF;
  --name: #FFF;
  --entry-title: #dedede;
  --date: rgba(255,255,255,0.3);
  --text: #999999;
  --entry-line: rgba(255,255,255,0.2);
  --entry-circle: rgba(255,255,255,0.3);
  --background: #121212;
  --code-text: rgba(255,255,255,0.5);
  --code-block: rgba(255,255,255,0.1);
  --link-text: rgba(255,255,255,0.5);
  --link-hover: orange;
  --quote-block-edge: rgb(255, 165, 0);
  --quote-block-text: rgba(255, 165, 0,0.5);
  --table-border: #999999;
  --footer: rgba(255,255,255,0.3);
  --tag: rgba(255,255,255,0.3);
}

To regulate what theme you wish to use, add the data-theme property to the <html> tag in base.njk. From there, assign the worth related to the corresponding CSS selector, i.e. “gentle” or “darkish.”

<!DOCTYPE html>
<html lang="en" data-theme="gentle">

Subsequent, I added styling to the <physique>, <footer>, bragdoc part, and emblem.

physique {
  font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 13px;
  coloration: var(--text);
  background-color: var(--background);
  margin: 0;
  peak: 100vh;
}

footer {
  margin: 0 auto;
  max-width: 500px;
  padding-bottom: 1.5em;
  text-align: heart;
  coloration: var(--footer);
  padding-top: 2em;
  margin-top: 2em;
}

/* Bragdoc Brand */

.bragdoc__header {
  margin: 0;
  padding: 1em;
  font-size: 1.5em;
  coloration: var(--logo)
}

/* Bragdoc Physique */

.bragdoc__section {
  peak: 100%;
  show: grid;
  grid-template-rows: auto 1fr auto;
  margin: 0;
  padding: 0;
}

At this level, the customized tags and courses within the HTML made it easy to duplicate the bragdoc format.

/* Bragdoc Person Profile */

.bragdoc__profile {
  padding-top: 3em;
  padding-bottom: 2em;
}

.bragdoc__photo {
  width: 8em;
  border-radius: 100%;
  padding: 0;
  peak: 8em;
  object-fit: cowl;
}

.bragdoc__name {
  coloration: var(--name);
  margin-bottom: 0.25em;
}

.bragdoc__icon {
  font-family: "Segoe UI Emoji", Occasions, serif;
}

.bragdoc__container {
  max-width: 800px;
  margin: 0 0 0 30em;
  peak: 100%;
}

.bragdoc__profile-role {
  margin: 0;
}

Subsequent, I styled the entries to duplicate the bragdocs.com timeline design.

/* Particular person Bragdoc Entry Blocks */

.bragdoc__entry {
  place: relative;
}

.bragdoc__entry:first-child {
  margin-top: 0;
}

.bragdoc__entry:earlier than {
  peak: 100%;
  place: absolute;
  background-color: var(--entry-line);
  width: 2px;
  content material: "";
  high: 30px;
}

.bragdoc__entry:last-child:earlier than {
  background-color: var(--background);
}

.bragdoc__taglist {
  margin-left: 1em;
  padding: 1em;
}

.bragdoc__taglist > * {
  border: 1px stable var(--tag);
  padding: 0.25em 0.5em 0.25em 0.5em;
  border-radius: 0.5em;
  margin-right: 1em;
}

/* Entry Content material */

.bragdoc__entry-block {
  margin-left: 1em;
  padding: 1em;
}

.bragdoc__entry-title {
  margin-top: 4px;
  coloration: var(--entry-title);
  font-size: 1.5em;
}

.bragdoc__entry-date {
  line-height: 3em;
  coloration: var(--date);
}

/* Bragdoc milestone circle */

.bragdoc__entry-milestone {
  place: absolute;
  peak: 5px;
  width: 5px;
  border: 2px stable var(--entry-circle);
  background-color: var(--background);
  left: 0;
  high: 30px;
  margin-top: -2px;
  margin-left: -3px;
  border-radius: 100px;
}

/* Bragdoc Entry Content material */

.bragdoc__entry-content > * {
  margin-bottom: 0.5em;
  margin-left: 0;
}

.bragdoc__entry-content > h1 {
  font-size: 1.15em;
}

.bragdoc__entry-content > h2, h3, h4, h5, h6 {
  font-size: 1em;
  coloration: var(--text);
}

Utilizing CSS media queries, I might additionally management the scale of textual content in addition to the positioning of HTML parts. This makes it work nicely when seen on cellular.

/* Make it responsive */

@media solely display and (max-width: 1400px) {

  .bragdoc__container {
    /* Middle the bragdoc*/
    margin: 0 auto;
  }

  .bragdoc__entry-title {
    font-size: 1.25em;
  }
}

@media solely display and (max-width: 870px) {

  .bragdoc__container {
    padding-left: 2em;
    padding-right: 2em;
  }

  .bragdoc__entry-title {
    font-size: 1.15em;
  }
}

The ultimate touches to the design wanted to account for the outline (i.e. the Markdown physique content material) in every entry, which you’ll find on this Gist.

Provided that the CSS has been structured just about root variables, we are able to proceed to create extra themes. Have a crack at exploring coloration palettes from Shade Hunt or Cooolers.

Deploying the bragdoc to GitHub Pages

Constructing a mission from scratch is unbelievable, however sharing it with the world is even higher!

Whereas there are a myriad of the way to host a bragdoc, I made a decision to host it on GitHub Pages. This meant I might use the bottom URL of my GitHub account and add /eleventy-bragdoc/ to the top of it.

At this level, I had been working from the eleventy-bragdoc repository and had already created a gh-pages department.

Comply with this tutorial for info on tips on how to arrange GitHub Pages in your repository.

Configuring the URL path

To configure the URL path for deployment, I included a pathPrefix in .eleventy.js to outline the route relative to the bottom URL.

With out specifying a pathPrefix, the worth by default is /, which hyperlinks to the bottom URL, i.e. https://emilyyleung.github.io/

Since I already had content material on the bottom URL, I wished to host it on a sub-page, i.e. https://emilyyleung.github.io/eleventy-bragdoc/

To set the pathPrefix for sub-pages, it should begin and finish with a slash:

module.exports = operate (eleventyConfig) {
  // ...
  return {
    dir: {
      enter: "src",
      output: "public"
    },
    markdownTemplateEngine: "njk",
    pathPrefix: "/eleventy-bragdoc/"
  }
}

Including the GitHub Pages dependency

After configuration, I put in GitHub Pages utilizing the terminal:

npm set up gh-pages --save-dev

This routinely provides the dependency to bundle.json

{
  // ...  
  "devDependencies": {
    "gh-pages": "^3.2.3"
  },
  // ...
}

Including a customized terminal script

To deploy the public folder, I added a deploy script and referenced the public folder:

{
  // ...
  "scripts": {
    "begin": "eleventy --serve",
    "construct": "eleventy",
    "deploy": "gh-pages -d public"
  }
  // ...
}

Operating the construct

Identical to in growth, I navigated my terminal to the eleventy-bragdoc folder. However this time, I ran the next command to rebuild the recordsdata into the public folder:

npm run-script construct

Then, to deploy to GitHub Pages, I ran the next command:

npm run deploy

Granting entry to deploy

At this level, the terminal might ask you to log in by way of the terminal or by means of the GitHub Desktop software. If the login fails, the terminal might ask you to generate a token of authentication to make use of as an alternative of a password. Here’s a information on tips on how to create one.

With a profitable response from the terminal, I might see my bragdoc stay!

Sustaining your bragdoc

Not like reviews and books, a bragdoc have to be maintained constantly as a stay document of your progress and achievements. Consider your bragdoc like a backyard, the place tending requires common consideration and care. Whilst you might not see the advantages right away, time invested in tending to your doc will result in far larger returns. On the spot recall and the power to share what you’ve executed are a few of the upsides in forming this behavior.

Whilst you might not have the ability to be aware down every little thing because it occurs, Julia Evans suggests setting a block of time to evaluate your progress and replace the doc. Even perhaps making it a bi-weekly group exercise to have a good time all wins, massive and small.

For a lot of, the much less time it takes to do one thing, the higher. With this bragdoc setup, including new entries and rebuilding the location doesn’t take lengthy in any respect! Simply to provide you an concept of how easy that is, I’ll stroll you thru the method of including one other entry to spherical out the tutorial.

Add a brand new bragdoc entry

Persevering with from my final deployment, I’ll first add a brand new Markdown file in my posts folder.

eleventy-bragdoc
├── src
│   ├── _data
│   │   └── information.json
│   ├── _filters
│   │   └── dates.js
│   ├── posts
│   │   ├── posts.json
│   │   ├── post-1.md
│   │   ├── post-2.md
│   │   ├── post-3.md
│   │   └── post-4.md  // new entry goes right here
│   ├── css
│   │   └── kinds.css
│   ├── pictures
│   │   ├── profile_picture.jpg
│   │   └── test_image.jpg
│   ├── _includes
│   │   ├── partials
│   │   │   └── bragdoc-entry.njk
│   │   └── layouts
│   │       └── base.njk
│   └── index.njk
├── .eleventy.js
├── node_modules
├── bundle.json
├── package-lock.json
├── README.md
└── .gitignore

Inside post-4.md, I’ll add in my entrance matter and outline content material.

---
title: Working in direction of publishing my first article on CSS-Tips
date: 2021-10-02
classes:
  - Writing
  - Eleventy
public: True
icon: ✍🏻
---

Since re-creating [bragdocs.com](https://www.bragdocs.com/) utilizing Eleventy, I'm now within the means of writing the steps on how I did it.

Run the construct

With the entries added and saved, I’m prepared to inform Eleventy to reference my Markdown recordsdata from src to generate static HTML recordsdata within the public folder. So I navigate the terminal to eleventy-bragdoc the place I run the next command:

npm run-script construct

Run deploy

Since I’ve already deployed as soon as earlier than, my GitHub credentials ought to grant me instant entry for deployment when working the next command:

npm run deploy

These adjustments are then mirrored on my web site on the identical configured URL.

What’s subsequent?

Effectively first off, congratulations on placing collectively your very personal bragdoc from scratch! It’s yours to maintain, to have a tendency and to share.

Whereas this tutorial has solely scratched the floor of what’s attainable with Eleventy, a small step can lead you to all kinds of instructions. To gasoline your curiosity, take a look at what others are doing with Eleventy.

Be at liberty to reach out, I’d like to see what you provide you with!

#Creating #Bragdoc #Eleventy

Leave a Reply

Your email address will not be published. Required fields are marked *