如何用Eleventy创建你自己的Bragdoc(附代码)

159 阅读22分钟

无论你作为一个开发者处于什么阶段,我们完成的任务--无论大小--都会对我们的个人和职业成长产生巨大影响。不幸的是,这些任务并不总是被认可,因为它们很容易在其他需要完成的事情的海洋中迷失。

我们所做的不被注意的任务属于所谓的 "隐形工作",这个概念是我从Ryan T. Harter的一个题为"为隐形工作争光 "的演讲中偶然发现的。这种类型的工作渗入了缝隙,因为我们的大脑没有记住事情的能力。然而,到了审查时间,我们发现自己在试图回忆过去6个月或12个月所做的事情时一再被卡住。

为了解决这个由来已久的问题,朱莉娅-埃文斯写了一篇文章,建议我们保留自己的 "吹嘘文件"。吹嘘文件和它听起来一样。它是一份允许你自己吹嘘你所做的所有有价值工作的文件。无论它是什么:

  • 你如何为一个项目做出贡献
  • 帮助他人
  • 改进现有流程
  • 发表演讲或举办研讨会
  • 你学到了什么
  • 课外活动(如博客、讲座、个人项目)。
  • 奖项和职业发展

编写吹嘘文件没有一个方法,但这并没有阻止Jonny BurchProgression的团队建立bragdocs.com

使用他们的网站来建立一个是一个伟大的想法,但还有什么比从头开始创建你自己的吹嘘文件更好的方法?

今天我想告诉你我是如何使用静态网站生成器Eleventy重新创建bragdocs.com的。只需要一点点的JavaScript和CSS,你就可以让你自己的网站运行起来!

我们要建立什么?

下面是遵循本教程的最终结果。你可以在这里找到现场演示。它模仿bragdocs.com作为一个起点,让你从头开始创建一个属于自己的网站:

要求

  • 在Node.js中安装包(10版或更高)。
  • 对HTML和CSS的一般理解
  • Markdown、Nunjucks模板和JavaScript(都是可选的,但有帮助)
  • 基本的编程概念,包括 if 语句、循环和访问JSON中的变量

什么是Eleventy?

Eleventy是一个静态网站生成器。这意味着你不需要建立一个全栈式的网站(前端和后端),而是可以灵活地用Eleventy接受的以下任何一种模板语言编写内容:HTML、Markdown、Liquid、Nunjucks、Mustache等。然后,这些内容被处理(如果你喜欢,可以使用自定义模板),生成静态的HTML页面,准备作为一个完整功能的网站托管。

设置我们的 "你好,世界!"Eleventy项目

在本教程中,我所提到的资源库是 **eleventy-bragdoc**,而我们正在努力的最终产品将被称为 "bragdoc"。

在GitHub上创建了一个用 README.md**.**gitignore 文件,我开始建立一个Eleventy项目。

创建一个新的项目

在里面 **eleventy-bragdoc**中,我开始了以下文件的设置。

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

通过终端导航到 **eleventy-bragdoc**我通过运行下面的命令初始化了这个项目。

npm init -y

这创建了一个 package.json 文件来存放我的节点包。

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

接下来,我安装了Eleventy。

npm install @11ty/eleventy

这给了我以下的文件和文件夹列表。

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

配置Eleventy项目

安装好Eleventy后,我更新了 scripts 文件中的 **package.json**文件,以包括以下命令:

  • start 命令在开发过程中为项目提供服务,运行Browsersync进行热重载。
  • build 命令创建可用于生产的HTML文件,以便将其托管到服务器上。
{
  // ...
  "scripts": {
    "start": "eleventy --serve",
    "build": "eleventy"
  },
 //  ...
}

接下来,我创建了一个必要的配置文件,叫做 **.eleventy.js**来指定自定义的输入和输出目录。

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

在里面 **.eleventy.js**中,我告诉Eleventy,它将引用文件夹中的内容来构建HTML文件。 src 文件夹中的内容来建立HTML文件。然后,输出被存储在一个名为 **public**:

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

创建正面的内容

为了制作我的第一个页面,我创建了 src 文件夹,我将其作为输入目录在 **.eleventy.js**.在它里面,我添加了我的第一个页面,一个叫作:的Markdown文件。 **index.md**

