Commit 3de17dec49
Verified · cmc
Layout: unified · split
build.py +55 −8
| @@ -183,13 +183,16 @@ def get_recent_posts_html(content_dir="./content/blog", num_posts=3): | ||
| 183 | 183 | |
| 184 | 184 | # Build HTML lines |
| 185 | 185 | lines = [] |
| 186 | current_year = None | |
| 186 | 187 | for post in recent: |
| 187 | lines.append('\t<div class="post">') | |
| 188 | lines.append( | |
| 189 | f'\t\t<time datetime="{post["date_str"]}">{post["date_full"]}</time>' | |
| 190 | ) | |
| 191 | lines.append(f'\t\t\t<a href="/blog/{post["slug"]}.html">{post["title"]}</a>') | |
| 192 | lines.append("\t</div>") | |
| 188 | year = post["date_obj"].year | |
| 189 | if year != current_year: | |
| 190 | current_year = year | |
| 191 | lines.append(f'\t<li class="post-list-year">{year}</li>') | |
| 192 | lines.append('\t<li class="post-list-item">') | |
| 193 | lines.append(f'\t\t<a href="/blog/{post["slug"]}.html">{post["title"]}</a>') | |
| 194 | lines.append(f'\t\t<time datetime="{post["date_str"]}">{post["date_full"]}</time>') | |
| 195 | lines.append("\t</li>") | |
| 193 | 196 | |
| 194 | 197 | return "\n".join(lines) |
| 195 | 198 | |
| @@ -259,12 +262,12 @@ def run_emacs_publish(dev_mode=True): | ||
| 259 | 262 | print(result.stderr, file=sys.stderr) |
| 260 | 263 | sys.exit(1) |
| 261 | 264 | |
| 262 | annoying_file = Path(".build/cleberg-net.html") | |
| 265 | annoying_file = Path(".build/seijaku.html") | |
| 263 | 266 | if annoying_file.exists(): |
| 264 | 267 | os.remove(annoying_file) |
| 265 | 268 | else: |
| 266 | 269 | print( |
| 267 | "Warning: .build/cleberg-net.html not found, but Emacs exited successfully." | |
| 270 | "Warning: .build/seijaku.html not found, but Emacs exited successfully." | |
| 268 | 271 | ) |
| 269 | 272 | |
| 270 | 273 | |
| @@ -336,6 +339,48 @@ def generate_sitemap(build_dir=".build", base_url="https://cleberg.net"): | ||
| 336 | 339 | print(f"Sitemap generated at {sitemap_path} with {len(sitemap_entries)} entries.") |
| 337 | 340 | |
| 338 | 341 | |
| 342 | def inject_blog_year_separators(blog_index_path="./.build/blog/index.html"): | |
| 343 | """ | |
| 344 | Post-processes the rendered blog index to inject year separator <li> elements | |
| 345 | between groups of posts. Weblorg/templatel doesn't support mutable loop state, | |
| 346 | so this runs after the HTML is generated. | |
| 347 | ||
| 348 | Finds each <li class="post-list-item"> that contains a <time datetime="YYYY-MM-DD">, | |
| 349 | and inserts <li class="post-list-year">YYYY</li> before the first post of each year. | |
| 350 | """ | |
| 351 | path = Path(blog_index_path) | |
| 352 | if not path.exists(): | |
| 353 | print(f"Warning: {blog_index_path} not found, skipping year separators.") | |
| 354 | return | |
| 355 | ||
| 356 | content = path.read_text(encoding="utf-8") | |
| 357 | ||
| 358 | # Match each post list item, capturing the date and the full element | |
| 359 | item_pattern = re.compile( | |
| 360 | r'(<li class="post-list-item">.*?</li>)', | |
| 361 | re.DOTALL, | |
| 362 | ) | |
| 363 | date_pattern = re.compile(r"datetime=['\"]?(\d{4})-\d{2}-\d{2}['\"]?") | |
| 364 | ||
| 365 | current_year = None | |
| 366 | def replace_item(m): | |
| 367 | nonlocal current_year | |
| 368 | item_html = m.group(1) | |
| 369 | date_match = date_pattern.search(item_html) | |
| 370 | if not date_match: | |
| 371 | return item_html | |
| 372 | year = date_match.group(1) | |
| 373 | if year != current_year: | |
| 374 | current_year = year | |
| 375 | separator = f'<li class="post-list-year">{year}</li>' | |
| 376 | return f"{separator}\n{item_html}" | |
| 377 | return item_html | |
| 378 | ||
| 379 | new_content = item_pattern.sub(replace_item, content) | |
| 380 | path.write_text(new_content, encoding="utf-8") | |
| 381 | print(f"Blog year separators injected into {blog_index_path}") | |
| 382 | ||
| 383 | ||
| 339 | 384 | def deploy_to_server(build_dir, server): |
| 340 | 385 | remote_path = f"{server}:/var/www/cleberg.net/" |
| 341 | 386 | print(f"Deploying .build/ → {remote_path}") |
| @@ -384,6 +429,7 @@ def main(): | ||
| 384 | 429 | run_emacs_publish(dev_mode=False) |
| 385 | 430 | copy_org_sources() |
| 386 | 431 | update_index_html(html_snippet) |
| 432 | inject_blog_year_separators() | |
| 387 | 433 | minify_html("./.build/index.html", "./.build/index.html") |
| 388 | 434 | generate_sitemap() |
| 389 | 435 | if deploy: |
| @@ -398,6 +444,7 @@ def main(): | ||
| 398 | 444 | run_emacs_publish(dev_mode=True) |
| 399 | 445 | copy_org_sources() |
| 400 | 446 | update_index_html(html_snippet) |
| 447 | inject_blog_year_separators() | |
| 401 | 448 | minify_html("./.build/index.html", "./.build/index.html") |
| 402 | 449 | generate_sitemap() |
| 403 | 450 | if deploy: |