Hugo and Neocities

01/03/19

Last modified on 12/12/19

Categories: Development Projects Tags: Neocities Hugo

~/contents

NeoCities provides free hosting for static sites, which introduced me to the concept of static site generators. Having run a few Wordpress sites in the past, I appreciate how much static site generators streamline a website and it has become my preference. The markdown files used for blog posts and these are easily migrated between generators, so trying different generators out is trivial.

Initially I used Jekyll, but the setup felt kind of messy and the site kept taking longer to generate even though it wasn’t that large. I switched to Hexo, which was much faster, and then moved to Hugo because it had a site template I liked and was comparably fast.

I use Chocolatey for Windows package management.

choco install hugo -confirm
choco upgrade hugo -confirm

The NeoCities upload dashboard is intentionally basic, users are encouraged to develop their own tools for deployment. I use soulshake’s NeoCities Python API. I noticed recently neoslaughter was working on adding a push method for recursive directory uploading. It does not currently work as-is so I lifted the code and incorporated it into my upload script.

#! python3
import neocities
from glob import glob
import os

USERNAME = "user name"
PASSWORD = "password"
LOCAL_DIRECTORY = "public" # Hugo generates the site in the public directory

file_extensions = [
    '.html','.htm',
    '.jpg','.png','.gif','.svg','.ico',
    '.js','.json','.css','.txt','.csv','.xml',
    '.eot','.ttf','.woff','.woff2']

def push(d):
    ''' recursive directory upload, adapted from https://github.com/neoslaughter/python-neo '''
    files = glob(d + '/**', recursive=True)
    for file_name in files:
        if os.path.splitext(file_name)[1] in file_extensions:
            destination_path = file_name.replace(LOCAL_DIRECTORY,'').replace("\\","/")
            nc.upload((file_name, destination_path))
            print("Uploaded {} as {}".format(file_name, destination_path))

nc = neocities.NeoCities(USERNAME, PASSWORD)
push(LOCAL_DIRECTORY)

The Windows command line workflow is pretty straight-forward. Hugo does not have a clean flag like Hexo, so you must delete the old directory with rmdir.

C:\Hugo\Sites\neocities>rmdir /S public | delete existing public folder, Windows asks for confirmation
C:\Hugo\Sites\neocities>hugo  | generate latest version of site in public directory
C:\Hugo\Sites\neocities>hugo server | test site
C:\Hugo\Sites\neocities>python site_push.py | push site to NeoCities

Site Workflow

Updated 12/11/19
I realized I would update the site more if I had a better workflow, then documented the workflow so I won’t forget it when I invariably ignore the site for 6 months.

I use Atom as my editor with the plugins:
- markdown-preview
- markdown-writer
- tool-bar-markdown-writer
- run-in-terminal
- language-hugo

The tool bar is most useful to me for the New Post button. F9 pulls up the terminal, and from there I navigate where I need to for Hugo, etc. markdown-writer has a tag/category/post management feature that relies on a .json listing all those items. The .json is linked by updating _mdwriter.cson. I’m using a temporary .json handcrafted in the fires of Mt. Doom but ideally a Hugo template does the work for us.

When I decided to try microblogging I added a second set of markdown files in a folder called “notes” and created a unique list template that lists the date, title, and full content (unlike the project blog list, which lists the title, categories, and tags). The benefit of this method is the microblog posts will be easy to migrate or combine if needed.

I decided (and I hope I’m right) that so-called “ugly” URLs would be easier to manage with Neocities limited dashboard. Using the dashboard, if I wanted to delete a section of “pretty” posts that each have their own subfolder I would have to enter the subfolder, delete the index.html file, then delete the folder itself. Hugo will generate pages this way with the following config parameter:

uglyurls = true

Emojis

After adding emoji support and moods on my personal blog, I found I was constantly having to check the emoji reference page or my directories to see what emoji to use. The autocomplete-emojis plugin eliminates the need to use the reference sheet.

