Template mapping

This commit is contained in:
Jim Shepich III 2026-01-31 04:11:23 -05:00
parent bf0ca26a71
commit 14a9e1c504
9 changed files with 500 additions and 187 deletions

View File

@ -1,4 +1,5 @@
author: Jim Shepich III author: Jim Shepich III
templates_folder: ./templates
site_defaults: site_defaults:
base_url: http://localhost:8000 base_url: http://localhost:8000
web_root: ./dist web_root: ./dist

View File

@ -7,6 +7,12 @@ import yaml
import pydantic import pydantic
from typing import Optional from typing import Optional
from datetime import datetime, date from datetime import datetime, date
from dotmap import DotMap
class GlobalVars(pydantic.BaseModel):
'''Static-valued global variables to be interpolated into any HTML templates.'''
today: date = datetime.today()
def filepath_or_string(s: str) -> str: def filepath_or_string(s: str) -> str:
'''Loads the contents of a string if it is a filepath, otherwise returns the string.''' '''Loads the contents of a string if it is a filepath, otherwise returns the string.'''
@ -69,7 +75,11 @@ def format_html_template(template: str, **kwargs) -> str:
template = filepath_or_string(template) template = filepath_or_string(template)
# Interpolate the kwargs into the HTML template. # Interpolate the kwargs into the HTML template.
html = template.format(**kwargs) # Apply global variables twice in case a partial used
# by the first call of .format() uses a variable.
html = template.format(
globalvars = GlobalVars(), **kwargs
).format(globalvars = GlobalVars())
# Return the formatted HTML. # Return the formatted HTML.
return html return html
@ -91,7 +101,7 @@ def load_partials() -> dict:
with open(f'templates/partials/{filename}') as partial_file: with open(f'templates/partials/{filename}') as partial_file:
partial_template = partial_file.read() partial_template = partial_file.read()
partials[f'partials__{os.path.splitext(filename)[0]}'] = format_html_template( partials[f'partials.{os.path.splitext(filename)[0]}'] = format_html_template(
partial_template, partial_template,
current_year = datetime.now().year current_year = datetime.now().year
) )
@ -193,5 +203,74 @@ def copy_assets(site: SiteConfig):
return None return None
def build_index(site: SiteConfig) -> dict:
'''Loads the sites articles into an index mapping the filename stem
to a (metadata: dict, content: str) tuple.'''
index = {}
# Expand any globbed expressions.
expanded_article_list = []
for a in site.articles:
expanded_article_list.extend(
# Article paths are defined relative to the build cache; construct the full path.
glob.glob(f'{site.build_cache}/{a.lstrip("/")}')
)
for article in expanded_article_list:
metadata, content = load_markdown(article)
# Skip unpublished articles.
if not metadata.published:
continue
article_filestem = os.path.splitext(os.path.basename(article))[0]
index[article_filestem] = (metadata, content)
return index
def map_templates(dir: str, parent = '') -> DotMap:
'''Recursively maps the templates directory into a nested dict structure.
Leaves map the filestems of .html template files to their contents.
'''
output = {}
# List the files and subdirectories at the top level.
for sub in os.listdir(os.path.join(parent,dir)):
# Construct the full path to the file or subdir from the root of the tree.
full_path = os.path.join(parent,dir,sub)
# Recursively map subdirectories.
if os.path.isdir(full_path):
output[sub] = map_templates(sub, parent = dir)
continue
# Templates must be .html files.
filestem, ext = os.path.splitext(sub)
if ext != '.html':
continue
# Load template file.
with open(full_path, 'r') as file:
html = file.read()
# # Interpolate global variables into partials.
# if 'partials' in full_path:
# html = html.format(globalvars = GlobalVars())
output[filestem] = html
return DotMap(output)
if __name__ == '__main__': if __name__ == '__main__':
pass pass

View File

@ -1,4 +1,5 @@
ipykernel ipykernel
markdown markdown
pyyaml pyyaml
rfeed rfeed
dotmap

View File

@ -8,6 +8,7 @@
/*https://www.schemecolor.com/light-silver-gradient.php)*/ /*https://www.schemecolor.com/light-silver-gradient.php)*/
--navy-blue:#091b75; --navy-blue:#091b75;
--azure:#4f67db; --azure:#4f67db;
--azure-tint-20: #6e87e5;
--charcoal:#333333; --charcoal:#333333;
font-size:120%; font-size:120%;
@ -22,47 +23,47 @@
@font-face { @font-face {
font-family: Beleren; font-family: Beleren;
src: url('fonts/Beleren-Bold.ttf'); src: url('/assets/fonts/Beleren-Bold.ttf');
} }
@font-face { @font-face {
font-family: Playbill; font-family: Playbill;
src: url('fonts/Playbill.ttf'); src: url('/assets/fonts/Playbill.ttf');
} }
@font-face { @font-face {
font-family: Moderna; font-family: Moderna;
src: url('fonts/MODERNA_.ttf'); src: url('/assets/fonts/MODERNA_.ttf');
} }
@font-face { @font-face {
font-family: Adventure; font-family: Adventure;
src: url('fonts/Adventure.ttf'); src: url('/assets/fonts/Adventure.ttf');
} }
@font-face { @font-face {
font-family: Oxygen; font-family: Oxygen;
src: url('fonts/OxygenMono-Regular.ttf'); src: url('/assets/fonts/OxygenMono-Regular.ttf');
} }
@font-face { @font-face {
font-family: Garamond; font-family: Garamond;
src: url('fonts/EBGaramond.ttf'); src: url('/assets/fonts/EBGaramond.ttf');
} }
@font-face { @font-face {
font-family: Fira; font-family: Fira;
src: url('fonts/FiraSans-Regular.ttf'); src: url('/assets/fonts/FiraSans-Regular.ttf');
} }
@font-face { @font-face {
font-family: StitchWarrior; font-family: StitchWarrior;
src: url('fonts/StitchWarrior demo.ttf'); src: url('/assets/fonts/StitchWarrior demo.ttf');
} }
@font-face { @font-face {
font-family: Floral; font-family: Floral;
src: url('fonts/FloralCapitals.ttf'); src: url('/assets/fonts/FloralCapitals.ttf');
} }
var{ var{

View File

@ -2,9 +2,9 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<head> <head>
{partials__default_css} {partials.default_css}
{partials__header} {partials.header}
{partials__nav} {partials.nav}
</head> </head>
<body> <body>
<main> <main>
@ -18,5 +18,5 @@
{content} {content}
</article> </article>
</main> </main>
{partials__footer} {partials.footer}
</body> </body>

View File

@ -2,13 +2,13 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<head> <head>
{partials__default_css} {partials.default_css}
{partials__header} {partials.header}
{partials__nav} {partials.nav}
</head> </head>
<body> <body>
<main> <main>
{content} {content}
</main> </main>
{partials__footer} {partials.footer}
</body> </body>

View File

@ -1,3 +1,3 @@
<footer> <footer>
<br /><span class='copyright'>Copyright &copy; 2021-{current_year} Jim Shepich</span> <br /><span class='copyright'>Copyright &copy; 2021-{globalvars.today.year} Jim Shepich</span>
</footer> </footer>

View File

@ -2,13 +2,13 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<head> <head>
{partials__default_css} {partials.default_css}
{partials__header} {partials.header}
{partials__nav} {partials.nav}
</head> </head>
<body> <body>
<main> <main>
{content} {content}
</main> </main>
{partials__footer} {partials.footer}
</body> </body>

File diff suppressed because one or more lines are too long