Unabhängig davon, in welchem Stadium Sie sich als Entwickler befinden, haben die von uns erledigten Aufgaben – ob groß oder klein – einen enormen Einfluss auf unser persönliches und berufliches Wachstum. Leider werden diese Aufgaben nicht immer anerkannt, da sie leicht in der Flut anderer Dinge untergehen, die erledigt werden müssen.
Die unbemerkten Aufgaben, die wir erledigen, fallen unter das, was als „unsichtbare Arbeit“ bekannt ist, ein Konzept, auf das ich in einem Vortrag mit dem Titel „Getting Credit for Invisible Work“ von Ryan T. Harter gestoßen bin. Diese Art von Arbeit sickert in die Ritzen, weil unser Gehirn nicht darauf ausgelegt ist, sich Dinge zu merken. Doch zur Zeit der Überprüfung finden wir uns wiederholt festgefahren, wenn wir versuchen, uns daran zu erinnern, was wir in den letzten 6 oder 12 Monaten getan haben.
Um dieses seit langem bestehende Problem zu lösen, schrieb Julia Evans einen Artikel, in dem sie vorschlug, dass wir unser eigenes „Brag-Dokument“ führen sollten. Ein Brag-Dokument ist genau das, wonach es klingt. Es ist ein Dokument, in dem Sie sich selbst die Erlaubnis geben, über all die wertvolle Arbeit zu prahlen, die Sie geleistet haben. Sei es
- Wie Sie zu einem Projekt beigetragen haben
- Anderen zu helfen
- Bestehende Prozesse zu verbessern
- Vorträge zu halten oder Workshops zu leiten
- Was Sie gelernt haben
- Außerunterrichtliche Aktivitäten (z. B. Bloggen, Vorträge, persönliche Projekte)
- Auszeichnungen und Karrierefortschritt
Es gibt keine einzelne Methode, ein Brag-Dokument zu schreiben, aber das hat Jonny Burch und das Team von Progression nicht davon abgehalten, bragdocs.com zu entwickeln.
Die Nutzung ihrer Website, um eine zu erstellen, ist eine großartige Idee, aber wie könnte man besser über seine Arbeit prahlen, als sein eigenes Brag-Dokument von Grund auf neu zu erstellen?
Heute möchte ich Ihnen zeigen, wie ich bragdocs.com mit dem Static Site Generator Eleventy neu erstellt habe. Mit ein wenig JavaScript und CSS können Sie Ihr eigenes zum Laufen bringen!
Was werden wir bauen?
Unten sehen Sie das Endergebnis, wenn Sie diesem Tutorial folgen. Die Live-Demo finden Sie hier. Sie imitiert bragdocs.com als Ausgangspunkt, damit Sie eine von Grund auf neu erstellen und sie zu Ihrer eigenen machen können.