Eleventy可以使用许多模板语言,你可以混合使用。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

在Eleventy中,任何写在上面和下面的破折号(---)之间的键值对都被认为是前面的内容。

**index.md**中,我包含了一个 title 属性,其值为 "11ty x Bragdocs",并在前面的内容下面添加了一些测试内容。

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

This is the home page.

建立模板

接下来,我创建了一个Eleventy期望的文件夹,叫做 _includes 里面的 **src**.这就是模板,或者Eleventy所说的布局,必须住在这里。在这个文件夹中,我创建了一个子文件夹,名为 layouts 为我的第一个模板。 **base.njk**

这个 .njk 文件类型指的是模板语言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

我在里面添加了一个HTML5模板 **base.njk**:

<!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>

用模板和前台内容创建页面

**base.njk**中,在 **<title>**标签中,我想拉入 title 中定义的属性。 **index.md**,所以我使用了双大括号,即 **{{title}}**来访问这个变量。同样地,在正文中,我添加了 **<h1>**标签,并将其与相同的 title 属性。

接下来,我把其余的正文内容从 **index.md**使用 content 属性的其余内容。使用提供的 safe 过滤器,我告诉Eleventy渲染而不是转义Markdown文件内容中的任何HTML。

<!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>

然后我又跳回了 **index.md**并在前台添加了一个 layout 属性到前面的内容,并引用了 **base.njk**

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

This is the home page.

为了让你了解当我们运行构建时发生了什么,在 layout front matter属性中指定的模板被用来包装Markdown内容。在这个例子中,编译后的HTML将看起来像下面所示的那样。

<!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>

在构建中连接CSS和图片文件夹

虽然这部分可能不是所有Eleventy项目都需要的,但CSS和自带的图片总是可以添加的好功能。因此,我在 src 目录中。 css**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

然后,在 **.eleventy.js**,因为我希望这些文件夹内的内容在托管时可以被访问,我通过添加以下配置来引用这些文件夹。

  • **addWatchTarget**告诉Eleventy,当我们对这个目录中的文件进行修改时,它应该重新编译(比如说 styles.css 目录中的 css 文件夹)。
  • **addPassthroughCopy**告诉Eleventy,一旦文件被编译,就把目录中的内容传到 public 目录。

你可以在文档中阅读更多关于穿透式文件复制的工作方式。

由于我使用的是Nunjucks模板系统,我添加了 markdownTemplateEngine 属性,并将其设置为 njk 以确保它知道要先通过Nunjucks,然后才是其他东西。

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"
  }
}

然后我创建了一个 styles.css 文件夹中的 css 文件夹中创建了一个文件,并给它一些东西来测试,以确保它的工作。

* {
  color: teal;
}

由于我已经配置了 cssimages 文件夹,所以我可以使用Eleventy的URL过滤器来引用这些文件。 **.eleventy.js**文件夹,我就可以使用Eleventy的URL过滤器来引用这些文件。

为了访问这些自我托管的文件,我使用Eleventy的URL过滤器在 hrefsrc 属性中的URL过滤器。

<!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>

现在我已经准备好为我的Eleventy项目服务了。

为开发中的Eleventy提供服务

由于我已经定义了自定义开发脚本在 **package.json**中定义了自定义的开发脚本,我就可以运行下面的命令了。

npm start

这样就编译了 **index.md**目录中的 src 目录中编译,并生成一个HTML文件,放在 public 文件夹中。此外,它通过Browsersync启动了一个热重载服务器,我可以在那里看到结果。 **http://localhost:8080/**

到目前为止的结果

随着Eleventy在开发中的运行,我可以开始构建bragdoc的其他部分。

构建bragdoc系统

有了一个基本的Eleventy项目,在类似于下图的文件夹结构中,我开始构建我的bragdoc。

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

为bragdoc条目创建一个集合

Eleventy有能力创建集合,将类似的内容组合在一起。因此,我创建了一个文件夹叫 posts 为我的bragdoc条目。在该文件夹内,我创建了多个Markdown文件来代表每个条目。

文件名post-1.md,post-2.md,post-3.md 并不影响在网页上的任何渲染。

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

