Quick Install
One command is all you need to start a new website.
wget -qO - https://codeberg.org/vhs/after-dark/raw/branch/trunk/bin/install | sh
Run the above command in a terminal emulator after
installing Hugo to start a new website in 5-10 seconds. Hugo version 0.51
or greater required.
After Dark includes a portable installation script for quick set-up. Please install
Hugo 0.51
or greater before running:
Expand to view script
1#!/bin/sh
2#
3# Copyright (C) 2019 VHS <vhsdev@tutanota.com>
4#
5# This file is part of After Dark.
6#
7# After Dark is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as published
9# by the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# After Dark is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <https://www.gnu.org/licenses/>.
19#
20
21set -eu
22
23validate_hugo() {
24 # Exit with error if hugo is not installed
25 if ! hash hugo 2>/dev/null; then
26 echo "Error: After Dark requires Hugo version 0.51 or greater" >&2
27 exit 1
28 fi
29
30 # Exit with error if not minimum required hugo version
31 re="v(0\d*\.([5-9][1-9]|[6-9])|[1-9]).*"
32 if ! hugo version | grep -qE "$re"; then
33 echo "Error: After Dark requires Hugo version 0.51 or greater" >&2
34 exit 1
35 fi
36}
37
38confirm_intent() {
39 while true; do
40 printf "Do you wish to install After Dark? (y/n) "
41 read -r yn </dev/tty
42 case $yn in
43 [Yy]*)
44 break
45 ;;
46 [Nn]*) exit ;;
47 *) echo "Please answer yes or no." ;;
48 esac
49 done
50}
51
52prompt_site_name() {
53 printf "Please enter a name for your site: "
54 read -r response </dev/tty
55 SITE_NAME=$(echo "$response" | tr -cd '[:alnum:] [:space:]' | tr -s '[:space:]')
56 while true; do
57 printf "You entered %s. Is that correct? (y/n) " "\"$SITE_NAME\""
58 read -r yn </dev/tty
59 case $yn in
60 [Yy]*)
61 break
62 ;;
63 [Nn]*)
64 prompt_site_name
65 break
66 ;;
67 *) echo "Please answer yes or no." ;;
68 esac
69 done
70}
71
72format_dir_name() {
73 echo "$1" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd '[:alnum:]._-'
74}
75
76prompt_install_dir() {
77 default_dir=$(format_dir_name "$SITE_NAME")
78 printf "Choose an installation directory name (%s): " "$default_dir"
79 read -r response </dev/tty
80 if [ "$response" = "" ]; then
81 SITE_DIR=$default_dir
82 elif [ "${response%"${response#?}"}" = "/" ]; then
83 echo "Directory name not allowed. Proceeding with default..."
84 SITE_DIR=$default_dir
85 else
86 formatted_input_dir=$(format_dir_name "$response")
87 if [ "$formatted_input_dir" = "" ]; then
88 echo "Directory name not allowed. Proceeding with default..."
89 SITE_DIR=$default_dir
90 else
91 SITE_DIR=$formatted_input_dir
92 fi
93 fi
94 while true; do
95 printf "Installation directory name set to %s. Is that correct? (y/n) " "\"$SITE_DIR\""
96 read -r yn </dev/tty
97 case $yn in
98 [Yy]*)
99 break
100 ;;
101 [Nn]*)
102 prompt_install_dir
103 break
104 ;;
105 *) echo "Please answer yes or no." ;;
106 esac
107 done
108}
109
110create_site_dir() {
111 SITE_DIR_ABS="$PWD/$SITE_DIR"
112 mkdir "$SITE_DIR"
113}
114
115create_site() {
116 echo "Creating a new Hugo site ..."
117 hugo new site "$SITE_DIR" 1>/dev/null
118 cd "$SITE_DIR" || exit 1
119}
120
121download_theme() {
122 echo "Downloading the latest version of After Dark ..."
123 LATEST_META=$(wget -qO - https://registry.npmjs.org/after-dark/latest)
124 vers=$(echo "$LATEST_META" | grep -oE "\"version\".*[^,]*," | cut -d ',' -f1 | cut -d ':' -f2 | tr -d '" ')
125 mkdir -p themes/after-dark
126 wget -qO - https://registry.npmjs.org/after-dark/-/after-dark-"$vers".tgz | tar --strip-components=1 -xz -C themes/after-dark
127 echo "Version $vers downloaded to $SITE_DIR/themes/after-dark"
128}
129
130download_module() {
131 [ -z "$1" ] && {
132 echo "Error: Attempt to download undefined module" >&2
133 exit 1
134 }
135 echo "Downloading $1 module for After Dark ..."
136 meta=$(wget -qO - https://registry.npmjs.org/"$1"/latest)
137 vers=$(echo "$meta" | grep -oE "\"version\".*[^,]*," | cut -d ',' -f1 | cut -d ':' -f2 | tr -d '" ')
138 mkdir -p themes/"$1"
139 wget -qO - https://registry.npmjs.org/"$1"/-/"$1"-"$vers".tgz | tar --strip-components=1 -xz -C themes/"$1"
140 echo "Version $vers downloaded to $SITE_DIR/themes/$1"
141}
142
143configure_theme() {
144 echo "Configuring basic After Dark theme settings ..."
145 tee "config.toml" >/dev/null <<TOML
146baseurl = "https://domain.example" # Controls base URL sitewide
147languageCode = "en-US" # Controls site language
148title = "$SITE_NAME" # Homepage title and page title suffix
149paginate = 11 # Number of posts to show before paginating
150copyright = "Copyright © Copyright Owner. Licensed under <a target=\"_blank\" rel=\"external noopener license\" href=\"https://creativecommons.org/licenses/by-nd/4.0/\">CC-BY-ND-4.0</a>." # Optional, remove to suppress copyright notices
151
152# Controls default theme and theme components
153theme = [
154 "fractal-forest", # OBSD
155 "after-dark" # AGPL-3.0-or-later
156]
157
158disableLiveReload = false # Optional, set true to disable live reload
159enableRobotsTXT = true # Suggested, enable robots.txt file
160sectionPagesMenu = "main" # Enable menu system for lazy bloggers
161
162[markup.goldmark.renderer]
163 unsafe = true # Optional, allows HTML inside your CommonMark content
164[markup.tableOfContents]
165 startLevel = 1 # Suggested, draws TOC using all heading levels
166 endLevel = 6 # Suggested, draws TOC using all heading levels
167[markup.highlight]
168 noClasses = false # Suggested, used for custom syntax highlighting
169
170[params]
171 description = "" # Suggested, controls default description meta
172 author = "" # Optional, controls author name display on posts
173 hide_author = false # Optional, set true to hide author name on posts
174 disable_csp = false # Optional, set true to disable content security policy
175 images = [
176 "https://source.unsplash.com/collection/983219/2000x1322"
177 ] # Suggested, controls default Open Graph images
178
179[params.layout.menu.main]
180 hidden = true # Optional, set false or remove to show section menu
181
182[params.layout.footer]
183 hidden = false # Optional, set true to hide footer
184
185[params.modules.fractal_forest]
186 enabled = true # Optional, set false to disable module
187 decoders = ["bpgdec8a"] # Optional, 8-bit javascript decoder with animation
188TOML
189}
190
191update_archetypes() {
192 echo "Updating the default content archetype ..."
193 rm -f archetypes/default.md
194 cp themes/after-dark/archetypes/default.md archetypes
195}
196
197create_welcome_post() {
198 echo "Creating welcome post ..."
199 hugo new post/welcome.md 1>/dev/null
200}
201
202generate_help_docs() {
203 echo "Generating help documentation ..."
204 THEME_PATH=themes/after-dark
205 meta_path="$THEME_PATH"/data/npm
206 mkdir -p "$meta_path" && echo "$LATEST_META" | tr '\r\n' ' ' >"$meta_path"/latest.json
207 cd "$THEME_PATH"/docs && mkdir themes && ln -s ../.. "$THEME_PATH"
208 hugo new validate.md --kind validate 1>/dev/null
209}
210
211echo "Welcome to the After Dark quick installer. Press CTRL-C at any time to abort."
212
213confirm_intent
214validate_hugo
215prompt_site_name
216prompt_install_dir
217create_site_dir
218create_site
219download_theme
220update_archetypes
221download_module "fractal-forest"
222configure_theme
223create_welcome_post
224generate_help_docs
225
226YELLOW='\033[0;33m'
227NC='\033[0m'
228
229echo "${YELLOW}Installation successful!${NC}"
230echo "Site created in $SITE_DIR_ABS"
231echo "Serve your site with \"hugo serve --buildDrafts --navigateToChanged\""
232echo "Thank you for choosing After Dark."
Script has been tested on GNU/Linux, BSD (Darwin) and Windows via Cmder.
Here are three methods for downloading and running:
-
Download and pipe to
sh
directly:wget -qO - https://codeberg.org/vhs/after-dark/raw/branch/trunk/bin/install | sh
-
Download into new file,
chmod
and execute:curl -O https://cdn.jsdelivr.net/npm/after-dark@latest/bin/install && \ chmod +x install && ./install
-
From canonical
git
clone:# clone source and change to source directory git clone https://codeberg.org/vhs/after-dark.git && cd "$_" # use npm cli to get the release hash echo "${$(npm run integrity)#*sha512-}" # run quick install after validating ./bin/install
Script should complete in 5-10 seconds resulting in a sample site and help docs:

Your new site will be called flying-toasters
. Change it to the name of your project anytime you like. Access site by navigating to https://localhost:1313.
Multi-site Configuration (Advanced)
After Dark enables multi-site management from a single installation. To manage multiple websites use the -c
and -d
flags to specify the content
and destination
directories, respectively.
For example, to generate an audio site using the current After Dark installation create an executable script to generate the site:
#!/bin/sh
hugo -c sites/audio -d public/static.domain.example
Where audio
contains the content for that site:
├── layouts
├── sites
│ └── audio
│ ├── audiobooks
│ │ ├── gaining-currency.md
│ │ └── the-power-of-now.md
│ └── clips
│ └── war-of-the-worlds.md
├── static
And public
contains a folder for each site:
public
└── static.domain.example
├── categories
│ └── index.xml
├── audiobooks
│ └── index.html
├── clips
│ └── index.html
├── css
├── index.html
├── index.xml
├── js
├── sitemap.xml
└── tags
└── index.xml
And create another script to serve the content for editing:
#!/bin/sh
hugo -c sites/audio
Each subdirectory of public
then becomes an independent, deployable website and exact copy save for destination content generated.
hugo --help
and modify your scripts using the --theme
and --config
flags.
Multi-site is perfect for maintaining a consistent look-and-feel across multiple domain origins while limiting the need to run the Upgrade Script for each site.