Anforderungen
- Installation von Paketen in Node.js (Version 10 oder höher)
- Allgemeines Verständnis von HTML und CSS
- Markdown, Nunjucks-Templating und JavaScript (alles optional, aber hilfreich)
- Grundlegende Programmierkonzepte, einschließlich
if-Anweisungen, Schleifen und Zugriff auf Variablen in JSON
Was ist Eleventy?
Eleventy ist ein Static Site Generator. Das bedeutet, dass Sie anstatt einer Full-Stack-Website (Frontend und Backend) die Flexibilität haben, Inhalte in jeder der von Eleventy unterstützten Vorlagensprachen zu schreiben: HTML, Markdown, Liquid, Nunjucks, Mustache, etc. Die Inhalte werden dann verarbeitet (bei Bedarf mit benutzerdefinierten Vorlagen), um statische HTML-Seiten zu generieren, die für das Hosting als voll funktionsfähige Website bereit sind.
Einrichten unseres „Hallo, Welt!“-Eleventy-Projekts
In diesem Tutorial beziehe ich mich auf das Repository eleventy-bragdoc, und das Endergebnis, auf das wir hinarbeiten, wird als „Bragdoc“ bezeichnet.
Mit einem GitHub-Repository, das mit einer README.md- und einer .gitignore-Datei für Node erstellt wurde, begann ich mit der Einrichtung eines Eleventy-Projekts.
Erstellen eines neuen Projekts
Innerhalb von eleventy-bragdoc begann ich mit den folgenden Dateien
eleventy-bragdoc
├── README.md
└── .gitignore // .gitignore for node
Nachdem ich das Terminal in eleventy-bragdoc navigiert hatte, initialisierte ich das Projekt, indem ich den folgenden Befehl ausführte
npm init -y
Dies erstellte eine package.json-Datei für meine Node-Pakete.
eleventy-bragdoc
├── package.json // new file
├── README.md
└── .gitignore
Als Nächstes habe ich Eleventy installiert.
npm install @11ty/eleventy
Dies gab mir die folgende Liste von Dateien und Ordnern
eleventy-bragdoc
├── node_modules // new folder
├── package.json
├── package-lock.json // new file
├── README.md
└── .gitignore
Konfigurieren des Eleventy-Projekts
Nachdem Eleventy installiert war, habe ich die scripts in der package.json-Datei aktualisiert, um die folgenden Befehle einzufügen
- Der
start-Befehl dient dem Projekt während der Entwicklung und führt Browsersync für Hot Reload aus. - Der
build-Befehl erstellt produktionsbereite HTML-Dateien, die dann auf einem Server gehostet werden können.
{
// ...
"scripts": {
"start": "eleventy --serve",
"build": "eleventy"
},
// ...
}
Als Nächstes habe ich die erforderliche Konfigurationsdatei namens .eleventy.js erstellt, um die benutzerdefinierten Eingabe- und Ausgabeverzeichnisse festzulegen.
eleventy-bragdoc
├── .eleventy.js // new file
├── node_modules
├── package.json
├── package-lock.json
├── README.md
└── .gitignore
Innerhalb von .eleventy.js habe ich Eleventy mitgeteilt, dass es die Inhalte des src-Ordners referenzieren wird, um die HTML-Dateien zu erstellen. Die Ausgabe wird dann in einem Ordner namens public gespeichert.
module.exports = function(eleventyConfig) {
return {
dir: {
input: "src",
output: "public"
}
}
}
Erstellen von Frontend-Inhalten
Um meine erste Seite zu erstellen, habe ich den src-Ordner erstellt, den ich in .eleventy.js als Eingabeverzeichnis deklariert habe. Darin habe ich meine erste Seite, eine Markdown-Datei namens index.md, hinzugefügt.
Eleventy arbeitet mit vielen Vorlagensprachen, die Sie mischen und anpassen können: HTML, Markdown, Liquid, Nunjucks, JavaScript, Handlebars, Mustache, EJS, Haml, Pug.
eleventy-bragdoc
├── src
│ └── index.md // new file
├── .eleventy.js
├── node_modules
├── package.json
├── package-lock.json
├── README.md
└── .gitignore
In Eleventy gelten alle Schlüssel-Wert-Paare, die zwischen den Gedankenstrichen (---) oben und unten geschrieben sind, als Front Matter.
In index.md habe ich eine title-Eigenschaft mit dem Wert „11ty x Bragdocs“ und etwas Testinhalt unterhalb des Front Matters eingefügt.
---
title: "11ty x Bragdocs"
---
This is the home page.
Erstellen von Vorlagen
Als Nächstes habe ich einen Ordner erstellt, den Eleventy erwartet, namens _includes innerhalb von src. Hier müssen die Vorlagen, oder was Eleventy als Layouts bezeichnet, liegen. Innerhalb dieses Ordners habe ich einen Unterordner namens layouts für meine erste Vorlage, base.njk, erstellt.
Die Dateiendung .njk bezieht sich auf die Vorlagensprache Nunjucks.
eleventy-bragdoc
├── src
│ ├── _includes // new folder
│ │ └── layouts // new folder
│ │ └── base.njk // new file
│ └── index.md
├── .eleventy.js
├── node_modules
├── package.json
├── package-lock.json
├── README.md
└── .gitignore
Ich habe eine HTML5-Boilerplate in base.njk eingefügt.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
Erstellen von Seiten mit Vorlagen und Front Matter
In base.njk, zwischen den <title>-Tags, wollte ich die title-Eigenschaft, die im Front Matter von index.md definiert ist, einbinden. Daher habe ich doppelte geschweifte Klammern, d. h. {{title}}, verwendet, um auf diese Variable zuzugreifen. Ähnlich habe ich im Body <h1>-Tags hinzugefügt und sie mit derselben title-Eigenschaft versehen.
Als Nächstes habe ich den restlichen Body-Inhalt von index.md über die content-Eigenschaft eingebunden. Mit dem bereitgestellten safe-Filter habe ich Eleventy angewiesen, jegliches HTML im Inhalt der Markdown-Datei zu rendern anstatt es zu escapen.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
</head>
<body>
<h1>{{ title }}</h1>
{{ content | safe }}
</body>
</html>
Dann bin ich zurück zu index.md gesprungen und habe eine layout-Eigenschaft zum Front Matter hinzugefügt und base.njk referenziert.
---
title: "11ty x Bragdocs"
layout: "layouts/base.njk"
---
This is the home page.
Um Ihnen eine Vorstellung davon zu geben, was passiert, wenn wir den Build ausführen: Die in der Front Matter-Eigenschaft layout angegebene Vorlage wird verwendet, um den Markdown-Inhalt zu umschließen. In diesem Beispiel sieht das kompilierte HTML wie unten gezeigt aus.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>11ty x Bragdocs</title>
</head>
<body>
<h1>11ty x Bragdocs</h1>
<p>This is the home page.</p>
</body>
</html>
Verbinden von CSS- und Bildordnern im Build
Auch wenn dieser Teil für alle Eleventy-Projekte möglicherweise nicht notwendig ist, sind CSS und selbst gehostete Bilder immer gute Funktionen, die man hinzufügen kann. Daher habe ich im Verzeichnis src zwei Ordner erstellt: css und images.
eleventy-bragdoc
├── src
│ ├── css // new folder
│ ├── images // new folder
│ ├── _includes
│ │ └── layouts
│ │ └── base.njk
│ └── index.md
├── .eleventy.js
├── node_modules
├── package.json
├── package-lock.json
├── README.md
└── .gitignore
Dann habe ich in .eleventy.js, da ich wollte, dass der Inhalt dieser Ordner zugänglich ist, wenn er gehostet wird, diese Ordner referenziert, indem ich die folgenden Konfigurationen hinzugefügt habe.
addWatchTargetweist Eleventy an, dass es neu kompiliert werden soll, wenn wir eine Datei in diesem Verzeichnis ändern (z. B.styles.cssimcss-Ordner).addPassthroughCopyweist Eleventy an, dass nach der Kompilierung der Dateien der Inhalt des Verzeichnisses in das Verzeichnispublickopiert werden soll.
Sie können mehr darüber lesen, wie das Kopieren von Passthrough-Dateien funktioniert, in der Dokumentation.
Da ich das Nunjucks-Templating-System verwendete, habe ich die Eigenschaft markdownTemplateEngine hinzugefügt und sie auf njk gesetzt, um sicherzustellen, dass sie weiß, dass sie zuerst durch Nunjucks geht, bevor etwas anderes.
module.exports = function(eleventyConfig) {
eleventyConfig.addWatchTarget("./src/css/")
eleventyConfig.addWatchTarget("./src/images/")
eleventyConfig.addPassthroughCopy("./src/css/")
eleventyConfig.addPassthroughCopy("./src/images/")
return {
dir: {
input: "src",
output: "public"
},
markdownTemplateEngine: "njk"
}
}
Dann habe ich eine styles.css-Datei im css-Ordner erstellt und ihr etwas zum Testen gegeben, um sicherzustellen, dass es funktioniert.
* {
color: teal;
}
Da ich die Ordner css und images bereits in .eleventy.js konfiguriert hatte, konnte ich diese Dateien über den URL-Filter von Eleventy referenzieren.
Um auf diese selbst gehosteten Dateien zuzugreifen, habe ich die URL-Filter von Eleventy in den href- und src-Eigenschaften der CSS- und Bild-Tags verwendet.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
<link rel="stylesheet" href="{{ '/css/styles.css' | url }}">
</head>
<body>
<h1>{{ title }}</h1>
<img src="{{ '/images/test_image.jpg' | url }}">
{{ content | safe }}
</body>
</html>
Jetzt war ich bereit, mein Eleventy-Projekt zu servieren.
Eleventy in der Entwicklung bereitstellen
Da ich die benutzerdefinierten Entwicklungsskripte bereits in package.json definiert hatte, konnte ich den folgenden Befehl ausführen
npm start
Dies kompilierte index.md im Verzeichnis src und generierte eine HTML-Datei im Verzeichnis public. Außerdem startete es einen Hot-Reload-Server über Browsersync, auf dem ich das Ergebnis unter https://:8080/ sehen konnte.