Tag and Category Clouds

Added 10/15/19
I was able to add nice taxonomy clouds thanks to Brian Phyre’s tag cloud post.

<div class="cat-cloud">
   {{ $cats := $.Site.Taxonomies.categories.Alphabetical }}
   {{ $cats := where $cats "Count" ">=" 1 }}
   {{ $cats := where $cats "Term" "not in" (slice "personal") }}
   {{ $count := 0 }}
   {{ range $key, $cat := $cats }}
     {{ if $cat.Term }}
       {{ $catURL := printf "categories/%s" $cat.Term | relURL }}
       {{ if ne $key 0}} {{ end }}
       <a style="font-size: {{ add 100 (mul (sub $cat.Count 8) 2) }}%;"
         href="{{ $catURL }}">{{ $cat.Term }} <span class="cat-cloud-count">{{$cat.Count}}</span></a>
     {{ end }}
   {{ end }}
 </div>

<div class="tag-cloud">
   {{ $tags := $.Site.Taxonomies.tags.Alphabetical }}
   {{ $tags := where $tags "Count" ">=" 3 }}
   {{ $tags := where $tags "Term" "not in" (slice "tags") }}
   {{ $count := 0 }}
   {{ range $key, $tag := $tags }}
     {{ if $tag.Term }}
       {{ $tagURL := printf "tags/%s" $tag.Term | relURL }}
       {{ if ne $key 0}} {{ end }}
       <a style="font-size: {{ add 100 (mul (sub $tag.Count 8) 5) }}%;"
         href="{{ $tagURL }}">{{ $tag.Term }} <span class="tag-cloud-count">{{$tag.Count}}</span></a>
     {{ end }}
   {{ end }}
 </div>

Chronological Archives

Using year/month taxonomies per onedrawingperday’s example, see Content Archives in Hugo.

Image Management

atom-markdown-image-assistant allows you to copy-paste into your markdown file, and it automatically saves the image in a directory and provides a link. As I use ugly urls I prefer to have all my images in an images/ folder rather than individual folders. Additionally, imagemin can be used to minify .pngs on the fly.
- markdown-image-assistant
- imagemin
- image-resize

I quickly ran into issues with image/url paths since mine are custom. Hugo actually ends up putting the images in the microblog home directory, which is actually great for me, but of course the auto-links are for the relative path. Adding the correct home directory to the front of the image link is not a big deal, and the way my content is organized this works out well.

Image Galleries

I wanted to create photo albums without using existing silos and figured out I could use a static gallery generator and host those on Neocities as well. Sigal was ridiculously easy to set up, so that’s the one I went with. It’s still a work in progress.
http://sigal.saimon.org
http://exifpurge.com/
https://github.com/liwenyip/hugo-easy-gallery

Inspoboards & Moodboards

Added 11/08/19
I’ve been looking into making inspoboards. I was introduced to these on Tumblr and they flourish there but Tumblr, by its nature, imposes limitations on the concept. I decided I wanted to be able to create responsive grids that incorporate all kinds of different images. The inspoboards are different from photo galleries because it’s supposed to be an immersive, continuous space, the images are part of a whole rather than individuals.

You can accomplish a great deal with Javascript, but Chris Coyier’s Seamless Responsive Photo Grid is a pure CSS method that is simple and does exactly what I want. You simply put a list of images in a section tag.

With this method you need to manually list all the images. It would be nice if I could just drop photos in a directory and generate a page, but I have a html template now so the main thing is getting all those file names into image tags. There are several cmd commands that can pull filenames from a directory, for instance see MatthewA’s How to easily copy all names of files in a folder in Windows, but I found user Marged on Stackoverflow has a great method for grabbing all the images in a directory and wrapping them in HTML img tags.

for %i in (*.jpg) do echo ^<img src="%i" /^> >> all.html

Easy peasy, just copypasta and you’re done. To see a different implemenation, check out cyber rot.