我认为包括的自定义属性是有用的。

  • 标题
  • 日期(默认情况下,帖子是按时间顺序排序的)
  • 类别(一个用于组织条目的数值列表)
  • 公开/私密(一个布尔值--真或假--决定你是否要在bragdoc上显示它。)
  • 图标(一个受Notion启发的设计元素,用于视觉上组织条目。)

我决定每个条目的描述将是Markdown文件的主体内容,因为这将给我添加段落、图片、代码块等的自由。此外,我并不局限于Markdown元素,因为我也可以包括HTML,并使用CSS进行样式设计。

下面是一个Markdown文件中的bragdoc条目的例子。

---
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!

有些事情需要注意

  • 用Markdown写的链接,默认情况下不会在一个新的空白窗口中打开。因此,经过一些研究,我偶然发现了马克-托马斯-米勒一个片段,我把它加在了Markdown的结尾的 **<body>**中的 **base.njk**.这可能不是你的东西(这绝对不是克里斯的东西),但万一你需要它。
<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>
  • 前面提到的 date 前面的事项属性必须以 **YYYY-MM-DD**格式。
  • 你可以根据你的需要指定任意多的自定义前台属性。只要确保如果你打算在模板中访问该属性,该属性在所有使用同一模板的Markdown文件中都存在;否则它可能会破坏构建。
  • 前期事务中的列表可以用多种方式来写(例如,数组或单行)。

为一个集合分配前事项的属性

我创建了一个数据目录JSON文件,在一个集合中只分配一次相同的键值对,而不是在每个Markdown文件中重复分配具有相同价值的前事项属性。

要创建一个数据目录文件,它必须有与集合相同的名称,即 **posts.json**.此外,该文件也必须放在集合文件夹内,即 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

在这一点上,bragdoc的帖子还没有被定义为一个集合。为了做到这一点,我在 tags 中的属性 **posts.json**.在这里,我给该属性分配了 "post "的值,这样我就可以通过调用.NET来访问这个集合。 **collections.posts**

因为我不需要每个帖子都有自己的页面,也就是说。 **http://localhost:8080/posts/post-1/**我关掉了它的自动生成的固定链接

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

列出bragdoc条目

简单地说,bragdoc是一个由集合中的条目组成的页面。 posts 集合中的条目组成的页面。为了访问Markdown文件的正面属性和正文内容,这些条目通过Nunjucks进行循环。

为了做到这一点,我回到了 **index.md**并将文件类型从Markdown改为Nunjucks,即 **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

接下来,我把 **index.njk**的内容替换为Nunjucks for 循环。

一个Nunjucks函数(for 循环。 if 语句等)必须包括开始和结束标签。

由于默认情况下帖子的顺序是按时间顺序排列的(最早的在前),所以我添加了一个 reverse 过滤器,将最新的显示在顶部。

要访问前面的内容并将其呈现在HTML中(如 datetitle 的),我不得不通过另一个 "数据 "层。访问正面内容的属性需要双大括号。

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

{% for post in collections.posts | reverse %}
  <p>
    {{ post.data.date }} - {{ post.data.title }}
  </p>
{% endfor %}

还有一点进展

筛选bragdoc条目

为了过滤某些条目,我使用前台数据来检查是否有 public 属性是否被设置为 **True**.如果该属性被设置为 **False**,该条目就不会出现在bragdoc中。

同样地,在访问前言属性时,比如说 public 时,我又需要通过另一个 "数据 "层。

---
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 %}

帖子是按标题排序的。

添加自定义数据过滤器

在默认情况下,该 date 属性呈现的是我们通常不熟悉的东西。因此,经过一些研究,我发现了一个由Phil Hawksworth编写的自定义过滤器。为了使用这个过滤器,我创建了一个文件叫做 **dates.js**的文件,并把它放在一个新的文件夹里,名为 **_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

然后,在 **dates.js**中,我添加了以下内容。

