手记3:实例教学之Ghost模板定制

接下来我们聊一下如何定制这个博客的风格。

7. 定制Themes

Ghost缺省使用的主题叫casper theme,你可以在博客管理界面Settings -> General -> Themes中找到你当前安装过的全部Themes,并任意激活/删除它们。

有两种方法来安装Themes。第一种是在这个管理界面中选最下面的『Upload A Theme』来上传你下载过的Theme .zip包,第二种是直接将.zip包解压到Ghost安装目录的content/themes/目录下。

我选择的是使用小蘿蔔丁(在这里)发布的kaldorei - 0.8.0,你可以下载或阅读这个Theme相关的说明(这里)。我可能将来会将博客换成别的什么风格,不过现在kaldorei还是挺合用的。

但我还是做了一些修改(关于Themes的基础使用与修改可以参考这里)。

7.1 一些基本和简单的使用

Ghost的一个好处是可以随意定制并生成静态页,这些页可以用博客后台来发布或更新,或者仅仅只是一个普通的静态页面(无需通过后台来更新内容)。无论如果,Ghost提供很简单的方法来做这件事,并且允许你为每一个静态页定制自己的页面风格、主题或模板。

kaldorei主题是使用这个方式来实现『历史归档』的功能(参考这里),这也相当于介绍了『定制静态页』功能的用法——所以我的博客的『关于』页面就是这样做的。

7.1.1 处理背景色与背景图片

需要两个操作。其一:

/* modify file at ./ghost-theme-kaldorei/assets/css/screen.css */
body {
    margin: 0;
    background: #000;
}

其二,在default.hbs模板的body标签之后添加如下风格样式:

<style>
body {
    background-image: url(/assets/img/background.jpg);
    background-repeat: no-repeat;
    background-position: top center;
    background-attachment: fixed;
    background-size: auto;
}

.site-wrapper {
    background: none;
}

.main-header {
    background: none;
    border-bottom: none;
}

.main-nav a {
    color: #FFF;
}
</style>

注意这个风格中的背景图片是放在Ghost安装目录下的content/themes/ghost-theme-kaldorei/assets/img目录中的。makesite.sh脚本(或Monster工具)会搜索到这个文件,并下载这个文件到你的static目录中。

7.1.2 为每篇博客添加『编辑』按钮

当添加了这个按钮之后,我在本地博客中读博文的时就可以随时编辑它,而不必总是回到管理后台去找到这篇文章~~——Ghost后台没有搜索功能~~。

因为添加的这个按钮对线上的用户没有意义,所以在我的makesite.sh脚本中有一处代码会将它从./static中的静态页面中清理掉。

<!-- modify file at ./ghost-theme-kaldorei/post.hbs -->
<span class="post-meta-item pull-right">
  <!-- 在这个位置插入如下行 -->
  <a href="/ghost/editor/{{id}}/" target="_blank">编辑</a>
</span>

7.1.3 移除所有页脚

纯粹只是个人不喜欢而已,因此除了保留版权说明之外,其它页脚都全部合并/删除掉了。基本上你在.hbs文件中搜索-footer然后自己斟情清理就行了。

> grep 'footer' *.hbs partials/*

7.1.4 定制个人信息

相关的信息页面在如下模板中,斟情修改(许多信息可以在博客后台的个人配置与网页配置中定制):

## 清理掉部分社交信息
ghost-theme-kaldorei/partials/social.hbs
ghost-theme-kaldorei/partials/post_author.hbs
## 我移除掉了标签数量的统计
ghost-theme-kaldorei/partials/site_stat.hbs

7.1.5 在博客文章中显示作者信息

kaldorei主题并没有特别强调多作者博客的功能,所以它的文章(post)中只显示标签云,而不显示该文章的作者信息。因此我添加了这一功能,但需要做的修改极少:

<!-- modify file at ./ghost-theme-kaldorei/partials/sidebar.hbs -->
<!-- 注意在下面位置的is标签后面,多添加一个post参数,就可以了 -->
    {{! 作者:显示作者信息 }}
    {{#is "author, post"}}

关于多作者博客的支持,我打算另开一篇博文来讲。

^^.

7.1.6 修改语法高亮

在default.hbs中载入新的highlight style即可:

<!-- kaldorei的缺省风格是monokai-sublime.css, 在styles目录下找个新的换上就Ok -->
<!-- 可以先查看https://highlightjs.org/static/demo/来选择风格 -->
<link rel="stylesheet" type="text/css" href="{{asset "plugins/highlight-9.1.0/styles/xcode.css"}}" />

此外,你可能需要调整高亮代码左侧的行号背景(或其它),那么应修改如下样式表:

/* modify file at ./ghost-theme-kaldorei/assets/css/screen.css */
.pre-numbering {
    position: absolute;
    ...
}

.pre-numbering li {
    ...
}

7.1.7 指定文章置顶

置顶文章是常见的博客操作,你可以将一篇文章设置为featured,并且通过修改模板来使它们置顶。这会涉及到不少的修改。

好在所谓『置顶』操作其实只会发生在带有(列表)list性质的页面中,这类页面在Ghost中称为paged,它只出现在以下三类页面上:index, tag and author(参见这里)。在这三类页面中,可以用loop模板去列举所有页,但它们的第1页是paged为false的,而之后的第2..n页则是paged为true的。可以通过这种区别来将你需要的内容置顶,并在其它页面中筛除它们。