Während Eleventy in der Entwicklung lief, konnte ich mit dem Aufbau des restlichen Bragdocs beginnen.
Aufbau des Bragdoc-Systems
Mit einem grundlegenden Eleventy-Projekt in einer Ordnerstruktur, die der unten gezeigten ähnelt, begann ich mit dem Aufbau meines Bragdocs.
eleventy-bragdoc
├── src
│ ├── css
│ │ └── styles.css
│ ├── images
│ │ └── test_image.jpg
│ ├── _includes
│ │ └── layouts
│ │ └── base.njk
│ └── index.md
├── .eleventy.js
├── node_modules
├── package.json
├── package-lock.json
├── README.md
└── .gitignore
Erstellen einer Sammlung für Bragdoc-Einträge
Eleventy hat die Fähigkeit, Sammlungen zu erstellen, die ähnliche Inhalte gruppieren. Daher habe ich einen Ordner namens posts für meine Bragdoc-Einträge erstellt. Innerhalb dieses Ordners habe ich mehrere Markdown-Dateien erstellt, um jeden Eintrag darzustellen.
Die Dateinamen post-1.md, post-2.md, post-3.md beeinflussen nichts, was auf der Webseite gerendert wird.
eleventy-bragdoc
├── src
│ ├── posts
│ │ ├── post-1.md // new file
│ │ ├── post-2.md // new file
│ │ └── post-3.md // new file
│ ├── css
│ │ └── styles.css
│ ├── images
│ │ └── test_image.jpg
│ ├── _includes
│ │ └── layouts
│ │ └── base.njk
│ └── index.md
├── .eleventy.js
├── node_modules
├── package.json
├── package-lock.json
├── README.md
└── .gitignore
Die von mir als nützlich erachteten benutzerdefinierten Eigenschaften
- Titel
- Datum (standardmäßig werden Beiträge chronologisch sortiert)
- Kategorien (eine Liste von Werten zur Organisation von Einträgen)
- Öffentlich / Privat (ein boolescher Wert – wahr oder falsch –, der bestimmt, ob Sie ihn im Bragdoc anzeigen möchten)
- Symbol (ein von Notion inspiriertes Designelement zur visuellen Organisation von Einträgen)
Ich entschied, dass die Beschreibung für jeden Eintrag der Body-Inhalt der Markdown-Datei sein würde, da dies mir die Freiheit geben würde, Absätze, Bilder, Codeblöcke usw. hinzuzufügen. Darüber hinaus war ich nicht auf Markdown-Elemente beschränkt, da ich auch HTML einfügen und es mit CSS stylen konnte.
Unten sehen Sie ein Beispiel für einen Bragdoc-Eintrag in einer Markdown-Datei
---
title: Build my own Bragdoc using Eleventy
date: 2021-09-19
categories:
- Learning
- Eleventy
public: True
icon: 🎈
---
I learned how to use Eleventy to build my own bragdoc!
Einige Anmerkungen
- Links, die in Markdown geschrieben sind, öffnen sich standardmäßig nicht in einem neuen separaten Fenster. Nach einiger Recherche bin ich auf einen Code-Schnipsel von Mark Thomas Miller gestoßen, den ich kurz vor dem schließenden
<body>-Tag inbase.njkhinzugefügt habe. Das ist vielleicht nicht Ihr Ding (es ist definitiv nicht Chris' Ding), aber nur für den Fall, dass Sie es brauchen.
<script>
// Making all external links open in new tabs
// Snippet by Mark Thomas Miller
(function () {
const links = document.querySelectorAll("a[href^='https://'], a[href^='http://']")
const host = window.location.hostname
const isInternalLink = link => new URL(link).hostname === host
links.forEach(link => {
if (isInternalLink(link)) return
link.setAttribute("target", "_blank")
link.setAttribute("rel", "noopener")
})
})()
</script>
- Die Front Matter-Eigenschaft
datemuss im FormatYYYY-MM-DDgeschrieben werden. - Sie können beliebig viele benutzerdefinierte Front Matter-Eigenschaften zuweisen. Stellen Sie einfach sicher, dass, wenn Sie planen, auf die Eigenschaft in der Vorlage zuzugreifen, die Eigenschaft in allen Markdown-Dateien vorhanden ist, die dieselbe Vorlage verwenden; andernfalls kann dies den Build unterbrechen.
- Listen im Front Matter können auf verschiedene Weisen geschrieben werden (z. B. als Array oder einzeilig).
Zuweisen von Front Matter-Eigenschaften zu einer Sammlung
Anstatt Front Matter-Eigenschaften wiederholt mit demselben Wert in jeder Markdown-Datei zuzuweisen, habe ich ein JSON-Datei im Datenverzeichnis erstellt, um dasselbe Schlüssel-Wert-Paar nur einmal über eine Sammlung hinweg zuzuweisen.
Um eine Datendatei zu erstellen, muss sie denselben Namen wie die Sammlung haben, d. h. posts.json. Außerdem muss die Datei im Sammlungsordner liegen, d. h. im Ordner posts.
eleventy-bragdoc
├── src
│ ├── posts
│ │ ├── posts.json // new file
│ │ ├── post-1.md
│ │ ├── post-2.md
│ │ └── post-3.md
│ ├── css
│ │ └── styles.css
│ ├── images
│ │ └── test_image.jpg
│ ├── _includes
│ │ └── layouts
│ │ └── base.njk
│ └── index.md
├── .eleventy.js
├── node_modules
├── package.json
├── package-lock.json
├── README.md
└── .gitignore
Zu diesem Zeitpunkt waren die Beiträge für das Bragdoc noch nicht als Sammlung definiert. Um dies zu tun, habe ich die tags-Eigenschaft in posts.json hinzugefügt. Hier habe ich dieser Eigenschaft den Wert „posts“ zugewiesen, damit ich auf die Sammlung zugreifen kann, indem ich collections.posts aufrufe.
Und da ich nicht wollte, dass jeder Beitrag seine eigene Seite hat, d. h. https://:8080/posts/post-1/, habe ich seinen automatisch generierten Permalink deaktiviert.
{
"tags": "posts",
"permalink": false
}
Auflisten von Bragdoc-Einträgen
Vereinfacht ausgedrückt ist das Bragdoc eine Seite, die aus den Einträgen in der Sammlung posts besteht. Um auf die Front Matter-Eigenschaften und den Body-Inhalt der Markdown-Dateien zuzugreifen, werden die Einträge über Nunjucks durchlaufen.
Um dies zu tun, ging ich zurück zu index.md und änderte die Dateiendung von Markdown zu Nunjucks, d. h. index.njk.
eleventy-bragdoc
├── src
│ ├── posts
│ │ ├── posts.json
│ │ ├── post-1.md
│ │ ├── post-2.md
│ │ └── post-3.md
│ ├── css
│ │ └── styles.css
│ ├── images
│ │ └── test_image.jpg
│ ├── _includes
│ │ └── layouts
│ │ └── base.njk
│ └── index.njk // changed filetype
├── .eleventy.js
├── node_modules
├── package.json
├── package-lock.json
├── README.md
└── .gitignore
Als Nächstes ersetzte ich den Inhalt von index.njk durch eine Nunjucks for-Schleife.
Eine Nunjucks-Funktion (for-Schleife, if-Anweisung usw.) muss Start- und End-Tags enthalten.
Da die Reihenfolge der Beiträge standardmäßig chronologisch war (älteste zuerst), habe ich den reverse-Filter hinzugefügt, um die neuesten oben anzuzeigen.
Um das Front Matter abzurufen und es in HTML zu rendern (wie das date und der title eines Beitrags), musste ich durch eine weitere „Datenschicht“ gehen. Der Zugriff auf Eigenschaften im Front Matter erfordert doppelte geschweifte Klammern.
---
title: "11ty x Bragdocs"
layout: "layouts/base.njk"
---
{% for post in collections.posts | reverse %}
<p>
{{ post.data.date }} - {{ post.data.title }}
</p>
{% endfor %}

Filtern von Bragdoc-Einträgen
Um bestimmte Einträge zu filtern, habe ich die Front Matter-Daten verwendet, um zu prüfen, ob die Eigenschaft public auf True gesetzt war. Wenn die Eigenschaft auf False gesetzt war, erschien der Eintrag nicht im Bragdoc.
Ähnlich wie beim Zugriff auf Front Matter-Eigenschaften, wie public über eine Nunjucks-Funktion, musste ich wieder durch eine weitere „Datenschicht“ gehen.
---
title: "11ty x Bragdocs"
layout: "layouts/base.njk"
---
{% for post in collections.posts | reverse %}
{% if post.data.public %}
<p>
{{ post.data.date }} - {{ post.data.title }}
</p>
{% endif %}
{% endfor %}

Hinzufügen von benutzerdefinierten Datenfiltern
Standardmäßig rendert die date-Eigenschaft etwas, das uns im Allgemeinen unbekannt ist. Nach einiger Recherche fand ich einen benutzerdefinierten Filter, der von Phil Hawksworth geschrieben wurde. Um den Filter zu verwenden, erstellte ich eine Datei namens dates.js und platzierte sie in einem neuen Ordner namens _filters.
eleventy-bragdoc
├── src
│ ├── _filters // new folder
│ │ └── dates.js // new file
│ ├── posts
│ │ ├── posts.json
│ │ ├── post-1.md
│ │ ├── post-2.md
│ │ └── post-3.md
│ ├── css
│ │ └── styles.css
│ ├── images
│ │ └── test_image.jpg
│ ├── _includes
│ │ └── layouts
│ │ └── base.njk
│ └── index.njk
├── .eleventy.js
├── node_modules
├── package.json
├── package-lock.json
├── README.md
└── .gitignore
Dann habe ich in dates.js Folgendes hinzugefügt:
/*
A date formatter filter for Nunjucks
Written by Phil Hawksworth
*/
module.exports = function(date, part) {
var d = new Date(date);
if(part == 'year') {
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();
}
Um auf den Datumsfilter im Projekt zuzugreifen, habe ich einen neuen Filter in .eleventy.js hinzugefügt, bei dem ich ihn unter dem benutzerdefinierten Namen dateDisplay aufrufen kann.
module.exports = function (eleventyConfig) {
// Add filter
eleventyConfig.addFilter("dateDisplay", require("./src/_filters/dates.js") );
eleventyConfig.addPassthroughCopy("./src/css/")
eleventyConfig.addPassthroughCopy("./src/images/")
eleventyConfig.addWatchTarget("./src/css/")
eleventyConfig.addWatchTarget("./src/images/")
return {
dir: {
input: "src",
output: "public"
},
markdownTemplateEngine: "njk"
}
}
In index.njk habe ich den Filter dateDisplay der Variablen date zugewiesen und sie in einem menschenlesbaren Format gerendert.
---
title: "11ty x Bragdocs"
layout: "layouts/base.njk"
---
{% for post in collections.posts | reverse %}
{% if post.data.public %}
<p>
{{ post.data.date | dateDisplay }} - {{ post.data.title }}
</p>
{% endif %}
{% endfor %}
Der Server muss jedes Mal neu gestartet werden, wenn Sie etwas an der Konfigurationsdatei ändern.

Um den Body-Inhalt eines Beitrags zurückzugeben, habe ich templateContent aufgerufen und den safe-Filter hinzugefügt, damit er jegliches HTML in der Markdown-Datei rendert, anstatt es zu escapen.
---
title: "11ty x Bragdocs"
layout: "layouts/base.njk"
---
{% for post in collections.posts | reverse %}
{% if post.data.public %}
<p>
{{ post.data.date | dateDisplay }} - {{ post.data.title }}
<br/>
{{ post.templateContent | safe }}
</p>
<br/>
{% endif %}
{% endfor %}

Schließlich habe ich eine weitere for-Schleife eingefügt, um die Werte in der Front Matter-Eigenschaft categories aufzulisten.
---
title: "11ty x Bragdocs"
layout: "layouts/base.njk"
---
{% for post in collections.posts | reverse %}
{% if post.data.public %}
<p>
{{ post.data.date | dateDisplay }} - {{ post.data.title }}
<br/>
{{ post.templateContent | safe }}
{% for category in post.data.categories %}
<span># {{category}}</span>
{% endfor %}
</p>
<br/>
{% endif %}
{% endfor %}

Nachdem ich mit dem Extrahieren von Daten aus der Beitragsammlung fertig war, war es an der Zeit, die HTML-Struktur aufzubauen.
Strukturieren des Bragdocs
Partials in Eleventy ermöglichen es uns, Teile von HTML oder Vorlagen wiederholt zu verwenden. Dies vereinfacht auch den Code von einer riesigen Vorlagendatei zu überschaubaren Teilen, die zusammenpassen.
Innerhalb der <body>-Tags von base.njk habe ich alles außer dem Inhalt und dem Snippet entfernt.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
<link rel="stylesheet" href="{{ '/css/styles.css' | url }}">
</head>
<body>
{{ content | safe }}
<script>
(function () {
const links = document.querySelectorAll("a[href^='https://'], a[href^='http://']")
const host = window.location.hostname
const isInternalLink = link => new URL(link).hostname === host
links.forEach(link => {
if (isInternalLink(link)) return
link.setAttribute("target", "_blank")
link.setAttribute("rel", "noopener")
})
})()
</script>
</body>
</html>

Als Nächstes habe ich bragdoc-entry.njk erstellt, das sich in einem neuen Ordner namens partials befindet.
eleventy-bragdoc
├── src
│ ├── _filters
│ │ └── dates.js
│ ├── posts
│ │ ├── posts.json
│ │ ├── post-1.md
│ │ ├── post-2.md
│ │ └── post-3.md
│ ├── css
│ │ └── styles.css
│ ├── images
│ │ └── test_image.jpg
│ ├── _includes
│ │ ├── partials // new folder
│ │ │ └── bragdoc-entry.njk // new file
│ │ └── layouts
│ │ └── base.njk
│ └── index.njk
├── .eleventy.js
├── node_modules
├── package.json
├── package-lock.json
├── README.md
└── .gitignore
Innerhalb von bragdoc-entry.njk habe ich den Inhalt, der den Bragdoc-Eintrag ausmacht, den ich in index.njk geschrieben hatte, hierher gebracht. Beachten Sie, dass er kein Front Matter benötigt, da er als Snippet behandelt wird.
Partials erweitern keine Vorlage, daher benötigen sie kein Front Matter.
<p>
{{ post.data.date | dateDisplay }} - {{ post.data.title }}
<br/>
{{ post.templateContent | safe }}
{% for category in post.data.categories %}
<span># {{category}}</span>
{% endfor %}
</p>
<br/>
Dann habe ich zwischen der if-Anweisung in index.njk ein include-Tag hinzugefügt, das auf das bragdoc-entry.njk Partial verweist. Dadurch wird der Inhalt von bragdoc-entry.njk wiederholt hinzugefügt, bis die for-Schleife abgeschlossen ist.
---
title: "11ty x Bragdocs"
layout: "layouts/base.njk"
---
{% for post in collections.posts | reverse %}
{% if post.data.public %}
{% include 'partials/bragdoc-entry.njk' %}
{% endif %}
{% endfor %}
Als Nächstes habe ich die gesamte for-Schleife mit benutzerdefiniertem HTML umschlossen, einschließlich eines Headers, eines Profilcontainers und eines Footers. Zu diesem Zeitpunkt habe ich auch ein Profilbild im Ordner images aufgenommen und es mit dem URL-Filter von Eleventy im benutzerdefinierten HTML referenziert.
---
title: "11ty x Bragdocs"
layout: "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="{{ '/images/profile_picture.jpg' | url }}">
<h1 class="bragdoc__name">Emily Y Leung</h1>
<div class="role">Computational Designer</div>
</div>
{% for post in collections.posts | reverse %}
{% if post.data.public -%}
{% include 'partials/bragdoc-entry.njk' %}
{% endif %}
{% endfor %}
</div>
<footer>
<div><a target="_blank" href="https://www.bragdocs.com/">Bragdocs</a> inspired theme built with <a target="_blank" href="https://www.11ty.dev/">11ty</a></div>
<div>Made with ♥ by <a target="_blank" href="https://emilyyleung.github.io/">Emily Y Leung</a></div>
</footer>
</div>

Dann habe ich in bragdoc-entry.njk die HTML-Struktur aktualisiert und Klassen für das Styling hinzugefügt.
<div class="bragdoc__entry">
<div class="bragdoc__entry-milestone"></div>
<div class="bragdoc__entry-block">
<span class="bragdoc__entry-date">
{{ post.data.date | dateDisplay }}
</span>
<br/>
<h2 class="bragdoc__entry-title"><span class="bragdoc__icon">{{ post.data.icon }}</span> {{ post.data.title }}</h2>
<div class="bragdoc__entry-content">
{{ post.templateContent | safe }}
</div>
</div>
<div class="bragdoc__taglist">
{% for category in post.data.categories %}
<span># {{category}}</span>
{% endfor %}
</div>
</div>

Zugriff auf globale Daten
Ein guter Weg, globale Daten zu verstehen, ist, sich vorzustellen, eine HTML-Vorlage zu erstellen, die jemand als Basis für seine Website verwenden könnte. Anstatt nach bestimmten HTML-Tags zu suchen, um den Text zu ersetzen, muss er nur bestimmte Werte in einer externen Datei ersetzen, die dann den Inhalt aktualisiert. Dies ist eine der vielen Dinge, die eine globale Datendatei für uns tun kann.
Eleventy kann globale Datendateien aus JSON lesen, wenn sie in einem Ordner namens _data platziert werden. Daher habe ich eine data.json-Datei erstellt, auf die ich zugreifen kann, wenn ich {{data}} aufrufe, und dann die Eigenschaften aus dem JSON-Objekt auswähle.
eleventy-bragdoc
├── src
│ ├── _data // new folder
│ │ └── data.json // new file
│ ├── _filters
│ │ └── dates.js
│ ├── posts
│ │ ├── posts.json
│ │ ├── post-1.md
│ │ ├── post-2.md
│ │ └── post-3.md
│ ├── css
│ │ └── styles.css
│ ├── images
│ │ ├── profile_picture.jpg
│ │ └── test_image.jpg
│ ├── _includes
│ │ ├── partials
│ │ │ └── bragdoc-entry.njk
│ │ └── layouts
│ │ └── base.njk
│ └── index.njk
├── .eleventy.js
├── node_modules
├── package.json
├── package-lock.json
├── README.md
└── .gitignore
Innerhalb von data.json habe ich Eigenschaften eingefügt, die im gesamten Projekt wiederverwendet wurden.
{
"mywebsite": "https://emilyyleung.github.io/",
"myname": "Emily Y Leung",
"myrole": "Computational Designer"
}
Ein großartiger Anwendungsfall war, den Inhalt des Profils und des Footers in index.njk zu ersetzen.
<!-- Profile -->
<div class="bragdoc__profile">
<img class="bragdoc__photo" src="{{ '/images/profile_picture.jpg' | url }}">
<h1 class="bragdoc__name">{{ data.myname }}</h1>
<div class="role">{{ data.myrole }}</div>
</div>
<!-- Footer -->
<footer>
<div><a target="_blank" href="https://www.bragdocs.com/">Bragdocs</a> inspired theme built with <a target="_blank" href="https://www.11ty.dev/">11ty</a></div>
<div>Made with ♥ by <a target="_blank" href="{{ data.mywebsite }}">{{ data.myname }}</a></div>
</footer>
Styling the bragdoc
Mit der Fertigstellung der Bragdoc-Struktur habe ich das Styling in styles.css aktualisiert.
Um bragdocs.com zu imitieren, habe ich einige ihrer Farben ausgewählt und sie in einer Root-Variable gespeichert.
Zusätzlich wollte ich mehrere Themes erstellen, daher habe ich eine benutzerdefinierte data-theme-Eigenschaft über der :root-Variable hinzugefügt. In diesem Fall ist das Standard-Farbthema „light“, unabhängig davon, ob data-theme dem <html>-Tag zugewiesen ist. Das bedeutet aber auch, dass ich, wenn ich ein „dark“-Theme erstellen möchte, einen neuen Selektor html[data-theme="dark"] in meinem CSS erstellen und die gleichen Variablen mit alternativen Farben belegen kann, wie in :root angegeben.
: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: grey;
--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;
}
Um auf Root-Variablen zu verweisen, rufen Sie var() auf, wobei das Argument der Name der Eigenschaft ist.
Hier ist ein Beispiel, wie wir Root-Variablen verwenden können, um die Textfarbe in einem <p>-Tag zu stylen.
:root {
--text: teal;
}
p {
color: var(--text)
}
Zum Spaß habe ich eine dunkle Version hinzugefügt, die von Google Material inspiriert ist.
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);
}
Um zu steuern, welches Theme Sie verwenden möchten, fügen Sie die data-theme-Eigenschaft zum <html>-Tag in base.njk hinzu. Von dort aus weisen Sie den Wert zu, der dem entsprechenden CSS-Selektor entspricht, z. B. „light“ oder „dark“.
<!DOCTYPE html>
<html lang="en" data-theme="light">
Als nächstes habe ich das Styling für <body>, <footer>, den Bragdoc-Bereich und das Logo hinzugefügt.
body {
font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 13px;
color: var(--text);
background-color: var(--background);
margin: 0;
height: 100vh;
}
footer {
margin: 0 auto;
max-width: 500px;
padding-bottom: 1.5em;
text-align: center;
color: var(--footer);
padding-top: 2em;
margin-top: 2em;
}
/* Bragdoc Logo */
.bragdoc__header {
margin: 0;
padding: 1em;
font-size: 1.5em;
color: var(--logo)
}
/* Bragdoc Body */
.bragdoc__section {
height: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
margin: 0;
padding: 0;
}