/*
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();
}

为了访问项目中的日期过滤器,我在项目中添加了一个新的过滤器。 **.eleventy.js**中添加了一个新的过滤器,我可以用自定义的名称来调用它 **dateDisplay**

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"
  }
}

**index.njk**中,我把这个 dateDisplay 过滤器到 date 变量,将其呈现为人类可读的格式。

---
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 %}

每次改变配置文件中的内容时,都需要重新启动服务器。

有更新日期格式的帖子。

为了返回一个帖子的正文内容,我调用了 **templateContent**并添加了 safe 过滤器,这样它就可以渲染Markdown文件中的任何HTML,而不是将其转义。

---
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 %}

有正文内容的帖子。

最后,我包含了另一个for 循环,以列出 categories 前面的属性。

---
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 %}

在完成了从帖子集合中提取数据之后,是时候建立HTML结构了。

建立bragdoc的结构

Eleventy中的参数允许我们重复使用HTML或模板的片段。这也将代码从一个庞大的模板文件简化为可管理的片段。

**<body>**的标签内。 **base.njk**的标签内,我删除了除内容和片段之外的所有内容。

<!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>

接下来,我创建了 **bragdoc-entry.njk**它位于一个新的文件夹中,名为 **partials**

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

里面的 **bragdoc-entry.njk**的文件夹,我把构成bragdoc条目的内容带过来,用的是 **index.njk**.请注意,它不需要任何前面的内容,因为它被当作一个片段来处理。

Partials并不扩展模板,所以它们不需要任何前台内容。

<p>
  {{ post.data.date | dateDisplay }} - {{ post.data.title }}
  <br/>
  {{ post.templateContent | safe }}
  {% for category in post.data.categories %}
      <span># {{category}}</span>
  {% endfor %}
</p>
<br/>

然后,在 if 中的语句,我在 **index.njk**中的语句之间,我添加了一个 include 标签,引用 bragdoc-entry.njk 部分。通过这样做,里面的内容 bragdoc-entry.njk 的内容会被重复添加,直到 for 循环结束。

---
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 %}

接下来,我把整个 for 循环,包括一个标题、简介容器和页脚。在这一点上,我还在文件夹中加入了一张个人资料图片,并在自定义的图片中引用了它。 images 文件夹中,并在自定义HTML中使用Eleventy的URL过滤器来引用它。

---
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>

然后,在 **bragdoc-entry.njk**中,我更新了HTML结构,并包含了样式设计的类。

<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>

访问全局数据

理解全局数据的一个好方法是想象建立一个HTML模板,有人可以用它作为网站的基础。他们不需要搜索特定的HTML标签来替换文本,而只需要替换一个外部文件中的某些值,然后更新内容。这就是全局数据文件可以为我们做的许多事情之一。

Eleventy可以访问用JSON编写的全局数据文件,当它们被放置在一个名为 **_data**.因此,我创建了一个 data.json 文件,当我调用 **{{data}}**然后挑出我在JSON对象中提供的任何属性。

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

在里面 **data.json**我包括在整个项目中重复使用的属性。

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

一个很好的用例是,在项目中替换简介和页脚中的内容。 **index.njk**

<!-- 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>

塑造bragdoc的风格

随着bragdoc结构的完成,我更新了 "我的 "中的风格。 **styles.css**

为了模仿bragdocs.com,我选择了他们的一些颜色,并将它们存储在一个根变量中。

此外,我想创建多个主题,所以我在Bragdoc的顶部添加了一个自定义的 data-theme 属性在 :root 变量之上。在这种情况下,默认的颜色主题是 "浅色",无论是否 data-theme 被分配到 **<html>**标签。但这也意味着,如果我想创建一个 "深色 "主题,我可以在CSS中创建一个新的选择器 html[data-theme="dark"] 中指定的相同变量指定替代颜色。 **: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: 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;
}

要引用根变量,可以调用 var() 其中的参数是属性的名称。

下面是一个例子,说明我们如何使用根变量来设计文本在一个 **<p>**标签中的文本颜色。

:root {
  --text: teal;
}

p {
  color: var(--text)
}

为了好玩,我添加了一个暗色版本,灵感来自于Google Material

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);
}

要控制你要使用的主题,请将 data-theme 属性添加到 <html> 标签中的 **base.njk**.从那里,把相关的值分配给相应的CSS选择器,即 "light "或 "dark"。

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

接下来,我将样式添加到 **<body>**, **<footer>**, bragdoc部分,以及标志。

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;
}

在这一点上,HTML中的自定义标签和类使得复制bragdoc的布局变得简单。

/* 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;
}

接下来,我对条目进行了样式设计,以复制bragdocs.com的时间线设计。

/* 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);
}

使用CSS媒体查询,我还可以控制文本的大小以及HTML元素的位置。这使得它在手机上观看时效果很好。

/* 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;
  }
}

设计的最后润色需要考虑到每个条目中的描述(即Markdown主体内容),你可以在这个Gist中找到

鉴于CSS的结构已经参考了根变量,我们可以继续创建更多的主题。试试从Color HuntCooolers中探索调色板。

将bragdoc部署到GitHub页面

从头开始建立一个项目是非常棒的,但与世界分享它就更棒了!请跟随本教程了解如何在GitHub页面上部署bragdoc。

虽然有无数种方法来托管bragdoc,但我决定把它托管在GitHub Pages上。这意味着我可以使用我的GitHub账户的基本URL,并在后面加上 **/eleventy-bragdoc/**到它的末尾。

在这一点上,我已经从 eleventy-bragdoc 仓库,并且已经创建了一个 gh-pages 分支。

遵循本教程,了解如何为你的仓库设置GitHub Pages的信息。

配置URL路径

为了配置部署用的URL路径,我在 pathPrefix.eleventy.js 来定义相对于基本URL的路由。

如果不指定a **pathPrefix**的情况下,默认值是 **/**,它链接到基本URL,即 **https://emilyyleung.github.io/**

