Index

joshstock.in / ac5912b

Source for serving and static templating/compiling of https://joshstock.in.

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
15814 Jan 2023 23:375aaa26aWebsite rewriteJosh Stockin11940G

Blob @ joshstock.in / site / targets.py

application/x-python6875 bytesdownload raw
1# targets.py / Template engine for my website
2# Joshua Stockin / josh@joshstock.in / https://joshstock.in
3
4import os
5import html
6from datetime import datetime, timezone, timedelta
7
8import markdown2
9import htmlgenerator as hg
10import readtime
11import sass
12from feedgen.feed import FeedGenerator
13
14from _utils import dotdict as namespace, current_dir, load_generators, list_files
15
16# Site generation metadata
17CONTENT_DIRECTORY = os.path.join(current_dir(), "content")
18SASS_DIRECTORY = os.path.join(current_dir(), "style")
19STATIC_DIRECTORY = os.path.join(current_dir(), "static")
20
21blog_description = "Barely coherent ramblings about engineering projects, software, hardware, and other things."
22
23# Fetch generator functions
24GENERATORS_MODULE = "generators"
25GENERATORS = [
26 "head.head",
27 "header",
28 "footer",
29 "blog.article",
30 "blog.index",
31 "blog.listing",
32]
33
34generate = load_generators(GENERATORS_MODULE, GENERATORS)
35
36# Site template implementation; returns dict {filename: data}
37def template() -> {str: str}:
38 files = {}
39
40 articles_list = []
41 fg = FeedGenerator()
42 fg.id("https://joshstock.in/blog")
43 fg.title("Blog - Josh Stockin")
44 fg.author({"name": "Josh Stockin", "email": "josh@joshstock.in", "uri": "https://joshstock.in"})
45 fg.link(href="https://joshstock.in/blog", rel="alternate")
46 fg.subtitle(blog_description)
47 fg.link(href="https://joshstock.in/atom", rel="self")
48 fg.language("en")
49
50 for content_file in list_files(CONTENT_DIRECTORY, ".md"):
51 f = open(content_file, "r")
52 data = f.read()
53 f.close()
54
55 content_html = markdown2.markdown(
56 data,
57 safe_mode=False,
58 extras=[
59 "code-friendly",
60 "cuddled-lists",
61 "fenced-code-blocks",
62 "footnotes",
63 "header-ids",
64 "metadata",
65 "strike",
66 "tables",
67 "wiki-tables",
68 "tag-friendly",
69 "target-blank-links",
70 ],
71 )
72
73 page_data = namespace(content_html.metadata)
74
75 page_data.link = page_data.link or ""
76
77 if page_data.type == "website":
78 page_generator = hg.HTML(
79 generate("head.head", page_data),
80 hg.BODY(
81 *generate("header", page_data),
82 hg.DIV(
83 hg.DIV(hg.mark_safe(content_html), _class="content-body"),
84 hg.DIV(_class="vfill"),
85 generate("footer"),
86 _class="content-container",
87 ),
88 onscroll="scroll()",
89 ),
90 )
91 files[page_data.index] = hg.render(page_generator, {}).encode("utf-8")
92
93 elif page_data.type == "article": # Blog article handling
94 page_data.readtime = readtime.of_html(content_html, wpm=150)
95 page_data.thumbnail = page_data.banner_image
96 page_data.link = "/blog/" + page_data.identifier
97 page_data.links = page_data.links or {}
98 articles_list += [generate("blog.listing", page_data)]
99 page_data.content = content_html
100
101 fe = fg.add_entry()
102 fe.id("https://joshstock.in/blog/" + page_data.identifier)
103 fe.author({"name": "Josh Stockin", "email": "josh@joshstock.in", "uri": "https://joshstock.in"})
104 fe.title(page_data.title)
105 fe.summary(page_data.description + " / https://joshstock.in/blog/" + page_data.identifier)
106 datetime_pub = datetime.strptime(page_data.datestring, "%Y-%m-%d").replace(tzinfo=timezone(-timedelta(hours=6)))
107 fe.published(datetime_pub)
108 fe.updated(datetime_pub)
109 fe.link(href="https://joshstock.in/blog/" + page_data.identifier)
110
111 page_generator = hg.HTML(
112 generate("head.head", page_data),
113 hg.BODY(
114 *generate("header", page_data),
115 hg.DIV(
116 hg.DIV(
117 *generate("blog.article", page_data), _class="content-body"
118 ),
119 hg.DIV(_class="vfill"),
120 generate("footer"),
121 _class="content-container",
122 ),
123 onscroll="scroll()",
124 ),
125 )
126
127 files["blog/" + page_data.identifier + ".html"] = hg.render(
128 page_generator, {}
129 ).encode("utf-8")
130
131 # Create blog index page
132 blog_page_data = namespace(
133 title="Blog",
134 banner_image="",
135 thumbnail="",
136 link="/blog",
137 description=fg.subtitle(),
138 )
139 blog_page_generator = hg.HTML(
140 generate("head.head", blog_page_data),
141 hg.BODY(
142 *generate("header", blog_page_data),
143 hg.DIV(
144 hg.DIV(
145 hg.DIV(
146 hg.H1("Blog ", hg.IMG(src="/static/svg/memo.svg", _class="inline svg")),
147 hg.P(
148 fg.subtitle(), hg.BR(),
149 hg.SPAN("[", hg.A("Atom feed", href="/atom"), "] ", style="font-size: 0.75em; color: var(--caption-color)"),
150 hg.SPAN("[", hg.A("RSS feed", href="/rss"), "]", style="font-size: 0.75em; color: var(--caption-color)")
151 )
152 ),
153 *articles_list,
154 _class="content-body",
155 ),
156 hg.DIV(_class="vfill"),
157 generate("footer"),
158 _class="content-container",
159 ),
160 onscroll="scroll()",
161 ),
162 )
163 files["blog.html"] = hg.render(blog_page_generator, {}).encode("utf-8")
164
165 # Feeds
166 files["atom.xml"] = fg.atom_str(pretty=True)
167 fg.link(href="https://joshstock.in/rss", rel="self", replace=True)
168 files["rss.xml"] = fg.rss_str(pretty=True)
169
170 # Compile Sass stylesheets
171 for stylesheet_file in list_files(SASS_DIRECTORY, ".scss"):
172 if os.path.basename(stylesheet_file)[0] != "_":
173 files[
174 os.path.join(
175 "static",
176 "style",
177 os.path.splitext(os.path.relpath(stylesheet_file, SASS_DIRECTORY))[
178 0
179 ]
180 + ".css",
181 )
182 ] = sass.compile(filename=stylesheet_file, output_style="compressed").encode("utf-8")
183
184 # Copy content from static files
185 for static_file in list_files(STATIC_DIRECTORY):
186 f = open(static_file, "rb")
187 data = f.read()
188 f.close()
189
190 files[
191 os.path.join("static", os.path.relpath(static_file, STATIC_DIRECTORY))
192 ] = data
193
194 return files
195