Zu diesem Zeitpunkt machte es die Verwendung von benutzerdefinierten Tags und Klassen in HTML einfach, das Bragdoc-Layout zu replizieren.
/* Bragdoc User Profile */
.bragdoc__profile {
padding-top: 3em;
padding-bottom: 2em;
}
.bragdoc__photo {
width: 8em;
border-radius: 100%;
padding: 0;
height: 8em;
object-fit: cover;
}
.bragdoc__name {
color: var(--name);
margin-bottom: 0.25em;
}
.bragdoc__icon {
font-family: "Segoe UI Emoji", Times, serif;
}
.bragdoc__container {
max-width: 800px;
margin: 0 0 0 30em;
height: 100%;
}
.bragdoc__profile-role {
margin: 0;
}

Als nächstes habe ich die Einträge gestylt, um das Timeline-Design von bragdocs.com zu replizieren.
/* Individual Bragdoc Entry Blocks */
.bragdoc__entry {
position: relative;
}
.bragdoc__entry:first-child {
margin-top: 0;
}
.bragdoc__entry:before {
height: 100%;
position: absolute;
background-color: var(--entry-line);
width: 2px;
content: "";
top: 30px;
}
.bragdoc__entry:last-child:before {
background-color: var(--background);
}
.bragdoc__taglist {
margin-left: 1em;
padding: 1em;
}
.bragdoc__taglist > * {
border: 1px solid var(--tag);
padding: 0.25em 0.5em 0.25em 0.5em;
border-radius: 0.5em;
margin-right: 1em;
}
/* Entry Content */
.bragdoc__entry-block {
margin-left: 1em;
padding: 1em;
}
.bragdoc__entry-title {
margin-top: 4px;
color: var(--entry-title);
font-size: 1.5em;
}
.bragdoc__entry-date {
line-height: 3em;
color: var(--date);
}
/* Bragdoc milestone circle */
.bragdoc__entry-milestone {
position: absolute;
height: 5px;
width: 5px;
border: 2px solid var(--entry-circle);
background-color: var(--background);
left: 0;
top: 30px;
margin-top: -2px;
margin-left: -3px;
border-radius: 100px;
}
/* Bragdoc Entry Content */
.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;
color: var(--text);
}

