Index

joshstock.in / ca03566

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

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
16822 Jan 2023 10:360f630e2Update footerJosh Stockin153G

Blob @ joshstock.in / site / targets.py

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