catcrafts.net/implementations/Catcrafts-Blog.cpp

82 lines
2.8 KiB
C++
Raw Normal View History

2025-11-12 20:58:07 +01:00
/*
catcrafts.net
Copyright (C) 2026 Catcrafts
2025-11-12 20:58:07 +01:00
The source code of this website is made available for viewing purposes only.
2025-11-12 20:58:07 +01:00
No permission is granted to copy, modify, distribute, or create derivative works.
*/
export module Catcrafts:Blog_impl;
import :Blog;
2025-11-12 21:56:18 +01:00
import :Root;
import :Views;
import Crafter.Graphics;
2025-11-12 20:58:07 +01:00
import std;
using namespace Crafter;
2025-11-12 21:56:18 +01:00
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<Dom::HtmlElementPtr> blogButtons;
2025-11-12 21:56:18 +01:00
void RenderBlog() {
2025-11-14 23:56:39 +01:00
blogButtons.clear();
2025-11-12 20:58:07 +01:00
std::string html = "";
2025-11-14 23:56:39 +01:00
for(const BlogPost& post : posts) {
2025-11-12 21:56:18 +01:00
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) + "...";
}
}
2025-11-12 21:24:23 +01:00
html += std::format(R"(
2025-11-12 22:11:56 +01:00
<div class="post fade-in" id="blog-post-{}">
2025-11-12 21:24:23 +01:00
<div class="post-header">
2025-11-12 21:56:18 +01:00
<h2 class="post-title"><a>{}</a></h2>
2025-11-12 21:24:23 +01:00
<span class="post-date">{}</span>
</div>
<div class="post-content">
{}
</div>
2025-11-12 21:56:18 +01:00
<div class="post-footer">
2025-11-12 22:11:56 +01:00
<a class="btn">Read Full Post</a>
2025-11-12 21:56:18 +01:00
</div>
2025-11-12 22:11:56 +01:00
</div>)", post.slug, post.name, post.date, previewContent);
2025-11-12 20:58:07 +01:00
}
MainContent().SetInnerHTML(std::format(R"(<div class="blog-posts">{}</div>)", html));
2025-11-12 21:56:18 +01:00
2025-11-14 23:56:39 +01:00
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));
2025-11-12 21:56:18 +01:00
RenderRoot(std::format("/blog/{}", slug));
});
}
}
2025-11-12 21:56:18 +01:00
void RenderBlogPost(const std::string_view slug) {
2025-11-14 23:56:39 +01:00
for(const BlogPost& post : posts) {
2025-11-12 21:56:18 +01:00
if(post.slug == slug) {
MainContent().SetInnerHTML(std::format(R"(
2025-11-12 22:40:33 +01:00
<div class="blog-post-page">
2025-11-12 21:56:18 +01:00
<div class="post-header">
<h1 class="post-title">{}</h1>
<span class="post-date">{}</span>
</div>
<div class="post-content">
{}
</div>
</div>)", post.name, post.date, post.content));
return;
}
}
MainContent().SetInnerHTML("<h1>Post Not Found</h1><p>The requested blog post could not be found.</p>");
2025-11-12 20:58:07 +01:00
}
}