Mithilfe von CSS-Media-Queries konnte ich auch die Textgröße sowie die Positionierung von HTML-Elementen steuern. Dies sorgt für eine gute Darstellung auf Mobilgeräten.
/* Make it responsive */
@media only screen and (max-width: 1400px) {
.bragdoc__container {
/* Center the bragdoc*/
margin: 0 auto;
}
.bragdoc__entry-title {
font-size: 1.25em;
}
}
@media only screen and (max-width: 870px) {
.bragdoc__container {
padding-left: 2em;
padding-right: 2em;
}
.bragdoc__entry-title {
font-size: 1.15em;
}
}

Die letzten Anpassungen am Design mussten die Beschreibung (d. h. den Markdown-Body-Inhalt) für jeden Eintrag berücksichtigen, die Sie in diesem Gist finden.
Da die CSS mit Bezug auf Root-Variablen strukturiert wurde, können wir weiterhin mehr Themes erstellen. Probieren Sie es aus und erkunden Sie Farbpaletten von Color Hunt oder Cooolers.
Bereitstellen des Bragdoc auf GitHub Pages
Ein Projekt von Grund auf neu zu bauen ist fantastisch, aber es noch besser mit der Welt zu teilen!
Während es unzählige Möglichkeiten gibt, ein Bragdoc zu hosten, habe ich mich entschieden, es auf GitHub Pages zu hosten. Das bedeutete, ich konnte die Basis-URL meines GitHub-Kontos verwenden und /eleventy-bragdoc/ am Ende hinzufügen.
Zu diesem Zeitpunkt hatte ich vom eleventy-bragdoc-Repository aus gearbeitet und bereits einen gh-pages-Branch erstellt.
Folgen Sie dieser Anleitung für Informationen, wie Sie GitHub Pages für Ihr Repository einrichten.
Konfigurieren des URL-Pfads
Um den URL-Pfad für die Bereitstellung zu konfigurieren, habe ich ein pathPrefix in .eleventy.js aufgenommen, um die Route relativ zur Basis-URL zu definieren.
Ohne Angabe eines pathPrefix ist der Standardwert /, der auf die Basis-URL verweist, d. h. https://emilyyleung.github.io/
Da ich bereits Inhalte auf der Basis-URL hatte, wollte ich diese auf einer Unterseite hosten, d. h. https://emilyyleung.github.io/eleventy-bragdoc/
Um den pathPrefix für Unterseiten festzulegen, muss er mit einem Schrägstrich beginnen und enden.
module.exports = function (eleventyConfig) {
// ...
return {
dir: {
input: "src",
output: "public"
},
markdownTemplateEngine: "njk",
pathPrefix: "/eleventy-bragdoc/"
}
}
Hinzufügen der GitHub Pages-Abhängigkeit
Nach der Konfiguration habe ich GitHub Pages über das Terminal installiert.
npm install gh-pages --save-dev
Dies fügt automatisch die Abhängigkeit zu package.json hinzu.
{
// ...
"devDependencies": {
"gh-pages": "^3.2.3"
},
// ...
}
Hinzufügen eines benutzerdefinierten Terminal-Skripts
Um den public-Ordner bereitzustellen, habe ich ein deploy-Skript hinzugefügt und den public-Ordner referenziert.
{
// ...
"scripts": {
"start": "eleventy --serve",
"build": "eleventy",
"deploy": "gh-pages -d public"
}
// ...
}
Ausführen des Builds
Genau wie in der Entwicklung habe ich mein Terminal in den eleventy-bragdoc-Ordner navigiert. Dieses Mal habe ich den folgenden Befehl ausgeführt, um die Dateien im public-Ordner neu zu erstellen.
npm run-script build
Um dann auf GitHub Pages bereitzustellen, habe ich den folgenden Befehl ausgeführt.
npm run deploy
Zugriff für die Bereitstellung gewähren
Zu diesem Zeitpunkt kann das Terminal Sie auffordern, sich über das Terminal oder die GitHub Desktop-Anwendung anzumelden. Wenn die Anmeldung fehlschlägt, kann das Terminal Sie auffordern, ein Authentifizierungstoken anstelle eines Passworts zu generieren. Hier ist eine Anleitung, wie Sie eines erstellen können.
Mit einer erfolgreichen Antwort vom Terminal konnte ich mein Bragdoc live sehen!
Ihr Bragdoc pflegen
Im Gegensatz zu Berichten und Büchern muss ein Bragdoc kontinuierlich als Live-Aufzeichnung Ihrer Fortschritte und Errungenschaften gepflegt werden. Betrachten Sie Ihr Bragdoc wie einen Garten, in dem die Pflege regelmäßige Aufmerksamkeit und Sorgfalt erfordert. Auch wenn Sie die Vorteile nicht sofort sehen, wird die investierte Zeit in die Pflege Ihres Dokuments zu weitaus größeren Erträgen führen. Sofortige Abrufbarkeit und die Möglichkeit, das Geleistete zu teilen, sind einige der Vorteile, wenn man diese Gewohnheit ausbildet.
Auch wenn Sie vielleicht nicht alles sofort festhalten können, schlägt Julia Evans vor, einen Zeitblock festzulegen, um Ihre Fortschritte zu überprüfen und das Dokument zu aktualisieren. Vielleicht sogar als zweiwöchentliche Gruppenaktivität, um alle Erfolge, groß und klein, zu feiern.
Für viele gilt: Je weniger Zeit es kostet, etwas zu tun, desto besser. Mit dieser Bragdoc-Einrichtung dauert das Hinzufügen neuer Einträge und das Neuerstellen der Website überhaupt nicht lange! Um Ihnen eine Vorstellung davon zu geben, wie einfach das ist, führe ich Sie durch den Prozess des Hinzufügens eines weiteren Eintrags, um das Tutorial abzuschließen.
Einen neuen Bragdoc-Eintrag hinzufügen
Fortfahrend von meiner letzten Bereitstellung werde ich zuerst eine neue Markdown-Datei in meinem posts-Ordner hinzufügen.
eleventy-bragdoc
├── src
│ ├── _data
│ │ └── data.json
│ ├── _filters
│ │ └── dates.js
│ ├── posts
│ │ ├── posts.json
│ │ ├── post-1.md
│ │ ├── post-2.md
│ │ ├── post-3.md
│ │ └── post-4.md // new entry goes here
│ ├── css
│ │ └── styles.css
│ ├── images
│ │ ├── profile_picture.jpg
│ │ └── test_image.jpg
│ ├── _includes
│ │ ├── partials
│ │ │ └── bragdoc-entry.njk
│ │ └── layouts
│ │ └── base.njk
│ └── index.njk
├── .eleventy.js
├── node_modules
├── package.json
├── package-lock.json
├── README.md
└── .gitignore
Innerhalb von post-4.md füge ich meine Frontmatter und den Beschreibungsinhalt ein.
---
title: Working towards publishing my first article on CSS-Tricks
date: 2021-10-02
categories:
- Writing
- Eleventy
public: True
icon: ✍🏻
---
Since re-creating [bragdocs.com](https://www.bragdocs.com/) using Eleventy, I am now in the process of writing the steps on how I did it.
Build ausführen
Nachdem die Einträge hinzugefügt und gespeichert wurden, bin ich bereit, Eleventy anzuweisen, meine Markdown-Dateien aus src zu referenzieren, um statische HTML-Dateien im public-Ordner zu generieren. Daher navigiere ich mit dem Terminal zu eleventy-bragdoc, wo ich den folgenden Befehl ausführe.
npm run-script build
Deploy ausführen
Da ich bereits einmal bereitgestellt habe, sollten meine GitHub-Anmeldedaten mir sofortigen Zugriff für die Bereitstellung gewähren, wenn ich den folgenden Befehl ausführe.
npm run deploy
Diese Änderungen werden dann auf meiner Website unter derselben konfigurierten URL widergespiegelt.

Was kommt als Nächstes?
Zunächst einmal herzlichen Glückwunsch zum Erstellen Ihres ganz eigenen Bragdocs von Grund auf! Es gehört Ihnen, es zu pflegen und zu teilen.
Während dieses Tutorial nur an der Oberfläche von dem kratzt, was mit Eleventy möglich ist, kann ein kleiner Schritt Sie in alle möglichen Richtungen führen. Um Ihre Neugier zu wecken, schauen Sie sich an, was andere mit Eleventy machen.
Sie können sich gerne melden, ich würde gerne sehen, was Sie sich einfallen lassen!