Boiler plate for blog.
This commit is contained in:
parent
ee04a0f43e
commit
a6872fb415
69
Makefile
Normal file
69
Makefile
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
.PHONY: serve clean info
|
||||||
|
|
||||||
|
SRC_DIR := src
|
||||||
|
BUILD_DIR := build
|
||||||
|
ENTRIES_LIST := .entries.csv
|
||||||
|
|
||||||
|
# Pandoc basic configuration
|
||||||
|
PANDOC := pandoc -s
|
||||||
|
PANDOC_FILTERS :=
|
||||||
|
|
||||||
|
PANDOC_METADATA = \
|
||||||
|
--template=templates/default.html \
|
||||||
|
--metadata-file metadata.yaml \
|
||||||
|
--metadata=path="$(shell echo $@ | sed -e 's/build//g' )" \
|
||||||
|
--metadata=git_initial_date="$(shell git log --reverse -n 1 --pretty=format:%aI -- $< || echo 'draft')" \
|
||||||
|
--metadata=git_date="$(shell git log -n 1 --pretty=format:%aI -- $< || echo 'draft')" \
|
||||||
|
|
||||||
|
PANDOC_COMMAND = $(PANDOC) $(PANDOC_FILTERS) $(PANDOC_METADATA)
|
||||||
|
|
||||||
|
# Blog Configuration
|
||||||
|
COMMENT_SECTION := templates/comment-section.html
|
||||||
|
PANDOC_BLOG_FILTER := filters/blog_feed.py
|
||||||
|
|
||||||
|
# Public Pages configuration
|
||||||
|
#
|
||||||
|
# All markdown files
|
||||||
|
PAGES = \
|
||||||
|
build/index.html \
|
||||||
|
build/contact.html
|
||||||
|
FEEDS = build/blog/index.html build/blog/rss.xml
|
||||||
|
ENTRIES = $(shell find src/blog -mindepth 2 -type f -name '*.md' | sed -e 's/\.md/.html/;s/src/build/g')
|
||||||
|
# PAGES = # Define here which pages to publish.
|
||||||
|
# PAGES = build/index.html
|
||||||
|
|
||||||
|
info:
|
||||||
|
@echo $(ENTRIES)
|
||||||
|
|
||||||
|
|
||||||
|
all: $(PAGES) $(FEEDS)
|
||||||
|
|
||||||
|
$(ENTRIES_LIST): $(ENTRIES)
|
||||||
|
|
||||||
|
|
||||||
|
$(BUILD_DIR)/blog/%.html: $(SRC_DIR)/blog/%.md $(COMMENT_SECTION)
|
||||||
|
mkdir -p $(shell dirname $@)
|
||||||
|
[[ -d "$(shell dirname $<)/assets" ]] \
|
||||||
|
&& cp -r $(shell dirname $<)/assets/. $(shell dirname $@)/assets \
|
||||||
|
|| echo "Entry with no assets"
|
||||||
|
$(PANDOC_COMMAND) \
|
||||||
|
--filter $(PANDOC_BLOG_FILTER) \
|
||||||
|
--include-after-body=$(COMMENT_SECTION) \
|
||||||
|
-i $< -o $@
|
||||||
|
|
||||||
|
$(BUILD_DIR)/blog/index.html: $(SRC_DIR)/blog/index.md $(ENTRIES_LIST)
|
||||||
|
cat $(ENTRIES_LIST) | sort | ./scripts/entries2rss.py html | \
|
||||||
|
$(PANDOC_COMMAND) -i $< -i - -o $@
|
||||||
|
|
||||||
|
$(BUILD_DIR)/blog/rss.xml: $(ENTRIES_LIST)
|
||||||
|
cat $(ENTRIES_LIST) | sort | ./scripts/entries2rss.py > $@
|
||||||
|
|
||||||
|
$(BUILD_DIR)/%.html: $(SRC_DIR)/%.md
|
||||||
|
mkdir -p $(shell dirname $@)
|
||||||
|
$(PANDOC_COMMAND) -i $< -o $@
|
||||||
|
|
||||||
|
serve:
|
||||||
|
python3 -m http.server --directory $(BUILD_DIR)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(BUILD_DIR) $(ENTRIES_LIST)
|
||||||
34
filters/blog_feed.py
Executable file
34
filters/blog_feed.py
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import csv
|
||||||
|
import panflute as pf
|
||||||
|
|
||||||
|
def action(elem, doc):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def finalize(doc):
|
||||||
|
keys = [
|
||||||
|
"git_date",
|
||||||
|
"git_initial_date",
|
||||||
|
"title",
|
||||||
|
"subject",
|
||||||
|
"path",
|
||||||
|
"base_url",
|
||||||
|
"feed_list_path",
|
||||||
|
]
|
||||||
|
rss_data = {}
|
||||||
|
for k in keys:
|
||||||
|
rss_data[k] = doc.get_metadata(k, "")
|
||||||
|
feed_list_path = rss_data["feed_list_path"]
|
||||||
|
path = rss_data["base_url"] + rss_data["path"]
|
||||||
|
rss_data["path"] = path
|
||||||
|
del rss_data["feed_list_path"]
|
||||||
|
del rss_data["base_url"]
|
||||||
|
with open(feed_list_path, "a") as file:
|
||||||
|
writer = csv.DictWriter(file, fieldnames=keys[:-2])
|
||||||
|
writer.writerow(rss_data)
|
||||||
|
|
||||||
|
def main(doc=None):
|
||||||
|
return pf.run_filter(action, finalize=finalize, doc=doc)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
11
metadata.yaml
Normal file
11
metadata.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
title: Personal Site
|
||||||
|
subtitle: Foo Bar
|
||||||
|
global_links:
|
||||||
|
- name: Index
|
||||||
|
uri: /
|
||||||
|
- name: Contact
|
||||||
|
uri: /contact.html
|
||||||
|
- name: Blog
|
||||||
|
uri: /blog
|
||||||
|
feed_list_path: .entries.csv
|
||||||
|
base_url: http://localhost:8000
|
||||||
59
scripts/entries2rss.py
Executable file
59
scripts/entries2rss.py
Executable file
@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from sys import stdin, argv
|
||||||
|
from csv import DictReader
|
||||||
|
import panflute as pf
|
||||||
|
import yaml
|
||||||
|
from yaml.loader import SafeLoader
|
||||||
|
|
||||||
|
fieldnames = [
|
||||||
|
"git_date",
|
||||||
|
"git_initial_date",
|
||||||
|
"title",
|
||||||
|
"subject",
|
||||||
|
"path",
|
||||||
|
]
|
||||||
|
|
||||||
|
def entry_to_rss(entry):
|
||||||
|
return (
|
||||||
|
f'<item>\n'
|
||||||
|
f'<title>{entry["title"]}</title>\n'
|
||||||
|
f'<description>{entry.get("subtitle", "")}</description>\n'
|
||||||
|
f'<link>{entry["path"]}</link>\n'
|
||||||
|
f'<lastBuildDate>{entry["git_date"]}</lastBuildDate>\n'
|
||||||
|
f'<pubDate>{entry["git_initial_date"]}</pubDate>\n'
|
||||||
|
'</item>\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
def entry_to_html(entry):
|
||||||
|
date = entry["git_date"]
|
||||||
|
link = entry["path"]
|
||||||
|
title = entry["title"]
|
||||||
|
return (
|
||||||
|
f'<li>\n'
|
||||||
|
f'<a href="{link}">{date[:10]} - {title}</a>\n'
|
||||||
|
'</li>\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
reader = DictReader(stdin, fieldnames)
|
||||||
|
entries = [row for row in reader]
|
||||||
|
with open('metadata.yaml') as f:
|
||||||
|
metadata = yaml.load(f, Loader=SafeLoader)
|
||||||
|
if "html" in argv:
|
||||||
|
converter = entry_to_html
|
||||||
|
print("<ul>")
|
||||||
|
else:
|
||||||
|
converter = entry_to_rss
|
||||||
|
print('<?xml version="1.0" encoding="UTF-8" ?>\n<rss version="2.0">')
|
||||||
|
print("<channel>")
|
||||||
|
print("<title>", metadata["title"], "</title>")
|
||||||
|
print("<link>", metadata["base_url"], "</link>")
|
||||||
|
print("<description>", metadata.get("description", ""), "</description>")
|
||||||
|
for entry in entries:
|
||||||
|
print(converter(entry))
|
||||||
|
if "html" in argv:
|
||||||
|
print("</ul>")
|
||||||
|
else:
|
||||||
|
print("</channel></rss>")
|
||||||
|
|
||||||
6
src/blog/index.md
Normal file
6
src/blog/index.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Blog index
|
||||||
|
|
||||||
|
Welcome!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
39
src/index.md
Normal file
39
src/index.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Summos certamina vultibus carere
|
||||||
|
|
||||||
|
## Flagrans respiramen
|
||||||
|
|
||||||
|
Lorem markdownum aeris utinam! Paelex voce turbamque numen: corripe Bootes
|
||||||
|
*illa* iacere Caenis deceant prima Aeneia invitusque geminas? Sub rear cuspide,
|
||||||
|
regno populumque epops. Vox ullo Trachinia **tempora**, in sine fata in ultima
|
||||||
|
*precatur adspice* undas clamore, nos colle, tumulo; Cumarum.
|
||||||
|
|
||||||
|
1. Promittere hasta concutiuntque asper evehor
|
||||||
|
2. Non sanguine unam turba sit propositumque Turni
|
||||||
|
3. Da Meleagre subitam tutus incidit mutantur fratresque
|
||||||
|
|
||||||
|
## Densum si promissa responsa stamina patriumque fabrilis
|
||||||
|
|
||||||
|
Acrisioneas currus et rescierit aequor conlapsamque color quaeque ingeniosus
|
||||||
|
Erysicthone quidque et [crescit utque](#). Primordia et
|
||||||
|
inania, non *et*, densus quoque pater, est.
|
||||||
|
|
||||||
|
Praemia Patareaque etiamnum posset. Pes Delphis loquendo omnes.
|
||||||
|
|
||||||
|
## Auroram debilitaturum arcus animos urar amplexa mergeret
|
||||||
|
|
||||||
|
Quantaque non quos hinc Perseus cura similis damnosa pietasque quaeque pugnat,
|
||||||
|
et per quibus aconiton vertice spatium. Praebebat dat praesignis verba
|
||||||
|
exiguumque, ubi caput cecini propiore si in. Super pignora quoscumque sunt. Aevo
|
||||||
|
certum: Stygii nuntia, ille dolori invenit equosque gutture, vitae, et dignior,
|
||||||
|
et. Illa dictis erat, est enim contorta [adeste ipse](#), vos munus tum est e paterque
|
||||||
|
deprensa nomen celebrabant ac?
|
||||||
|
|
||||||
|
> Inplumes notavit micantes **hunc**, nec sanguine, cessant, an. Ubi mollia
|
||||||
|
> maerent et Syrtis vertice condebat faveant sit fugatas comites *lilia cum
|
||||||
|
> quam* nepotes, semper, barbarus.
|
||||||
|
|
||||||
|
Vota breve videbor: in dammas matrona lacus, nec vides saucius, nullamque.
|
||||||
|
Dubium pulsat fraxinus et, ter Philomela tectam maxima vertuntur saturae, iam ad
|
||||||
|
dignissime. Amens sine ista turbinis equorum Epaphus Iunonis
|
||||||
|
[supplex](#) duobus, tuta facit pendet medius. Paternum scorpius
|
||||||
|
aquarum per iter candentem parva et ramos urbs ubi.
|
||||||
3
templates/comment-section.html
Normal file
3
templates/comment-section.html
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<div class"comment-section">
|
||||||
|
<textarea></textarea>
|
||||||
|
</div>
|
||||||
75
templates/default.html
Normal file
75
templates/default.html
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="$lang$" xml:lang="$lang$"$if(dir)$ dir="$dir$"$endif$>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="generator" content="pandoc" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
||||||
|
$for(author-meta)$
|
||||||
|
<meta name="author" content="$author-meta$" />
|
||||||
|
$endfor$
|
||||||
|
$if(date-meta)$
|
||||||
|
<meta name="dcterms.date" content="$date-meta$" />
|
||||||
|
$endif$
|
||||||
|
$if(keywords)$
|
||||||
|
<meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
|
||||||
|
$endif$
|
||||||
|
$if(description-meta)$
|
||||||
|
<meta name="description" content="$description-meta$" />
|
||||||
|
$endif$
|
||||||
|
<title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
|
||||||
|
<style>
|
||||||
|
$styles.html()$
|
||||||
|
</style>
|
||||||
|
$for(css)$
|
||||||
|
<link rel="stylesheet" href="$css$" />
|
||||||
|
$endfor$
|
||||||
|
$for(header-includes)$
|
||||||
|
$header-includes$
|
||||||
|
$endfor$
|
||||||
|
$if(math)$
|
||||||
|
$math$
|
||||||
|
$endif$
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
$for(include-before)$
|
||||||
|
$include-before$
|
||||||
|
$endfor$
|
||||||
|
$if(title)$
|
||||||
|
<header id="title-block-header">
|
||||||
|
<h1 class="title">$title$</h1>
|
||||||
|
$if(subtitle)$
|
||||||
|
<p class="subtitle">$subtitle$</p>
|
||||||
|
$endif$
|
||||||
|
$for(author)$
|
||||||
|
<p class="author">$author$</p>
|
||||||
|
$endfor$
|
||||||
|
$if(date)$
|
||||||
|
<p class="date">$date$</p>
|
||||||
|
$endif$
|
||||||
|
$if(abstract)$
|
||||||
|
<div class="abstract">
|
||||||
|
<div class="abstract-title">$abstract-title$</div>
|
||||||
|
$abstract$
|
||||||
|
</div>
|
||||||
|
$endif$
|
||||||
|
</header>
|
||||||
|
$endif$
|
||||||
|
$if(toc)$
|
||||||
|
<nav id="$idprefix$TOC" role="doc-toc">
|
||||||
|
$if(toc-title)$
|
||||||
|
<h2 id="$idprefix$toc-title">$toc-title$</h2>
|
||||||
|
$endif$
|
||||||
|
$table-of-contents$
|
||||||
|
</nav>
|
||||||
|
$endif$
|
||||||
|
<main>
|
||||||
|
$body$
|
||||||
|
</main>
|
||||||
|
$for(include-after)$
|
||||||
|
$include-after$
|
||||||
|
$endfor$
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue
Block a user