This is the inaugural post to this blog. Specifically, this post documents setting up this blog.
Requirements
My requirements were:
- Professional appearance and quality user experience
- Deploy-able with Ansible
- Minimize the application “native” data
- Prefer configuration stored in “source” format within source control
- Custom theme
- Emphasis on code
- Allow import of articles written external to the application (which will also be managed within source control)
After some investigation, I settled on Ghost. The next section details the strategy for responding to these requirements.
Strategy
Ghost now provides Ghost CLI which we’ll ultimately combine with Ansible for deployment.
The custom theme will integrate Bootstrap and Prism (for code highlighting).
Development Instance
The Ghost directions are straightforward. Ghost is not supported with the latest version of node.js so in a macOS environment managed with Homebrew a supported version must be found on the path.
$ mkdir ghost
$ cd ghost
$ env PATH=$(brew --prefix node@8)/bin:$PATH ghost install local
$ env PATH=$(brew --prefix node@8)/bin:$PATH ghost restart --development
That wisdom is captured in the following Makefile
.
# ghost.mk
MAKEFILE=$(lastword $(MAKEFILE_LIST))
DIRECTORY=$(basename $(MAKEFILE))
export PATH:=$(shell brew --prefix node@8)/bin:${PATH}
$(DIRECTORY):
mkdir $@
cd $@; ghost install --local --no-start
start restart: $(DIRECTORY)
cd $<; ghost $@ --development
stop: $(DIRECTORY)
cd $<; ghost $@
# Local Variables:
# compile-command: "make -f ghost.mk "
# End:
The instance will be served locally @ http://localhost:2368/ with the administration interface @ http://localhost:2368/ghost/. Upon initial start-up, the administration screen will present a dialog for initial configuration which should be completed. In addition, general settings should be configured.
Also available on the administration page menu is the Labs option which provides two important features:
From the “ghost” directory, use:
$ env PATH=$(brew --prefix node@8)/bin:$PATH ghost stop
to stop the instance (or the corresponding “stop” target in ghost.mk
).
Creating the Theme
When the server is started with --development
, theme content may be added
directory to content/themes
. For example, to start this blog’s theme:
$ git clone https://github.com/TryGhost/Casper.git blog-ghost-theme
And then edit the package.json
file within the directory updating the
name, description, and version fields. Restart the server so the newly
created theme is available on the
Design menu option.
{
"name": "blog-ghost-theme",
"version": "1.0.0",
"author": {
"name": "Allen D. Ball",
"email": "ball@iprotium.com"
}
}
The theme may be activated by clicking on the corresponding Activate
link.
Ghost provides links to helpful documentation for any errors identified.
Bootstrap and Prism Integration
Bootstrap dependencies were added to the package.json
file along with
scripts to deploy to the assets/
hierarchy.
{
"name": "blog-ghost-theme",
"version": "1.0.0",
"author": {
"name": "Allen D. Ball",
"email": "ball@iprotium.com"
},
"dependencies": {
"bootstrap": "^4.1.3",
"jquery": "^3.3.1",
"popper.js": "^1.14.4",
"vendor-copy": "^2.0.0"
},
"scripts": {
"clean": "rm -rf node_modules",
"postinstall": "vendor-copy"
},
"vendorCopy": [
{
"from": "node_modules/bootstrap/dist/css/bootstrap.css",
"to": "assets/css/bootstrap.css"
},
{
"from": "node_modules/bootstrap/dist/js/bootstrap.js",
"to": "assets/js/bootstrap.js"
},
{
"from": "node_modules/popper.js/dist/popper.js",
"to": "assets/js/popper.js"
},
{
"from": "node_modules/jquery/dist/jquery.js",
"to": "assets/js/jquery.js"
}
]
}
Prism was configured and downloaded from https://prismjs.com/download.html
directly into the assets
hierarchy.
The text/css
links are included in partials/meta-css.hbs
:
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="stylesheet" type="text/css" href="{{asset "css/bootstrap.css"}}"/>
<link rel="stylesheet" type="text/css" href="{{asset "css/prism.css"}}"/>
<link rel="stylesheet" type="text/css" href="{{asset "css/style.css"}}"/>
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
And the <script/>
directives are included in partials/javascript.hbs
:
<script type="text/javascript" src="{{asset "js/jquery.js"}}"></script>
<script type="text/javascript" src="{{asset "js/popper.js"}}"></script>
<script type="text/javascript" src="{{asset "js/bootstrap.js"}}"></script>
<script type="text/javascript" src="{{asset "js/prism.js"}}"></script>
All integrated into default.hbs
:
<!DOCTYPE html>
<html lang="{{lang}}">
<head>
{{> meta-css}}
{{ghost_head}}
</head>
<body class="{{body_class}}">
{{> header}}
<div class="container">
{{{body}}}
</div>
{{> javascript}}
{{ghost_foot}}
</body>
</html>
where the previous two files are included via the
{{> meta-css}}
and
{{> javascript}}
directives and the Ghost-rendered
output is placed within a Bootstrap-configured
<div class="container">...</div>
. partials/header.hbs
is also included
through the {{> header}}
directive and provides a
Bootstrap 4 “fixed-top” navbar
. Some details of that implementation are
described in the next section.
Bootstrap navbar
The theme provides a navbar
that is always fixed to the top of the page.
The Bootstrap 4 class names are given in partials/header.hbs
:
<nav class="navbar navbar-dark fixed-top bg-dark">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="{{@blog.url}}">{{@blog.title}}</a>
</div>
</div>
</nav>
However, as configured the navbar
will cover content. This may be
addressed within assets/css/style.css
:
body {
padding-top: 60px;
}
@media (max-width: 979px) {
body {
padding-top: 0px;
}
}
Next Steps
Deploy a production Ghost server (to be covered in a future post).