In this post, I present the different tools I used to create and manage my website. Now, my current setup is Jekyll + my custom CLI, which allows me to convert simple markdown pages into nice html pages.
Programming is not innate. You don’t know when you start what are the wonderful libraries that would let you save time.
The first thing I known is that I am not a front-end developer. I have knowledge in algorithmic, but none on website development. I know basic stuff about HTML, which are just enough to start with.
So, I start by searching an HTML template that fit my taste. I searched for a free one on the web, and got this one.
You can search your own there:
Be careful with the license: free doesn’t mean you can do anything you want with.
Now, you need to custom it a little bit, changing colors, columns location, fonts, …
You cannot fill by hand each page, link to all images without error. So I used pandoc to compile markdown pages into HTML pages. This was okay for building independent pages, but not to link them together.
A few month ago, I wanted to upgrade my website, to have “blog features” like a set of linked pages which display articles header. My current company has a technical blog which used Jekyll to generate pages. It is very hard to start with when there is an existing codebase. But starting from scratch with it, it was very easy.
You cannot migrate your website in one shot, but progressively by learning how to use the different features:
lib
, src
, img
, etc. But how do you know which one you need to select ? Jekyll has a directory structure that help you to get everything organized.post
: Your website might be a bunch of page that you update periodically. Or it could be a blog where you add new pages every weeks. The best option is to store the pages into the _post
folder, where jekyll will take care of it.Jekyll is a tool that allows to transform easy-to-write markdown files into HTML pages. Additionally, it allows to run your website locally, so you can see the direct result.
To start with, I recommand to test their examples to understand how it works progressively.
I won’t detail the basic exemples, but some more advanced that are less documented on the web. (Their documentation is a good start, but you may like additional examples).
Posts are particular markdown files located in _post/
with the syntax yyyy-mm-dd-Whatever_name_you_like.md
.
You can custom this format, however it is good enough to start with.
In the yaml
header, you need to specify the category.
For instance category: foo
would lead to the creation into _site/
of _site/foo/yyyy/mm/dd/Whatever_name_you_like.html
If you do not want them to be published yet, write them into _draft/
folder. They won’t be transformed into html.
categories
and category
are reserved names.
On a post, you can set one category
layout: project_page
title: This is a test page.
category: projects
tags:
- tag number 1
- other tag
- last tag
You may want to list all items related to it.
In another page, using the Liquid syntax:
---
tag: project
---
<ul>
{% for post in site.posts %}
{% if post.categories contains page.tag %}
<a href="{{ post.url }}">{{ post.title }}</a>
{% endif %}
{% endfor %}
</ul>
Note that it could be page.tag
, but I could also rename tag: project
into filter_keyword: project
and search for page.filter_keyword
.
When you write a post, you can often classify it into many topics, so it is hard to choose a single one. Instead, you could add into your metadata a list of tags that best describe your page.
Here, I propose an example to list within a single page all posts with a particular tag in.
Suppose you have a blog post where you set in the yaml header:
tags:
- web
- programming
- blog
Then, on a regular page, you can list all the post about a particular topic.
---
tagx: programming
---
List of post with "{{ page.tagx }}" included:
<ul>
{% for post in site.posts %}
{% if post.tags contains page.tagx %}
<a href="{{ post.url }}">{{ post.title }}</a>
{% endif %}
{% endfor %}
</ul>
Here I names tagx
the tag to find, to show the difference with tags
which is a list.
In many blogs, you have some pages where you can preview 5 post at a time, with a clic button to go to the next page or the previous one, listing other blog articles. Here, I show you how to create automatically this n-linked page structure.
This is hard to setup, you need some time to fix the mistakes. See the official documentation for more info.
First, in the _config.yml
, you need to configure the behavior:
plugins:
- jekyll-paginate-v2
url: "" # the base hostname & protocol for your site, e.g. http://example.com
baseurl: "" # the subpath of your site, e.g. /blog
pagination:
enabled: true
per_page: 6
permalink: '/page:num/'
sort_reverse: true
You need of course to install jekyll-paginate-v2
.
This config does not create anything for the moment.
In the root directory, you need to instantiate the location of these blogposts listers.
So I added one: mkdir blg_project/
Plus, you need to add an HTML file to say what you want in.
vim blg_project/index.html
And set the minimal instructions:
---
layout: main_page
title: All projects
pagination:
enabled: true
category: projects
per_page: 5
---
{% for post in paginator.posts %}
<h1><a href="{{ post.url }}">{{ post.title }}</a></h1>
{% if post.description %}
<p>
{{ post.description }}
</p>
{% endif %}
<p class="author">
<span class="date">{{ post.date | date: "%a, %b %d, %y"}}</span>
</p>
{% if post.main_image %}
<img src="{{ post.main_image }}" >
{% endif %}
<p>
Categories: {{ post.categories}}
</p>
<p>
Tags:
<ul>
{% for tag in post.tags %}
<li> {{ tag }} </li>
{% endfor %}
</ul>
</p>
{% endfor %}
<!-- Pagination links -->
<div class="pagination">
{% if paginator.previous_page %}
<a href="{{ paginator.previous_page_path }}" class="previous">
Previous
</a>
{% else %}
<span class="previous">Previous</span>
{% endif %}
<span class="page_number ">
Page: {{ paginator.page }} of {{ paginator.total_pages }}
</span>
{% if paginator.next_page %}
<a href="{{ paginator.next_page_path }}" class="next">Next</a>
{% else %}
<span class="next ">Next</span>
{% endif %}
</div>
In the yaml section, you can overide the _config.yml
default parameters.
I asked to select only the post within the project
category. I could select all post also.
You can see that there are two blocks:
NB: you need to restart jekyll, otherwise it won’t create the pagination
You can create multiple blog lister, filtering other categories.
I decided to build my own CLI for several reasons:
As the official CLI was written in Ruby, and I don’t want to learn about because of a lack of time and it is unlikely that I would use this language professionnally, I decided to write a new one using python.
You have the documentation on GitHub.
It doesn’t require any particular libraries, and you don’t need to do any lib installation.
It is limited to Linux only (I use /
and not \
), but you can upgrade it to be platform agnostic.
The basic function I needed is to push one folder on a particular location.
When I create a post, I needed to update 3 things:
project/yyyy/mm/dd/my_project_x.html
image/my_project_x/
blg_proj/index.html
and all the othersTo push the post, I have two options:
As we have html pages (without the img), it is not too heavy, so we can add everything in one shot.
./neocities update project/ --rec
, which would uplad everything to the root of the website.
If I want to add only this file, I need to set the path.
./neocities update project/yyyy/mm/dd/my_project_x.html --remote_path="project/yyyy/mm/dd/"
Last option is to only update this month (if you push multiple articles at a time).
./neocities update project/yyyy/mm/ --rec --remote_path="project/yyyy/mm/"
This is not different from previous methods.
./neocities update IMG/*.jpg --remote_path="images/my_project_x/"
which is equivalent to
./neocities update IMG/ --rec --remote_path="images/my_project_x/"
I will endup with
images/my_project_x/img1.jpg
images/my_project_x/img2.jpg
images/my_project_x/img3.jpg
Locally, I have:
blg_project/
blg_project/index.html
blg_project/blg/
blg_project/blg/page2/
blg_project/blg/page2/index.html
blg_project/blg/page3/
blg_project/blg/page3/index.html
./neocities update blg_project/ --rec"
Would push this project to the root.
NB: this is very different from ./neocities update blg_project/* --rec"
, which would remove one layer and put all the content of blg_project/
to the root.