Building sites with vanilla HTML can be a pain in the ass if you want to redesign an element that appears in every page, like a navigation bar or footer. Static site generators solve this problem with components, but I like reinventing the wheel. Jinja templating can be used to ape components since it is capable of passing arbitrary functions into its DOM templates.
# ssg.py
def blog_footer():
return """
<footer>
<p>
<a href="/blog/feed.xml">Feed</a> -
<a
href="https://github.com/pavo-etc/pavo-etc.github.io/tree/master/generator"
>ironprof</a
>
</p>
</footer>"""
page_template = jinja2.Template(open("template.html", "r").read())
with open("output.html"), "w") as f:
f.write(page_template.render({
"blog_footer":blog_footer
}))
<!-- template.html -->
<!DOCTYPE html>
<html>
<body>
{{ blog_footer() }}
</body>
</html>
<!-- output.html -->
<!DOCTYPE html>
<html>
<body>
<footer>
<p>
<a href="/blog/feed.xml">Feed</a> -
<a
href="https://github.com/pavo-etc/pavo-etc.github.io/tree/master/generator"
>ironprof</a
>
</p>
</footer>
</body>
</html>
This follows normal Python rules, so inheritance is followed and parameters can be passed into functions in the template.
# components.py
def nav(activated_link):
links = ["projects", "blog"]
link_elements = []
for link in links:
is_active = ' activated-link' if activated_link == link else ''
link_elements.append(f' <a href="/{link}/" class="discrete-link{is_active}">{link.capitalize()}</a>')
right_links_str = '\n'.join(link_elements)
is_root_active = ' activated-link' if activated_link == '.' else ''
return f"""
<nav>
<div class="flex">
<div class="flex-left">
<a href="/" class="discrete-link{is_root_active}">Zach Manson</a>
</div>
<div class="flex-right">
{right_links_str}
</div>
</div>
</nav>"""
def blog_footer():
return """
<footer>
<p>
<a href="/blog/feed.xml">Feed</a> -
<a
href="https://github.com/pavo-etc/pavo-etc.github.io/tree/master/generator"
>ironprof</a
>
</p>
</footer>"""
# ssg.py
import components
page_template = jinja2.Template(open("template.html", "r").read())
with open("output.html"), "w") as f:
f.write(page_template.render({
"components":components
}))
<!-- template.html -->
<!DOCTYPE html>
<html>
<body>
{{ components.nav("blog")}}
<p>Lorem ipsum amirite</p>
{{ components.blog_footer() }}
</body>
</html>
<!-- outputs.html -->
<!DOCTYPE html>
<html>
<body>
<nav>
<div class="flex">
<div class="flex-left">
<a href="/" class="discrete-link">Zach Manson</a>
</div>
<div class="flex-right">
<a href="/projects/" class="discrete-link">Projects</a>
<a href="/blog/" class="discrete-link activated-link">Blog</a>
</div>
</div>
</nav>
<p>Lorem ipsum amirite</p>
<footer>
<p>
<a href="/blog/feed.xml">Feed</a> -
<a
href="https://github.com/pavo-etc/pavo-etc.github.io/tree/master/generator"
>ironprof</a
>
</p>
</footer>
</body>
</html>