diff --git a/.eleventy.js b/.eleventy.js
new file mode 100644
index 0000000..0899304
--- /dev/null
+++ b/.eleventy.js
@@ -0,0 +1,9 @@
+module.exports = () => {
+ return {
+ pathPrefix: "/error/",
+ dir: {
+ input: "src/main/",
+ output: "dist/",
+ }
+ };
+};
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..1a6bd45
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+package-lock.json binary
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e7ea1e8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,117 @@
+## Node
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+web_modules/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+.env.test
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+out
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and not Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+.vscode-test
+
+# yarn v2
+
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.pnp.*
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 0000000..38c7be7
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,114 @@
+const path = require("path");
+
+module.exports = grunt => {
+ grunt.initConfig({
+ pkg: grunt.file.readJSON("package.json"),
+ clean: {
+ default: ["dist/"],
+ },
+ exec: {
+ eleventy: "npx @11ty/eleventy",
+ },
+ focus: {
+ dev: {
+ include: ["js", "json", "md", "njk"],
+ },
+ },
+ replace: {
+ dev: {
+ src: ["./dist/**/*.html", "./dist/**/*.js"],
+ replacements: [
+ {
+ from: "%%VERSION_NUMBER%%",
+ to: "<%= pkg.version %>+" + new Date().toISOString().slice(0, 19).replace(/[-:T]/g, "")
+ }
+ ],
+ overwrite: true
+ },
+ deploy: {
+ src: ["./dist/**/*.html", "./dist/**/*.js"],
+ replacements: [
+ {
+ from: "%%VERSION_NUMBER%%",
+ to: "<%= pkg.version %>"
+ }
+ ],
+ overwrite: true
+ },
+ },
+ watch: {
+ js: {
+ files: ["src/main/**/*.js"],
+ tasks: ["webpack:dev", "replace:dev"],
+ },
+ json: {
+ files: ["src/main/**/*.json"],
+ tasks: ["exec:eleventy", "replace:dev"],
+ },
+ md: {
+ files: ["src/main/**/*.md"],
+ tasks: ["exec:eleventy", "replace:dev"],
+ },
+ njk: {
+ files: ["src/main/**/*.njk"],
+ tasks: ["exec:eleventy", "replace:dev"],
+ },
+ },
+ webpack: {
+ options: {
+ entry: "./src/main/js/main.js",
+ module: {
+ rules: [
+ {
+ test: /\.js$/,
+ exclude: /node_modules/,
+ },
+ ],
+ },
+ resolve: {
+ extensions: [".js"],
+ },
+ output: {
+ filename: "bundle.js",
+ path: path.resolve(__dirname, "dist/"),
+ },
+ },
+ dev: {
+ mode: "development",
+ devtool: "inline-source-map",
+ },
+ deploy: {
+ mode: "production",
+ },
+ },
+ });
+
+ grunt.loadNpmTasks("grunt-contrib-clean");
+ grunt.loadNpmTasks("grunt-contrib-watch");
+ grunt.loadNpmTasks("grunt-exec");
+ grunt.loadNpmTasks("grunt-focus");
+ grunt.loadNpmTasks("grunt-text-replace");
+ grunt.loadNpmTasks("grunt-webpack");
+
+ grunt.registerTask("dev", [
+ // Pre
+ "clean",
+ // Generate site
+ "exec:eleventy",
+ // Compile JS
+ "webpack:dev",
+ "replace:dev",
+ ]);
+ grunt.registerTask("dev:server", ["dev", "focus:dev"]);
+ grunt.registerTask("deploy", [
+ // Pre
+ "clean",
+ // Generate site
+ "exec:eleventy",
+ // Compile JS
+ "webpack:deploy",
+ "replace:deploy",
+ ]);
+
+ grunt.registerTask("default", ["dev"]);
+};
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..0650d3e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Felix W. Dekker
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index fcd0d75..eb7d108 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,23 @@
# Error pages
The error pages used on [fwdekker.com](https://fwdekker.com/) (and probably some related domains as well).
+
+## Development
+### Requirements
+* [npm](https://www.npmjs.com/)
+
+### Setting up
+```shell script
+# Install dependencies (only needed once)
+$> npm ci
+```
+
+### Building
+```shell script
+# Build the blog in `dist/` for development
+$> npm run dev
+# Build the blog in `dist/` for deployment
+$> npm run deploy
+```
+
+You may need to change the `pathprefix` option of Eleventy when using WebStorm so that the root of the blog is changed
+to `/error-pages/dist/` instead of `/`.
diff --git a/dist/400.html b/dist/400.html
deleted file mode 100644
index 32f5480..0000000
--- a/dist/400.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Bad request | FWDekker
-
-
-
-
-
-
-
-
- Bad request (400)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/401.html b/dist/401.html
deleted file mode 100644
index ef7a448..0000000
--- a/dist/401.html
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
-
-
-
-
-
- Unauthorized | FWDekker
-
-
-
-
-
-
-
-
- Unauthorized (401)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
-
diff --git a/dist/402.html b/dist/402.html
deleted file mode 100644
index 32da57e..0000000
--- a/dist/402.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Payment required | FWDekker
-
-
-
-
-
-
-
-
- Payment required (402)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/403.html b/dist/403.html
deleted file mode 100644
index a4e9b74..0000000
--- a/dist/403.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Access forbidden | FWDekker
-
-
-
-
-
-
-
-
- Access forbidden (403)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/404.html b/dist/404.html
deleted file mode 100644
index ae48e98..0000000
--- a/dist/404.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- File not found | FWDekker
-
-
-
-
-
-
-
-
- File not found (404)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/405.html b/dist/405.html
deleted file mode 100644
index e9dd23d..0000000
--- a/dist/405.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Internal server error | FWDekker
-
-
-
-
-
-
-
-
- Internal server error (405)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/406.html b/dist/406.html
deleted file mode 100644
index c99872e..0000000
--- a/dist/406.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Not acceptable | FWDekker
-
-
-
-
-
-
-
-
- Not acceptable (406)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/407.html b/dist/407.html
deleted file mode 100644
index 9af402e..0000000
--- a/dist/407.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Proxy authentication required | FWDekker
-
-
-
-
-
-
-
-
- Proxy authentication required (407)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/408.html b/dist/408.html
deleted file mode 100644
index 2cb96aa..0000000
--- a/dist/408.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Request timeout | FWDekker
-
-
-
-
-
-
-
-
- Request timeout (408)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/409.html b/dist/409.html
deleted file mode 100644
index 372753a..0000000
--- a/dist/409.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Conflict | FWDekker
-
-
-
-
-
-
-
-
- Conflict (409)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/410.html b/dist/410.html
deleted file mode 100644
index 4fe15f8..0000000
--- a/dist/410.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Gone | FWDekker
-
-
-
-
-
-
-
-
- Gone (410)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/411.html b/dist/411.html
deleted file mode 100644
index 6302b7f..0000000
--- a/dist/411.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Length required | FWDekker
-
-
-
-
-
-
-
-
- Length required (411)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/412.html b/dist/412.html
deleted file mode 100644
index 6c6d235..0000000
--- a/dist/412.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Precondition required | FWDekker
-
-
-
-
-
-
-
-
- Precondition required (412)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/413.html b/dist/413.html
deleted file mode 100644
index a289721..0000000
--- a/dist/413.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Request entity too large | FWDekker
-
-
-
-
-
-
-
-
- Request entity too large (413)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/414.html b/dist/414.html
deleted file mode 100644
index eef50a8..0000000
--- a/dist/414.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Request URI too long | FWDekker
-
-
-
-
-
-
-
-
- Request URI too long (414)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/415.html b/dist/415.html
deleted file mode 100644
index 2155d20..0000000
--- a/dist/415.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Unsupported media type | FWDekker
-
-
-
-
-
-
-
-
- Unsupported media type (415)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/416.html b/dist/416.html
deleted file mode 100644
index 650d4b1..0000000
--- a/dist/416.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Requested range not satisfiable | FWDekker
-
-
-
-
-
-
-
-
- Requested range not satisfiable (416)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/417.html b/dist/417.html
deleted file mode 100644
index 13a5b0c..0000000
--- a/dist/417.html
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
-
-
-
-
-
- Expectation failed | FWDekker
-
-
-
-
-
-
-
-
- Expectation failed (417)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
diff --git a/dist/451.html b/dist/451.html
deleted file mode 100644
index 025704b..0000000
--- a/dist/451.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Unavailable for legal reasons | FWDekker
-
-
-
-
-
-
-
-
- Unavailable for legal reasons (451)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/500.html b/dist/500.html
deleted file mode 100644
index 812fd70..0000000
--- a/dist/500.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Internal server error | FWDekker
-
-
-
-
-
-
-
-
- Internal server error (500)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/501.html b/dist/501.html
deleted file mode 100644
index a916078..0000000
--- a/dist/501.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Not implemented | FWDekker
-
-
-
-
-
-
-
-
- Not implemented (501)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/502.html b/dist/502.html
deleted file mode 100644
index 0fad552..0000000
--- a/dist/502.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Bad gateway | FWDekker
-
-
-
-
-
-
-
-
- Bad gateway (502)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/503.html b/dist/503.html
deleted file mode 100644
index 16a902a..0000000
--- a/dist/503.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Service unavailable | FWDekker
-
-
-
-
-
-
-
-
- Service unavailable (503)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/504.html b/dist/504.html
deleted file mode 100644
index 434246b..0000000
--- a/dist/504.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- Gateway timeout | FWDekker
-
-
-
-
-
-
-
-
- Gateway timeout (504)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/dist/505.html b/dist/505.html
deleted file mode 100644
index 2478281..0000000
--- a/dist/505.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
- HTTP version not supported | FWDekker
-
-
-
-
-
-
-
-
- HTTP version not supported (505)
- Sorry for the inconvenience.
- You may want to try going to this website's homepage.
-
-
-
-
-
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..4def3f8
Binary files /dev/null and b/package-lock.json differ
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..b2ccd11
--- /dev/null
+++ b/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "error-pages",
+ "version": "1.3.0",
+ "description": "Error pages for my website.",
+ "author": "Felix W. Dekker",
+ "browser": "dist/bundle.js",
+ "repository": {
+ "type": "git",
+ "url": "git@git.fwdekker.com:FWDekker/error-pages.git"
+ },
+ "private": true,
+ "scripts": {
+ "clean": "grunt clean",
+ "dev": "grunt dev",
+ "dev:server": "grunt dev:server",
+ "deploy": "grunt deploy"
+ },
+ "devDependencies": {
+ "@11ty/eleventy": "^0.12.1",
+ "grunt": "^1.4.0",
+ "grunt-cli": "^1.4.2",
+ "grunt-contrib-clean": "^2.0.0",
+ "grunt-contrib-watch": "^1.1.0",
+ "grunt-exec": "^3.0.0",
+ "grunt-focus": "^1.0.0",
+ "grunt-text-replace": "^0.4.0",
+ "grunt-webpack": "^4.0.3",
+ "webpack": "^5.36.2",
+ "webpack-cli": "^4.7.0"
+ }
+}
diff --git a/src/main/_data/error-pages.json b/src/main/_data/error-pages.json
new file mode 100644
index 0000000..9fde2df
--- /dev/null
+++ b/src/main/_data/error-pages.json
@@ -0,0 +1,102 @@
+[
+ {
+ "name": "Bad request",
+ "code": "400"
+ },
+ {
+ "name": "Unauthorized",
+ "code": "401"
+ },
+ {
+ "name": "Payment required",
+ "code": "402"
+ },
+ {
+ "name": "Access forbidden",
+ "code": "403"
+ },
+ {
+ "name": "File not found",
+ "code": "404"
+ },
+ {
+ "name": "Internal server error",
+ "code": "405"
+ },
+ {
+ "name": "Not acceptable",
+ "code": "406"
+ },
+ {
+ "name": "Proxy authentication required",
+ "code": "407"
+ },
+ {
+ "name": "Request timeout",
+ "code": "408"
+ },
+ {
+ "name": "Conflict",
+ "code": "409"
+ },
+ {
+ "name": "Gone",
+ "code": "410"
+ },
+ {
+ "name": "Length required",
+ "code": "411"
+ },
+ {
+ "name": "Precondition required",
+ "code": "412"
+ },
+ {
+ "name": "Request entity too large",
+ "code": "413"
+ },
+ {
+ "name": "Request URI too long",
+ "code": "414"
+ },
+ {
+ "name": "Unsupported media type",
+ "code": "415"
+ },
+ {
+ "name": "Requested range not satisfiable",
+ "code": "416"
+ },
+ {
+ "name": "Expectation failed",
+ "code": "417"
+ },
+ {
+ "name": "Unavailable for legal reasons",
+ "code": "451"
+ },
+ {
+ "name": "Internal server error",
+ "code": "500"
+ },
+ {
+ "name": "Not implemented",
+ "code": "501"
+ },
+ {
+ "name": "Bad gateway",
+ "code": "502"
+ },
+ {
+ "name": "Service unavailable",
+ "code": "503"
+ },
+ {
+ "name": "Gateway timeout",
+ "code": "504"
+ },
+ {
+ "name": "HTTP version not supported",
+ "code": "505"
+ }
+]
diff --git a/src/main/_data/site.json b/src/main/_data/site.json
new file mode 100644
index 0000000..d75e668
--- /dev/null
+++ b/src/main/_data/site.json
@@ -0,0 +1,5 @@
+{
+ "baseurl": "/",
+ "title": "FWDekker",
+ "author": "Felix W. Dekker"
+}
diff --git a/src/main/js/main.js b/src/main/js/main.js
new file mode 100644
index 0000000..16bf910
--- /dev/null
+++ b/src/main/js/main.js
@@ -0,0 +1,11 @@
+// noinspection JSUnresolvedVariable
+const {$, doAfterLoad, footer, nav} = window.fwdekker;
+
+
+doAfterLoad(() => {
+ $("#nav").appendChild(nav("/"));
+ $("#footer").appendChild(footer({
+ vcsURL: "https://git.fwdekker.com/FWDekker/error-pages/",
+ version: "v%%VERSION_NUMBER%%"
+ }));
+});
diff --git a/src/main/template.njk b/src/main/template.njk
new file mode 100644
index 0000000..1992521
--- /dev/null
+++ b/src/main/template.njk
@@ -0,0 +1,46 @@
+---
+pagination:
+ data: error-pages
+ size: 1
+ alias: errorPage
+permalink: "{{ errorPage.code | slug }}.html"
+---
+
+
+
+
+
+
+
+
+
+ {{ errorPage.name }} | FWDekker
+
+
+
+
+
+
+
+
+
+
+ {{ errorPage.name }} ({{ errorPage.code }})
+ Sorry for the inconvenience.
+ You may want to try going to this website's homepage.
+
+
+
+
+
+
+
+
+
+