Merge branch 'master' of netsoj.nl:chris/chris-website
This commit is contained in:
commit
5cdd5b322c
2
dub.json
2
dub.json
|
@ -5,7 +5,7 @@
|
|||
"copyright": "Copyright © 2019, Chris Josten",
|
||||
"dependencies": {
|
||||
"dyaml": "~>0.8.0",
|
||||
"vibe-d": "~>0.8.6"
|
||||
"vibe-d": "~>0.9.0"
|
||||
},
|
||||
"description": "A blog based on Markdown and JSON",
|
||||
"license": "AGPLv3",
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
{
|
||||
"fileVersion": 1,
|
||||
"versions": {
|
||||
"botan": "1.12.10",
|
||||
"botan": "1.12.19",
|
||||
"botan-math": "1.0.3",
|
||||
"diet-ng": "1.6.0",
|
||||
"dyaml": "0.8.0",
|
||||
"eventcore": "0.8.48",
|
||||
"diet-ng": "1.7.5",
|
||||
"dyaml": "0.8.3",
|
||||
"eventcore": "0.9.13",
|
||||
"fswatch": "0.5.0",
|
||||
"libasync": "0.8.4",
|
||||
"libasync": "0.8.6",
|
||||
"libevent": "2.0.2+2.0.16",
|
||||
"memutils": "0.4.13",
|
||||
"memutils": "1.0.4",
|
||||
"mir-linux-kernel": "1.0.1",
|
||||
"openssl": "1.1.6+1.0.1g",
|
||||
"stdx-allocator": "2.77.5",
|
||||
"taggedalgebraic": "0.11.7",
|
||||
"taggedalgebraic": "0.11.19",
|
||||
"tinyendian": "0.2.0",
|
||||
"vibe-core": "1.7.0",
|
||||
"vibe-d": "0.8.6"
|
||||
"vibe-core": "1.13.0",
|
||||
"vibe-d": "0.9.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,21 +4,32 @@ body {
|
|||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
header {
|
||||
border-bottom: solid 40px;
|
||||
border-image: url(old/flames.gif) 0 0 200 0 round round;
|
||||
}
|
||||
|
||||
footer {
|
||||
border-top: solid 40px;
|
||||
border-image: url(old/flames.gif) 200 0 0 round round;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
cursor: url(old/cursor-over.gif), auto;
|
||||
}
|
||||
|
||||
body > nav {
|
||||
background-color: yellow;
|
||||
.header-navigation {
|
||||
background-color: cyan;
|
||||
color: black;
|
||||
}
|
||||
|
||||
body > nav ul {
|
||||
.header-navigation> nav ul {
|
||||
padding-left: 2em;
|
||||
list-style-image: url(old/bullet.gif);
|
||||
}
|
||||
|
||||
body > main {
|
||||
background-color: black;
|
||||
body main {
|
||||
background-color: green;
|
||||
color: white;
|
||||
border-image: url(old/skull-border.gif) 33% / 2em round;
|
||||
/*border-left-width: 10px !important;
|
||||
|
@ -27,7 +38,7 @@ body > main {
|
|||
|
||||
.title {
|
||||
width: 100%;
|
||||
background-color: green;
|
||||
color: orange;
|
||||
}
|
||||
|
||||
pre {
|
||||
|
@ -35,7 +46,7 @@ pre {
|
|||
}
|
||||
|
||||
blockquote, .screenshots, code{
|
||||
background: #0000ff;
|
||||
background: darkgreen;
|
||||
border-left: #0000cc 6px solid;
|
||||
}
|
||||
|
||||
|
|
BIN
public/static/style/old/flames.gif
Normal file
BIN
public/static/style/old/flames.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 173 KiB |
102
source/app.d
102
source/app.d
|
@ -75,48 +75,53 @@ void addCachingHeader(bool publicCache = true)(ref HTTPServerResponse res) {
|
|||
res.headers["Cache-Control"] = header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method for fetching a single page for a subclass of page.
|
||||
* Params:
|
||||
* T = the data structure/class to be passed as template parameter. Must have a slug parameter.
|
||||
* templ = The template to use when rendering.
|
||||
* array = An associative array where the keys are slugs for parameters and the values the template parameter.
|
||||
* req = The server request to consume. Assumes there is an slug parameter.
|
||||
* res = The server response to write to.
|
||||
*
|
||||
*/
|
||||
void getSingle(T, string templ)(ref T[string] array, HTTPServerRequest req, HTTPServerResponse res) {
|
||||
string slug = req.params["slug"];
|
||||
OutputType outputType = getOutputType(slug);
|
||||
|
||||
enforceHTTP(slug in array, HTTPStatus.notFound, "Page not found");
|
||||
T content = array[slug];
|
||||
switch(outputType) with (OutputType) {
|
||||
case MARKDOWN:
|
||||
res.writeBody(content.contentSource, MIME_MARKDOWN);
|
||||
break;
|
||||
default:
|
||||
case HTML:
|
||||
res.render!(templ, content);
|
||||
break;
|
||||
|
||||
struct TranslateContext {
|
||||
import std.typetuple;
|
||||
|
||||
alias languages = TypeTuple!("en_GB", "nl_NL");
|
||||
mixin translationModule!"mijnblog";
|
||||
static string determineLanguage(scope HTTPServerRequest req) {
|
||||
if ("lang" !in req.query) return req.determineLanguageByHeader(languages); // default behaviour using "Accept-Language" header
|
||||
return req.query.get("lang", "en_GB");
|
||||
}
|
||||
}
|
||||
|
||||
struct TranslationContext {
|
||||
import std.typetuple;
|
||||
enum enforceExistingKeys = true;
|
||||
alias languages = TypeTuple!("en_GB", "nl_NL");
|
||||
mixin translationModule!"mijnblog";
|
||||
}
|
||||
/**
|
||||
* Generates boilerplate code for a single response.
|
||||
* params:
|
||||
* arrayName = The name of the associative array to take the items from.
|
||||
* templateName = The name of the template to render.
|
||||
*/
|
||||
string singleResponseMixin(string arrayName, string templateName) {
|
||||
return `string slug = req.params["slug"];
|
||||
OutputType outputType = getOutputType(slug);
|
||||
|
||||
@translationContext!TranslationContext
|
||||
enforceHTTP(slug in ` ~ arrayName ~ `, HTTPStatus.notFound, "Page not found");
|
||||
auto content = ` ~ arrayName ~ `[slug];
|
||||
switch(outputType) with (OutputType) {
|
||||
case MARKDOWN:
|
||||
res.writeBody(content.contentSource, MIME_MARKDOWN);
|
||||
break;
|
||||
default:
|
||||
case HTML:
|
||||
render!("` ~ templateName ~ `", content);
|
||||
break;
|
||||
}`;
|
||||
}
|
||||
|
||||
@translationContext!TranslateContext
|
||||
class MijnBlog {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Generates response for /posts/:slug and /palen/:slug.
|
||||
*/
|
||||
@path("/posts/:slug")
|
||||
void getArticleSingle(string _slug, HTTPServerRequest req, HTTPServerResponse res) {
|
||||
getSingle!(Article, "pages/article.dt")(articles, req, res);
|
||||
//getSingle!(Article, "pages/article.dt")(articles, req, res);
|
||||
mixin(singleResponseMixin("articles", "pages/article.dt"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,7 +130,7 @@ class MijnBlog {
|
|||
@path("/posts/")
|
||||
void getArticleOverview(HTTPServerRequest req, HTTPServerResponse res) {
|
||||
addCachingHeader(res);
|
||||
render!("pages/article-list.dt", articleList)(res);
|
||||
render!("pages/article-list.dt", articleList);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,18 +139,17 @@ class MijnBlog {
|
|||
@path("/projects/")
|
||||
void getProjectOverview(HTTPServerRequest req, HTTPServerResponse res) {
|
||||
addCachingHeader(res);
|
||||
render!("pages/project-list.dt", projectList)(res);
|
||||
render!("pages/project-list.dt", projectList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generate response for a project page
|
||||
*/
|
||||
@path("/projects/:slug")
|
||||
void getProject(HTTPServerRequest req, HTTPServerResponse res) {
|
||||
res.headers["Cache-Control"] = "public";
|
||||
getSingle!(Project, "pages/project.dt")(projects, req, res);
|
||||
//getSingle!(Project, "pages/project.dt")(projects, req, res);
|
||||
mixin(singleResponseMixin("projects", "pages/project.dt"));
|
||||
}
|
||||
/**
|
||||
* Generate response for a page
|
||||
|
@ -153,7 +157,8 @@ class MijnBlog {
|
|||
@path("/:slug")
|
||||
void getPage(HTTPServerRequest req, HTTPServerResponse res) {
|
||||
addCachingHeader(res);
|
||||
getSingle!(Page, "pages/page.dt")(pages, req, res);
|
||||
//getSingle!(Page, "pages/page.dt")(pages, req, res);
|
||||
mixin(singleResponseMixin("pages", "pages/page.dt"));
|
||||
}
|
||||
|
||||
@path("/")
|
||||
|
@ -161,8 +166,20 @@ class MijnBlog {
|
|||
addCachingHeader(res);
|
||||
// If no slug is supplied, it will be adjusted to "index"
|
||||
req.params.addField("slug", "index");
|
||||
getSingle!(Page, "pages/page.dt")(pages, req, res);
|
||||
//getSingle!(Page, "pages/page.dt")(pages, req, res);
|
||||
mixin(singleResponseMixin("pages", "pages/page.dt"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method for fetching a single page for a subclass of page.
|
||||
* Params:
|
||||
* T = the data structure/class to be passed as template parameter. Must have a slug parameter.
|
||||
* templ = The template to use when rendering.
|
||||
* array = An associative array where the keys are slugs for parameters and the values the template parameter.
|
||||
* req = The server request to consume. Assumes there is an slug parameter.
|
||||
* res = The server response to write to.
|
||||
*
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -189,15 +206,6 @@ void main() {
|
|||
URLRouter router = new URLRouter;
|
||||
router.get("/static/*", serveStaticFiles("./public/", fSettings));
|
||||
router.registerWebInterface(new MijnBlog);
|
||||
/*router.get("/posts/:slug", &articleGetSingle);
|
||||
router.get("/palen/:slug", &articleGetSingle);
|
||||
router.get("/posts/", &articleGetOverview);
|
||||
router.get("/palen/", &articleGetOverview);
|
||||
router.get("/projects/", &projectGetOverview);
|
||||
router.get("/projects/:slug", &projectGet);
|
||||
router.get("/projecten/:slug", &projectGet);
|
||||
router.get("/:slug", &pageGet);
|
||||
router.get("/", &pageGet);*/
|
||||
|
||||
listenHTTP(settings, router);
|
||||
|
||||
|
|
|
@ -1,2 +1,7 @@
|
|||
msgid "page.header-bottom-text"
|
||||
msgid "template.page.name"
|
||||
msgstr "Chris's website"
|
||||
|
||||
msgid "template.page.copyright"
|
||||
msgstr "© Chris Josten, 2021. If not specified otherwise, all content on this"
|
||||
"website is <a rel=\"license\" href=\"https://creativecommons.org/licenses/by/4.0/\">"
|
||||
"licensed under the CC-BY 4.0</a>"
|
||||
|
|
|
@ -11,5 +11,9 @@ msgstr ""
|
|||
"Language: nl\n"
|
||||
"X-Generator: Poedit 2.3.1\n"
|
||||
|
||||
msgid "Chris's website"
|
||||
msgid "template.page.name"
|
||||
msgstr "Chris z'n webstekkie"
|
||||
|
||||
msgid "template.page.copyright"
|
||||
msgstr "© Chris Josten, 2021. Tenzij anders vermeld staat, valt alle inhoud op deze webstek"
|
||||
"<a rel=\"license\" href=\"https://creativecommons.org/licenses/by/4.0/\"> onder de CC-BY 4.0</a>"
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
extends /parts/page.dt
|
||||
|
||||
block header
|
||||
title Posts - Netsoj.nl
|
||||
|
||||
block sidebar
|
||||
|
||||
block content
|
||||
header
|
||||
h1.title Post list
|
||||
- import vibe.d;
|
||||
- if (articleList.length == 0)
|
||||
p No posts found
|
||||
- else
|
||||
- import utils;
|
||||
- foreach(article; articleList)
|
||||
article
|
||||
header
|
||||
a(href="/posts/#{article.slug}", rel="bookmark")
|
||||
h2.title #{article.title}
|
||||
p.subtitle
|
||||
| By #{article.author} on #{article.firstPublished.toHumanString}
|
||||
- if (article.firstPublished != article.updated)
|
||||
|, updated on #{article.updated.toHumanString}
|
||||
p #{article.excerpt}…
|
|
@ -1,25 +0,0 @@
|
|||
extends /parts/page
|
||||
|
||||
block meta_data
|
||||
- page_type = "article";
|
||||
- page_title = content.title;
|
||||
- page_url = "/post/" ~ content.slug;
|
||||
- page_description = content.excerpt;
|
||||
|
||||
block extra_meta_data
|
||||
meta(name="og:article:author:username", content=content.author)
|
||||
meta(name="og:article:published_time", content=content.firstPublished.toISOExtString)
|
||||
- if (content.isModified)
|
||||
meta(name="og:article:modified_time", content=content.updated.toISOExtString)
|
||||
|
||||
block content
|
||||
article(itemscope, itemtype="https://schema.org/BlogPosting")
|
||||
- import utils;
|
||||
header
|
||||
h1.title(itemprop="headline") #{content.title}
|
||||
p.subtitle
|
||||
| By <span itemprop="author">#{content.author}</span>
|
||||
| on <time datetime="#{content.firstPublished.toISOExtString}" itemprop="datePublished">#{content.firstPublished.toHumanString}</time>
|
||||
- if (content.isModified)
|
||||
|, updated on <time datetime="#{content.updated.toISOExtString}" itemprop="dateModified">#{content.updated.toHumanString}</time>
|
||||
section(itemprop="articleBody") !{content.content}
|
|
@ -1,11 +0,0 @@
|
|||
extends /parts/page.dt
|
||||
|
||||
block header
|
||||
title #{error.message} - Netsoj.nl
|
||||
|
||||
block sidebar
|
||||
|
||||
block content
|
||||
header
|
||||
h1.title #{error.message} (#{error.code})
|
||||
pre #{error.debugMessage}
|
|
@ -1,4 +1,4 @@
|
|||
extends /parts/page.dt
|
||||
extends parts/page
|
||||
|
||||
block meta_data
|
||||
- page_title = content.title;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
extends /parts/page.dt
|
||||
extends parts/page
|
||||
|
||||
block header
|
||||
title Projects - Chris Netsoj.nl
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
extends /parts/page
|
||||
extends parts/page
|
||||
block meta_data
|
||||
- page_title = content.title;
|
||||
- page_url = "/project/" ~ content.slug;
|
||||
|
|
|
@ -1,5 +1,2 @@
|
|||
p
|
||||
small
|
||||
| © Chris Josten, 2020. If not specified otherwise, all content on this
|
||||
| website is <a rel="license" href="https://creativecommons.org/licenses/by/4.0/">
|
||||
| licensed under the CC-BY 4.0</a>.
|
||||
small& template.page.copyright
|
||||
|
|
|
@ -45,7 +45,7 @@ html(prefix="og: http://ogp.me/ns#")
|
|||
section.header-navigation
|
||||
header
|
||||
img.logo(src="/static/img/logo.png", alt="The logo of the website: the letter C drawn in an unprofessional manner with wobbly eyes on put on top")
|
||||
p& Chris's website
|
||||
p& template.page.name
|
||||
nav
|
||||
ul
|
||||
- menuItem("home", "/");
|
||||
|
@ -54,10 +54,10 @@ html(prefix="og: http://ogp.me/ns#")
|
|||
block sidebar
|
||||
footer.hide-small
|
||||
block footer
|
||||
include /parts/footer.dt
|
||||
include parts/footer
|
||||
main
|
||||
block content
|
||||
|
||||
footer.hide-big
|
||||
block footer
|
||||
include /parts/footer.dt
|
||||
include parts/footer
|
||||
|
|
Loading…
Reference in a new issue