Skip to content

Commit

Permalink
migrate to hugo + blowfish
Browse files Browse the repository at this point in the history
  • Loading branch information
danvolchek committed Nov 12, 2023
1 parent 87d85c9 commit 6b6f70e
Show file tree
Hide file tree
Showing 122 changed files with 9,598 additions and 11,454 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "themes/blowfish"]
path = themes/blowfish
url = https://github.com/nunocoracao/blowfish.git
branch = main
Empty file added .hugo_build.lock
Empty file.
59 changes: 20 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,33 @@

Source code for [https://danvolchek.com](https://danvolchek.com).

Holds details about me and my projects.
It holds links, details about projects I've worked on, and a blog for longer form thoughts.

It's a static website that's generated by a simple custom static site generator.
It's a static website that's generated by a static site generator.

## Static site generation
## Overview

Generation happens in two stages:
It uses:
* [Hugo](https://gohugo.io) as a template engine
* [Blowfish](https://blowfish.page) as the theme
* [Github pages](https://pages.github.com/) to host the content
* [Google Domains](https://domains.google.com) for the custom domain name

1. Load data to be displayed on the website
2. Generate HTML from the data
Before this stack, I used a website generator [I wrote myself](https://github.com/danvolchek/personal-website/tree/87d85c92cd4acd9c963902d6832403147ebc2994) that's remarkably similar in idea: take markdown files and generate a static website. I switched to hugo + blowfish because it looks better.

The process centers around "content fillers", or components that know how to retrieve data and then display it.
There's one for every logical unit of replacement:
- Projects
- Stardew Valley mods
- Pico-8 carts
I've added some customizations on top of blowfish:
* Copying code blocks works regardless of the `highlight.noClasses` setting, allowing for custom code block syntax highlighting.
* The home page shows recent articles in multiple sections, with configurable settings like taxonomy and display style per section.
* The color scheme is custom.

Each content filler follows similar steps:
## Build/run

1. Load data from YAML files
1. Augment data as necessary
- The projects filler parses project descriptions from markdown
- The Stardew Valley filler downloads current mod usage statistics
- The Pico-8 filler retrieves carts compiled to HTML so they can be played
1. Transform the data into HTML
1. Provide new HTML nodes to the HTML replacer

The HTML replacer handles inserting the generated HTML in the right places in the document. It's based on the idea of
replacing placeholder elements with real content.

The replacer follows these steps:

1. Loads a base HTML file to start from
1. Using "content ids" from the fillers, searches for corresponding `data-content="id"` tags on placeholder elements in the HTML
1. When found, replaces the content of the placeholder elements with the output from the fillers, and removes the tag
1. Writes a new HTML file after all placeholder elements have been replaced

Generated HTML from the fillers can itself hold placeholder elements. This allows for the projects filler to contain layout
for all projects, including where the stardew filler should place it's generated mods list. Nifty!

The generator script should be run with a working directory of the root of the repo:
```shell script
go run generate.go
To run the development server:
```
hugo server
```

The site can be previewed by running the preview script (also with a working directory of the root of the repo):
```shell script
go run preview.go
To build a new version:
```
hugo
```
12 changes: 12 additions & 0 deletions archetypes/default/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: '{{ replace .File.ContentBaseName "-" " " | title }}'
summary: Summary here, shown in various places.
description: Description here, copy the summary.
date: {{ .Date.Format "2006-02-1" }}
#series: []
#series_order: 0
#tags: []
draft: true
---

TODO
18 changes: 18 additions & 0 deletions archetypes/projects/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: '{{ replace .File.ContentBaseName "-" " " | title }}'
summary: Summary here, shown in various places.
description: Description here, copy the summary.
date: {{ time.Format "2006-02-1" .Date }}
#series: []
#series_order: 0
#tags: []
draft: true
---

## Repo

{{< github repo="danvolchek/TODO" >}}

## Overview

TODO
37 changes: 37 additions & 0 deletions assets/css/schemes/sunflower.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* Sunflower scheme */
:root {
--color-neutral: 255, 255, 255;
/* Gray */
--color-neutral-50: 255,255,255;
--color-neutral-100: 255,255,255;
--color-neutral-200: 214,219,222;
--color-neutral-300: 172,183,188;
--color-neutral-400: 129,146,154;
--color-neutral-500: 92,107,115;
--color-neutral-600: 74,86,92;
--color-neutral-700: 56,65,70;
--color-neutral-800: 38,44,47;
--color-neutral-900: 19,23,24;
/* Yellow */
--color-primary-50: 255,255,255;
--color-primary-100: 255,255,255;
--color-primary-200: 253,250,242;
--color-primary-300: 243,227,175;
--color-primary-400: 232,204,109;
--color-primary-500: 222,181,43;
--color-primary-600: 194,156,30;
--color-primary-700: 159,128,25;
--color-primary-800: 123,100,19;
--color-primary-900: 88,71,14;
/* Rose */
--color-secondary-50: 255, 241, 242;
--color-secondary-100: 255, 228, 230;
--color-secondary-200: 254, 205, 211;
--color-secondary-300: 253, 164, 175;
--color-secondary-400: 251, 113, 133;
--color-secondary-500: 244, 63, 94;
--color-secondary-600: 225, 29, 72;
--color-secondary-700: 190, 18, 60;
--color-secondary-800: 159, 18, 57;
--color-secondary-900: 136, 19, 55;
}
1 change: 1 addition & 0 deletions assets/icons/resume.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/logo_padded.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
76 changes: 76 additions & 0 deletions assets/js/code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// This overrides blowfish's default code.js to enable code copy even when
// highlight.noClasses is true in markup.yml.
// The docs say it needs to be false to work, but I want it true so that
// I can override blowfish's syntax highlighting with hugo's syntax highlighting
// which looks better.
//
// Look for OLD and NEW.
var scriptBundle = document.getElementById("script-bundle");
var copyText = scriptBundle && scriptBundle.getAttribute("data-copy")? scriptBundle.getAttribute("data-copy") : "Copy";
var copiedText = scriptBundle && scriptBundle.getAttribute("data-copied")? scriptBundle.getAttribute("data-copied") : "Copied";

function createCopyButton(highlightDiv) {
const button = document.createElement("button");
button.className = "copy-button";
button.type = "button";
button.ariaLabel = copyText;
button.innerText = copyText;
button.addEventListener("click", () => copyCodeToClipboard(button, highlightDiv));
addCopyButtonToDom(button, highlightDiv);
}

async function copyCodeToClipboard(button, highlightDiv) {
// OLD
// const codeToCopy = highlightDiv.querySelector(":last-child > .chroma > code").innerText;
// NEW
const codeToCopy = [...highlightDiv.querySelectorAll("code > span")].map(line => line.innerText.trimEnd()).join("\n");
try {
result = await navigator.permissions.query({ name: "clipboard-write" });
if (result.state == "granted" || result.state == "prompt") {
await navigator.clipboard.writeText(codeToCopy);
} else {
copyCodeBlockExecCommand(codeToCopy, highlightDiv);
}
} catch (_) {
copyCodeBlockExecCommand(codeToCopy, highlightDiv);
} finally {
codeWasCopied(button);
}
}

function copyCodeBlockExecCommand(codeToCopy, highlightDiv) {
const textArea = document.createElement("textArea");
textArea.contentEditable = "true";
textArea.readOnly = "false";
textArea.className = "copy-textarea";
textArea.value = codeToCopy;
highlightDiv.insertBefore(textArea, highlightDiv.firstChild);
const range = document.createRange();
range.selectNodeContents(textArea);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
textArea.setSelectionRange(0, 999999);
document.execCommand("copy");
highlightDiv.removeChild(textArea);
}

function codeWasCopied(button) {
button.blur();
button.innerText = copiedText;
setTimeout(function () {
button.innerText = copyText;
}, 2000);
}

function addCopyButtonToDom(button, highlightDiv) {
highlightDiv.insertBefore(button, highlightDiv.firstChild);
const wrapper = document.createElement("div");
wrapper.className = "highlight-wrapper";
highlightDiv.parentNode.insertBefore(wrapper, highlightDiv);
wrapper.appendChild(highlightDiv);
}

window.addEventListener("DOMContentLoaded", (event) => {
document.querySelectorAll(".highlight").forEach((highlightDiv) => createCopyButton(highlightDiv));
});
58 changes: 58 additions & 0 deletions config/_default/hugo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# -- Site Configuration --
# Refer to the theme docs for more details about each of these parameters.
# https://blowfish.page/docs/getting-started/


theme: blowfish
baseURL: https://danvolchek.com/
defaultContentLanguage: en

publishDir: docs

enableRobotsTXT: false
paginate: 10
summaryLength: 0

buildDrafts: false
buildFuture: false

imaging:
anchor: Center

taxonomies:
tag: tags
category: categories
author: authors
series: series
blog: blog
projects: projects

sitemap:
changefreq: daily
filename: sitemap.xml
priority: 0.5

outputs:
home:
- HTML
- RSS
- JSON

related:
threshold: 0
toLower: false
indices:
- name: tags
weight: 100
- name: categories
weight: 100
- name: series
weight: 50
- name: authors
weight: 20
- name: date
weight: 10
- applyFilter: false
name: fragmentrefs
type: fragments
weight: 10
24 changes: 24 additions & 0 deletions config/_default/languages.en.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
languageCode: en
languageName: English
weight: 1
title: Dan Volchek

params:
displayName: EN
isoCode: en
rtl: false
dateFormat: January 2, 2006
logo: img/logo_padded.png
description: Project website and blog.

author:
name: Dan Volchek
image: img/logo.png
headline: Software Engineer
bio: Incredibly powerful
links:
- email: mailto:danvnad@gmail.com
- github: https://github.com/danvolchek
- linkedin: https://linkedin.com/in/dan-volchek/
- mastodon: https://mastodon.social/@danvolchek
- resume: /dan_volchek_resume.pdf
14 changes: 14 additions & 0 deletions config/_default/markup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# -- Markup --
# These settings are required for the theme to function.

goldmark:
renderer:
unsafe: true

highlight:
noClasses: true
style: catppuccin-frappe

tableOfContents:
startLevel: 2
endLevel: 4
62 changes: 62 additions & 0 deletions config/_default/menus.en.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# -- Main Menu --
# The main menu is displayed in the header at the top of the page.
# Acceptable parameters are name, pageRef, page, url, title, weight.
#
# The simplest menu configuration is to provide:
# name = The name to be displayed for this menu link
# pageRef = The identifier of the page or section to link to
#
# By default the menu is ordered alphabetically. This can be
# overridden by providing a weight value. The menu will then be
# ordered by weight from lowest to highest.

main:
- name: Projects
pageRef: projects
weight: 10

- name: Blog
pageRef: blog
weight: 20

# - name: example sub-menu 1
# parent: Parent
# pageRef: posts
# weight: 20

# - name: example sub-menu 2
# parent: Parent
# pageRef: posts
# weight: 20

# - name: Categories
# pageRef: categories
# weight: 20

# - name: Tags
# pageRef: tags
# weight: 30

# subnavigation:
# - name: An interesting topic
# pageRef: tags/interesting-topic
# weight: 10

# - name: My Awesome Category
# pre: github
# pageRef: categories/awesome
# weight: 20

# -- Footer Menu --
# The footer menu is displayed at the bottom of the page, just before
# the copyright notice. Configure as per the main menu above.


# footer:
# - name: Tags
# pageRef: tags
# weight: 10

# - name: Categories
# pageRef: categories
# weight: 20
3 changes: 3 additions & 0 deletions config/_default/module.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
hugoVersion:
extended: false
min: 0.87.0
Loading

0 comments on commit 6b6f70e

Please sign in to comment.