refactor #1
5
.gitignore
vendored
5
.gitignore
vendored
@ -1 +1,6 @@
|
||||
shepich resume.pdf
|
||||
**/.venv
|
||||
**/.env
|
||||
tmp
|
||||
build
|
||||
dist
|
||||
BIN
__pycache__/main.cpython-312.pyc
Normal file
BIN
__pycache__/main.cpython-312.pyc
Normal file
Binary file not shown.
21
agenda.md
21
agenda.md
@ -1,21 +0,0 @@
|
||||
## Pages
|
||||
- Home
|
||||
- About
|
||||
- CV
|
||||
- Everything in as much detail as possible
|
||||
- Projects
|
||||
- E&E
|
||||
- M|Chroma
|
||||
- SI-Formatter
|
||||
- Socials (maybe better as a footer)
|
||||
- Instagram
|
||||
- Facebook
|
||||
- LinkedIn
|
||||
- GitHub
|
||||
- MAL
|
||||
- Bookmarks (?)
|
||||
|
||||
## Reference Material
|
||||
- https://www.tomscott.com/
|
||||
- http://vihart.com/
|
||||
- https://www.singingbanana.com/
|
||||
79
main.py
Normal file
79
main.py
Normal file
@ -0,0 +1,79 @@
|
||||
import os
|
||||
import subprocess
|
||||
import markdown
|
||||
import yaml
|
||||
from datetime import datetime
|
||||
|
||||
def filepath_or_string(s: str) -> str:
|
||||
'''Loads the contents of a string if it is a filepath, otherwise returns the string.'''
|
||||
if os.path.isfile(s):
|
||||
with open(s, 'r') as f:
|
||||
return f.read()
|
||||
else:
|
||||
return s
|
||||
|
||||
|
||||
def load_markdown(md: str) -> tuple[dict, str]:
|
||||
'''Loads a Markdown file into a (metadata: dict, content: str) pair.'''
|
||||
|
||||
# Load the file contents if a filepath is specified, and strip document delimiters ('---').
|
||||
md = filepath_or_string(md).strip().strip('---').strip()
|
||||
|
||||
# If there is no `---` delimiter, then the article has no metadata.
|
||||
if '---' not in md.strip('---'):
|
||||
return {}, md
|
||||
|
||||
# Split the metadata from the contents.
|
||||
[raw_metadata, raw_article] = md.split('---')
|
||||
|
||||
# Use YAML to parse the metadata.
|
||||
metadata = yaml.safe_load(raw_metadata)
|
||||
|
||||
# Convert the contents to a HTML string.
|
||||
content = markdown.markdown(raw_article)
|
||||
|
||||
return metadata, content
|
||||
|
||||
|
||||
def format_html_template(template: str, **kwargs) -> str:
|
||||
'''Interpolates variables specified as keyword arguments
|
||||
into the given HTML template.'''
|
||||
|
||||
# Load the template if a filepath is given.
|
||||
template = filepath_or_string(template)
|
||||
|
||||
# Interpolate the kwargs into the HTML template.
|
||||
html = template.format(**kwargs)
|
||||
|
||||
# Return the formatted HTML.
|
||||
return html
|
||||
|
||||
|
||||
REPOS = [
|
||||
'ssh://gitea/jim/resume.git',
|
||||
'ssh://gitea/jim/dogma-jimfinium.git'
|
||||
]
|
||||
run = lambda cmd: subprocess.run(cmd.split(' '), stdout = subprocess.PIPE, stderr = subprocess.PIPE)
|
||||
def update_git_repos(repos: list) -> None:
|
||||
'''Pulls updates to repos in the build directory, or clones them if they don't exist.'''
|
||||
for repo in repos:
|
||||
local_path = 'build/'+repo.split('/')[-1].strip('.git')
|
||||
print(local_path)
|
||||
if os.path.exists(f'{local_path}/.git'):
|
||||
run(f'git -C {local_path} pull origin')
|
||||
else:
|
||||
run(f'git clone {repo} {local_path}')
|
||||
|
||||
|
||||
def load_partials() -> dict:
|
||||
"""Loads partial templates from the templates/partials directory."""
|
||||
partials = {}
|
||||
for filename in os.listdir('templates/partials'):
|
||||
with open(f'templates/partials/{filename}') as partial_file:
|
||||
partial_template = partial_file.read()
|
||||
|
||||
partials[f'partials__{os.path.splitext(filename)[0]}'] = format_html_template(
|
||||
partial_template,
|
||||
current_year = datetime.now().year
|
||||
)
|
||||
return partials
|
||||
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@ -0,0 +1,3 @@
|
||||
ipykernel
|
||||
markdown
|
||||
pyyaml
|
||||
23
templates/default.html
Normal file
23
templates/default.html
Normal file
@ -0,0 +1,23 @@
|
||||
<html>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<head>
|
||||
{partials__default_css}
|
||||
{partials__header}
|
||||
{partials__nav}
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
<article>
|
||||
<h1 class="headline">{metadata__title}</h1>
|
||||
<p class="byline">
|
||||
<address class="author">By <a rel="author" href="mailto:admin@jimlab.io">Jim Shepich III</a></address>
|
||||
<br/>First published: <time pubdate datetime="{metadata__date}">{metadata__date}</time>
|
||||
<br/>Last modified: <time pubdate datetime="{metadata__lastmod}">{metadata__lastmod}</time>
|
||||
</p>
|
||||
{content}
|
||||
</article>
|
||||
{partials__footer}
|
||||
</body>
|
||||
0
templates/partials/blog_article.html
Normal file
0
templates/partials/blog_article.html
Normal file
4
templates/partials/default_css.html
Normal file
4
templates/partials/default_css.html
Normal file
@ -0,0 +1,4 @@
|
||||
<link rel="stylesheet" type="text/css" href="/assets/css/reset.css">
|
||||
<link rel="stylesheet" type="text/css" href="/assets/css/common.css">
|
||||
<link rel="stylesheet" type="text/css" href="/assets/css/layout.css">
|
||||
<link rel="stylesheet" type="text/css" href="/assets/css/theme.css">
|
||||
3
templates/partials/footer.html
Normal file
3
templates/partials/footer.html
Normal file
@ -0,0 +1,3 @@
|
||||
<footer>
|
||||
<br /><span class='copyright'>Copyright © 2021-{current_year} Jim Shepich</span>
|
||||
</footer>
|
||||
3
templates/partials/header.html
Normal file
3
templates/partials/header.html
Normal file
@ -0,0 +1,3 @@
|
||||
<header id="main-header" class="no-highlight">
|
||||
<span class="silver-text">Jimlab</span>
|
||||
</header>
|
||||
4
templates/partials/nav.html
Normal file
4
templates/partials/nav.html
Normal file
@ -0,0 +1,4 @@
|
||||
<nav id="main-navbar" class="no-highlight">
|
||||
<a href='/home.html' target='_self'><div class='nav-tab'><span class='nav-text'>Home</span></div></a>
|
||||
<a href='/shepich_resume.pdf' target='blank'><div class='nav-tab'><span class='nav-text'>Resume</span></div></a>
|
||||
</nav>
|
||||
142
testbench.ipynb
Normal file
142
testbench.ipynb
Normal file
@ -0,0 +1,142 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "dda60de8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Roadmap\n",
|
||||
"\n",
|
||||
"- [x] Load markdown\n",
|
||||
"- [] Determine static website structure\n",
|
||||
" - Where to put assets for subsites like dogma jimfinium\n",
|
||||
" - How to otherwise organize pages\n",
|
||||
"- [] Resolve markdown links\n",
|
||||
"- [] Consider separating article templates and overall page templates\n",
|
||||
"- [] RSS feed\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"WEBROOT\n",
|
||||
"- assets\n",
|
||||
"- main pages\n",
|
||||
"- resume\n",
|
||||
"- dogma-jimfinium/\n",
|
||||
" - assets/\n",
|
||||
" - pages"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "207d2510",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"import markdown\n",
|
||||
"import yaml\n",
|
||||
"import subprocess\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"from datetime import datetime\n",
|
||||
"from main import *"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "d2361c42",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"metadata, content = load_markdown('tmp/dogma-jimfinium/blowouts.md')\n",
|
||||
"content = content.replace('src=\"assets', 'src=\"../tmp/dogma-jimfinium/assets')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "ed7b3b2f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"PARTIALS = load_partials()\n",
|
||||
"html = format_html_template('templates/default.html', content = content, **{'metadata__'+k:v for k,v in metadata.items()}, **PARTIALS)\n",
|
||||
"with open('dist/home.html', 'w') as f:\n",
|
||||
" f.write(html)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b8c87620",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "57383c24",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"2025-12-01\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"CompletedProcess(args=['cp', 'build/resume/2025-12-01/shepich_resume.pdf', 'dist/shepich_resume.pdf'], returncode=0, stdout=b'', stderr=b'')"
|
||||
]
|
||||
},
|
||||
"execution_count": 170,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def get_latest_resume():\n",
|
||||
" max_date = '0000-00-00'\n",
|
||||
" for resume_folder in os.listdir('build/resume'):\n",
|
||||
" try:\n",
|
||||
" datetime.strptime(resume_folder,'%Y-%m-%d')\n",
|
||||
" except Exception:\n",
|
||||
" continue\n",
|
||||
" \n",
|
||||
" if resume_folder > max_date:\n",
|
||||
" max_date = resume_folder\n",
|
||||
" \n",
|
||||
"\n",
|
||||
" print(max_date)\n",
|
||||
" # print(max_date.strftime('%Y-%m-%d'))\n",
|
||||
" \n",
|
||||
" run(f'cp build/resume/{max_date}/shepich_resume.pdf dist/shepich_resume.pdf')"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user