Introduction

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.

Table of content


Managing my Neocities Website

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.

Starting with a template

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

Filling automatically your template

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.

Using Automated Tools

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:

  1. Template pages and Layout: Within Jekyll, you need to create “layout pages”. This are template pages which after compilation would place the markdown content to the right place. To use your HTML template, you need to combine them together
  2. Learning the directory structure: When starting coding, for me everything needed to be flat, i.e. all the material within the same folder. However, after some time, it becomes a big mess. Then, I saw that many people use standard names like 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.
  3. Using the yaml metadata to enrich pages.
  4. Understanding 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.
  5. Using CLI to update your website.

Jekyll

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

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.

Filtering by Categories

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.

Filtering by tags

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.

Listing your Posts

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:

  • The first one give you an overview of the blog:
    • Title
    • Short description (in my yaml header)
    • An image
    • The list of the tags.
  • The second is about pagination. Here, let the magic happen.

NB: you need to restart jekyll, otherwise it won’t create the pagination

You can create multiple blog lister, filtering other categories.


CLI

I decided to build my own CLI for several reasons:

  • neocities GUI has some bugs (drop down nested folders and you will see the result).
  • neocities CLI is incomplete (no option for filtering stuff, missing function) (Link to the official CLI)

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.

» Source Code on GitHub «

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:

  • Add the post in its folder project/yyyy/mm/dd/my_project_x.html
  • Add the images in the image folder image/my_project_x/
  • Update the blog listing pages blg_proj/index.html and all the others

Adding the Post

To push the post, I have two options:

  • I can only add the single file.
  • I push all the post folder

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

Adding the Images

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

Adding the blog lister

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.