由于我在基本URL上已经有了内容,我想把它放在一个子页面上,即。 **https://emilyyleung.github.io/eleventy-bragdoc/**

要设置 pathPrefix 为子页面,它必须以斜线开始和结束。

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

添加GitHub Pages的依赖性

配置完毕后,我用终端安装了GitHub Pages。

npm install gh-pages --save-dev

这将自动把依赖关系添加到 **package.json**

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

添加一个自定义的终端脚本

为了部署 public 文件夹,我添加了一个 deploy 脚本,并引用了 public 文件夹。

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

运行构建

就像在开发中一样,我把我的终端导航到 eleventy-bragdoc 文件夹。但这一次,我运行了以下命令,将文件重建到 public 文件夹。

npm run-script build

然后,为了部署到GitHub Pages,我运行了以下命令。

npm run deploy

授予部署的权限

这时,终端可能会要求你通过终端或 GitHub 桌面应用程序登录。如果登录失败,终端可能会要求你生成一个认证令牌来代替密码。这里有一份关于如何创建一个的指南。

随着终端的成功响应,我可以看到我的bragdoc已经上线了

维护你的bragdoc

与报告和书籍不同,bragdoc必须持续维护,作为你的进展和成就的实时记录。把你的bragdoc想象成一个花园,需要定期关注和照顾。虽然你可能不会马上看到好处,但投入时间照顾你的文件会带来更大的回报。即时回忆和分享你所做的事情的能力是形成这种习惯的一些好处。

虽然你可能无法记下所有发生的事情,但Julia Evans建议设定一个时间段来回顾你的进展并更新文件。也许甚至可以把它作为每两周一次的小组活动,以庆祝所有的胜利,无论大小。

对许多人来说,做一件事花的时间越少越好。有了这个bragdoc的设置,添加新的条目和重建网站根本不需要花费太多时间!为了让你了解这有多简单,我将带领你完成添加另一个条目的过程,以完善本教程。

添加一个新的bragdoc条目

继续我上次的部署,我将首先在我的 posts 文件夹里:

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

在里面 **post-4.md**中,我将添加我的正面内容和描述内容:

---
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.

运行构建

在添加并保存了条目后,我准备告诉Eleventy引用我的Markdown文件,从 src 文件夹中生成静态HTML文件。 public 文件夹中生成静态HTML文件。所以我把终端导航到 eleventy-bragdoc 在那里我运行了以下命令。

npm run-script build

运行部署

由于我之前已经部署过一次,所以在运行下面的命令时,我的GitHub凭证应该会立即给予我部署的权限。

npm run deploy

然后这些变化就会反映在我的网站上,也就是同一个配置的URL上。