在具体实现中,由于{{get}}标记在filter设置时不能使用包含或查找操作(它能使用的运算支持在这里),所以tag页不能用index/author页相同的方法来实现置顶。然而此外唯一可能做这个运算的{{has}}标记却不支持参数传入——所以,你已经知道结果了:在tag页中不支持(按标签分类过的)置顶。

<!-- 在loop.hbs中用以下代码分别载入置顶风格的posts -->
{{^is "paged"}}
    {{! list all feated posts on top }}
    {{#is "index"}}
    {{#get "posts" filter="featured:true" limit="all" include="tags" as |featured|}}
    {{#foreach featured}}
        {{> content_featured}}
    {{/foreach}}
    {{/get}}
    {{/is}}

    {{#is "author"}}
    {{#get "posts" filter="featured:true+author:{{author.slug}}" limit="all" include="tags" as |featured|}}
    {{#foreach featured}}
        {{> content_featured}}
    {{/foreach}}
    {{/get}}
    {{/is}}
{{/is}}

<!-- 紧接着载入普通风格的posts -->
    {{#foreach posts}}
    {{#is "tag"}}
        {{> content_post}}
    {{else}}
        {{#unless featured}}
        {{> content_post}}
    	{{/unless}}
    {{/is}}
    {{/foreach}}

然后在partials/content_featured.hbspartials/content_post.hbs中分别设置两种样式即可。——可以将原来在loop.hbs中foreach posts的代码块直接接到partials/content_post.hbs中。

最后,一些细节可以参考这里:Move Featured Posts to the Top of your Blog

7.2 将站点信息与云标签静态化

Ghost博客静态化有一个小的问题,就是如果你加上了类似『站点状态(site_stat)』或『标签云(tag_cloud)』这样的功能的话,那么你几乎每添加或修改一篇文章,就要全部重新生成静态页,然后再重新Push到github仓库——每次都全站发布一回。

原因是这样,比如说你的site_stat里有一个『站点发表了多少篇文章』的计数,那么,显然你添加/删除一篇博客,就得让所有静态面这个位置的计数变一下;又例如标签名,你添加一个标签那么全站所有页的标签云都要动态生成一下。

而事实上——99%的博客文章或静态页面在内容上都没有什么变化 。所以,能不能将这些动态变化的信息静态化掉,不至于每次都要重新生成?

是能的。我采用的策略是:用js装载这些静态化的信息。

7.2.1 为标签云添加一个静态页

在博客后台添加一篇新的博客,将它的页面url设置成tag_cloud,并配配置它为静态页面(参见『历史归档』的做法,在这里)。这一篇博客的内容可以为空。

然后在content/themes/ghost-theme-kaldorei/目录下新添加一个名为page-tag-cloud.hbs的模板——它将是上面这篇文章的专用模板,Ghost是通过文件名来识别的。内容如下:

document.writeln(function cloudTagHtmlContext() {/*
  {{> "tag_cloud"}}
*/}.toString().replace(/^[^\*]+\*+|\*+[^\*]+$/g, ''));

注意,这是一段标准的JavaScript代码,并且事实上只有一行:

document.writeln(...);

当Ghost将在后台把page-tag-cloud.hbs当成标准的模板文件来处理,所以它会填充其中的Ghost标志,并装载子模板页。而生成出来的静态页实际上是一个.js的文本文件,并且放在(我们在对应博客文章后台配置的)/tag_cloud这个位置上——不过没有扩展名而已。

这段脚本的作用仅仅是将cloudTagHtmlContext()这个函数(也可以是匿名函数)中的内容取出来,然后写在网页上。

这段代码总是通用的,可以用来将任意模板/网页转换成这样一个脚本文件,以便于动态装载。

7.2.2 修改其它模板以装入上述脚本

这很简单,在sitebar.hbs这个文件中找到{{> "tag_cloud"}},然后替换成下面的即可:

<!-- modify file at ./ghost-theme-kaldorei/partials/sidebar.hbs -->
<!-- 找到{{> "tag_cloud"}}然后替换成下面的脚本 -->
<script type="text/javascript" src="/tag-cloud"></script>

7.2.3 关于site_stat

与tag_cloud的处理类似,我添加了/profile_site静态页,并且添加模板如下:

// file at ghost-theme-kaldorei/page-profile-site.hbs
document.writeln(function cloudTagHtmlContext() {/*
    <hr> {{> "site_stat"}}
    <hr> {{> "social"}}
*/}.toString().replace(/^[^\*]+\*+|\*+[^\*]+$/g, ''));

同样,最后你需要改一下partials/profile.hbs相应位置来装载/profile_site这个脚本文件。

7.3 其它

事实上我现在仍然是采用每次都全站生成静态页面来更新整个网站,因此上面的有关『静态化』的处理并不能带来直接的便利。但我的确打算发布一个『只更新最新内容』的小工具,这样网站Online就会变得快些了。

2017.09.30 已经可以使用Monster的增量发布功能了,并且Monster专门增加了对静态化页面的支持。参见这里(Monster - 用Ghost写博客的终极利器),或这里(Monster's github)。

不同的主题的修改会略有区别,本文只供参考。