---

date: 2024-05-31T19:30:46Z

update: 2024-06-30T03:39:51Z

---

tilde30, June 1-30 2024

Tilde 30 is a event that involves picking a project or series of related activities and doing them over the course of thirty days. The main premise is to set weekly milestones or goals to complete them. More details:

tilde30.txt

Townies can also see a list of what people will be doing in the "tilde30!" thread on bbj, the town bulletin board. Thanks to ~elly for organising the event.

Project

My tilde30 mini-project will be a static gallery gemerator. Given a folder of images and metadata text files, write a CLI utility to generate static pages for a simple web gallery.

Milestones

Week 1: learn enough of a programming language to make mischief

Week 2: model config settings, parse sample config and image information

Week 3: write logic to source thumbnails, generate HTML from a template

Week 4: template sample gallery theme

Stretch goal: add HTML/CSS to the forforthcoming stats feature in Katalogo. Katalogo is a webring server by ~durrendal. Timing will depend on feature progress and remaining time. Templating can be done more effectively when the backend returns the sample data to be displayed.

Katalogo

Background

When last checked several years ago, most web gallery generators were either written in PHP, content management systems that handled embedding multimedia, or application servers that would not be easily made publicly accessible outside of ~town. Static HTML pages were less resource-intensive and could adequately display small image collections. The closest static site generators with a gallery component were Sigal and Nikola. Sigal was centered around generating gallery pages and image thumbnails, configuration and theming were straightforward, though it did not handle adding other pages that were not part of a gallery. Nikola had a gallery view alongside regular pages and other features, but the image lightbox view did not support multi-paragraph captions. My fix at the time was to combine the gallery built through Sigal with a shell script to output extra text-only pages, both sharing the same HTML theme. The arrangement worked, if clunkily.

Sigal — Simple Static Gallery Generator

Nikola — Static Site Generator

One or two months ago, someone asked in ~town chat if there was a gallery generator installed. By then had written a single-page generator that could serve as a gallery feature or subsite, but the idea of producing the gallery applet that should have existed years ago lingered. In twenty-nine days, the folly of this idea will be revealed.

znic: 1-page webzine generator

Update 2024-06-23: found imgram, a shell script HTML gallery generator while browsing a cluster of websites adjacent to the Old Computer Challenge gateway. It is closer to an imageboard without comments, having a Tumblr-like layout with support for tags and pagination. The author, prahou, kindly pointed me to the source (link below). A good option with a RSS feed.

imgram

Old Computer Challenge

Timeline

The sections below will be updated through the month.

Start: 2024-06-01

Week 1: 2024-06-08

Week 2: 2024-06-15

Week 3: 2024-06-22

Week 4: 2024-06-29

End: 2024-06-30

Updates

Day 0

t30.nim

Start / Day 1

# Check Helix's language server detection and grammar support.
# Enable Go in the use-grammars list in ~/.config/helix/languages.toml.
hx --health go
hx --grammar fetch
hx --grammar build

# Install Go compiler and language server.
apk add go gopls

Go by Example

Screenshot of the Helix editor with two vertical panes, the left containing sample code and a gopls tooltip about the `Println()` function spanning both panes, and a gemtext file open on the right

Week 1

1. Maximum size: images are the maximum size at the longer side. An image in landscape would be 200px in width and less in height, and an image in portrait a height of 200px, less in width. A square image would have a width and height of 200px.

2. Minimum size: images are the minimum size at the shorter side. An image in landscape would be 100px in height and more in width, and an image in portrait a width of 100px, more in height. A square image would have a width and height of 100px.

3. Width: images have the same width. An image in landscape would be 200px wide, less in height, and an image in portrait would be 200px wide, more in height. A square image would have a width and height of 200px.

4. Height: images have the same height. An image in landscape would be 100px high and wider than 100px, and an image in portrait would be 100px high, and narrower than 100px. A square image would have a width and height of 100px.

5. None: images are sized at a percentage of the original image regardless of set width and height. The current default is 50% of the original image dimensions, e.g. a 600 x 800px source image yields a new 300 x 400px image.

A plain HTML page with 2 rows of 6 square thumbnails resized from illustrations

Lesson recap:

Advantages to JSON as []byte instead of string

1. Unsorted: the spec does not include sorted maps as a requirement to allow for different types of maps in implementation. Avoid using maps alone for menus or scenarios where the elements' order of appearance is important. Use with a slice if needing a sorted collection.

2. Not concurrency-safe on its own: use with a synchronisation library to read and write to them at the same time.

Go maps in action

image/draw (standard library)

golang.org/x/image/draw

# Generate a go.mod file.
go mod init [module]

# Fetch the package.
go get golang.org/x/image/draw

# Add import path to source.
import "golang.org/x/image/draw"

1. Variadic arguments (`func foo(param ...string)` syntax), which allow for empty slices including not passing a value. Depending on use case, it can act like an optional parameter and is fine as long as the function only acts on the same number of elements as present in the slice. It may yield unexpected results (additional elements are ignored) or leave cruft unchecked if more elements are passed in than the function handles, as the compiler would not warn of a mismatch.

2. Place default values in a struct and convert the function to a method on the struct.

3. Pass in a placeholder value and reset it to a default value inside the function.

4. Write function variants for different sets of arguments.

Default value in Go's method

Proposal: add limits to variadic definition

Why does Go not support overloading of methods and operators?

golang/go os: add CopyFS

3 ways to copy files in Go

Week 2

1. `image`: functions for calculating image crop size and resizing.

2. `template`: functions to generate gallery pages.

3. `util`: a mix of supplementary functions unavailable in the standard library, e.g. multiple substring replacement for strings, boilerplate for copying files, sorted file lists.

A plain HTML page with two sets of image thumbnails

Lesson recap:

strings.Title (deprecated)

cases.Title

`# command-line-arguments ./main.go:8:2: undefined: [function]`, change the run command to include all Go files in the current directory: `go run . [args]`

Week 3

A page with the image set title and description at the top, followed by 3 rows of 4 thumbnails centered on the page

Same page showing a lightbox view, with a translucent white layer over the visible area and a larger image of a paper tilde on top, the title and short 1-line description below the image

Lesson recap:

cmd/vet: don't complain about int to string conversion

How to convert an int value to string

Week 4

1. CSS styles not copied when the `make` option is invoked the first time.

2. Top-level index.html being output to the source directory top-level when the config value is empty.

3. Runtime error when there is only one image in a set. Also hid the lightbox navigation links in this case.

4. Check for duplicate index page results in the index page being renamed when the set page has a description file.

5. Image descriptions not displayed after adjusting the description file path check.

Lesson recap:

embed: remove support for embedding directives on local variables

Bundling static resources

embed package

1. Variables cannot be used in the `//go:embed` directive. Oddly, the linter did not notify of an error.

# Incorrect example.
//go:embed filepath.Join(SampleThemeDir, "*")

# Error on compile.
template/template.go:196:3: invalid quoted string in //go:embed: )
template/template.go:196:3: usage: //go:embed pattern...

# Corrected example.
//go:embed themes/nettle/*

2. The path is relative to the package root directory. If the directive is invoked from a subdirectory and the files are in another adjacent subdirectory, either move the files to a location inside the same subdirectory, or create a `config.go` file and embed the files from there.

How to Use //go:embed to embed static files in CLI

End

Source repo

Project demo page

Problems with fetching repos via ssh after updated from 16.1.5 to 16.3.3