/* catcrafts.net Copyright (C) 2026 Catcrafts The source code of this website is made available for viewing purposes only. No permission is granted to copy, modify, distribute, or create derivative works. */ export module Catcrafts:Blog_impl; import :Blog; import :Root; import :Views; import Crafter.Graphics; import std; using namespace Crafter; export namespace Catcrafts { // Persistent storage for the per-post card click handlers. HtmlElementPtr // unregisters its listeners on destruction, so the elements have to // outlive Render(); clear() at the top of RenderBlog() detaches the // previous render's handlers before we attach the new ones. std::vector blogButtons; void RenderBlog() { blogButtons.clear(); std::string html = ""; for(const BlogPost& post : posts) { std::string previewContent = post.content; if(previewContent.length() > 200) { std::size_t lastSpace = previewContent.find_last_of(' ', 200); if(lastSpace != std::string::npos) { previewContent = previewContent.substr(0, lastSpace) + "..."; } else { previewContent = previewContent.substr(0, 200) + "..."; } } html += std::format(R"(

{}

{}
)", post.slug, post.name, post.date, previewContent); } MainContent().SetInnerHTML(std::format(R"(
{}
)", html)); for(const BlogPost& post : posts) { Dom::HtmlElementPtr& cardView = blogButtons.emplace_back(std::format("blog-post-{}", post.slug)); cardView.AddClickListener([slug = post.slug](Dom::MouseEvent) { Router::PushState("{}", "", std::format("/blog/{}", slug)); RenderRoot(std::format("/blog/{}", slug)); }); } } void RenderBlogPost(const std::string_view slug) { for(const BlogPost& post : posts) { if(post.slug == slug) { MainContent().SetInnerHTML(std::format(R"(

{}

{}
)", post.name, post.date, post.content)); return; } } MainContent().SetInnerHTML("

Post Not Found

The requested blog post could not be found.

"); } }