diff --git a/README.md b/README.md index d4104cf..7f93498 100644 --- a/README.md +++ b/README.md @@ -1,78 +1,54 @@ # catcrafts.net -A modern, responsive website built with C++ using Crafter.CppDOM and compiled to WebAssembly. +This is the source code for catcrafts.net, a website built entirely in C++ using the Crafter.CppDOM library. ## Features -- Modern, clean design with gradient colors and smooth animations -- Fully responsive layout that works on mobile and desktop -- Blog functionality with multiple posts -- Smooth navigation and transitions -- Semantic HTML structure -- Custom CSS with modern styling techniques +- **Responsive Design**: Works on all device sizes +- **Modern UI**: Clean and contemporary design with smooth animations +- **Blog System**: + - Blog posts displayed with previews on the main blog page + - Individual blog post pages with full content + - Navigation between posts ## Project Structure ``` -catcrafts.net/ -├── interfaces/ # Interface definitions -│ ├── Catcrafts.cppm -│ ├── Catcrafts-Views.cppm -│ ├── Catcrafts-Component.cppm -│ └── Catcrafts-Blog.cppm -├── implementations/ # Implementation files -│ ├── Catcrafts-Blog.cpp -│ └── main.cpp -├── styles.css # Modern CSS styling -├── project.json # Build configuration -├── run.sh # Development server script -└── build.sh # Build script +project.json - Build configuration +interfaces/ - Interface definitions +implementations/ - Implementation files +styles/styles.css - Styling +run.sh - Run script +README.md - This file +LICENSE - License information ``` +## Blog Implementation Details + +### Blog Previews +On the main `/blog` page, each blog post is displayed with: +- Title and date +- Preview of the content (first 200 characters) +- "Read Full Post" button to view the complete article + +### Individual Blog Pages +Each blog post has its own URL: +- `/blog/0` - First blog post +- `/blog/1` - Second blog post +- And so on... + +When visiting these URLs, users see the complete blog post content. + ## Building and Running -### Prerequisites -- C++ compiler with WebAssembly support -- Caddy server for serving files +To build and run the project: -### Quick Start - -1. Make the scripts executable: -```bash -chmod +x run.sh build.sh -``` - -2. Run the development server: ```bash ./run.sh ``` -The website will be available at `http://localhost:8085` +This will compile the project and serve it locally. -### Building Manually +## Contributing -```bash -./build.sh -``` - -## Technologies Used - -- **C++**: Core application logic -- **Crafter.CppDOM**: DOM manipulation library -- **WebAssembly**: Runtime environment -- **CSS3**: Modern styling with animations and gradients -- **HTML5**: Semantic markup - -## Customization - -To add new blog posts: -1. Edit `interfaces/Catcrafts-Blog.cppm` -2. Add new entries to the `posts` vector - -To modify styling: -1. Edit `styles.css` -2. Adjust colors, fonts, and layout as needed - -## License - -This project is licensed under the MIT License - see the LICENSE file for details. \ No newline at end of file +This project is open-source and made available for viewing purposes only. No permission is granted to copy, modify, distribute, or create derivative works. \ No newline at end of file diff --git a/implementations/Catcrafts-Blog.cpp b/implementations/Catcrafts-Blog.cpp index 1d54172..2b58919 100644 --- a/implementations/Catcrafts-Blog.cpp +++ b/implementations/Catcrafts-Blog.cpp @@ -8,23 +8,73 @@ No permission is granted to copy, modify, distribute, or create derivative works export module Catcrafts:Blog_impl; import :Blog; +import :Root; +import :Views; import std; -namespace Catcrafts { - std::string RenderBlog() { +using namespace Crafter::CppDOMBindings; + +export namespace Catcrafts { + std::vector* blogButtons = new std::vector(); + + void RenderBlog() { + delete blogButtons; + blogButtons = new std::vector(); std::string html = ""; for(const BlogPost& post : *posts) { + // For preview, we'll limit the content to first 200 characters + std::string previewContent = post.content; + if(previewContent.length() > 200) { + // Find the last space before 200 characters to avoid cutting words + 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.name, post.date, post.content); + +)", post.name, post.date, previewContent, post.slug); } - return html; + main->SetInnerHTML(html); + + for(const BlogPost& post : *posts) { + HtmlElementView& view = blogButtons->emplace_back(std::format("blog-button-{}", post.slug)); + view.AddClickListener([slug = post.slug](Crafter::MouseEvent e) { + 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) { + main->SetInnerHTML(std::format(R"( +
+
+

{}

+ +
+
+ {} +
+
)", post.name, post.date, post.content)); + return; + } + } + + main->SetInnerHTML("

Post Not Found

The requested blog post could not be found.

"); } } \ No newline at end of file diff --git a/implementations/Catcrafts-Root.cpp b/implementations/Catcrafts-Root.cpp new file mode 100644 index 0000000..9c93bc6 --- /dev/null +++ b/implementations/Catcrafts-Root.cpp @@ -0,0 +1,38 @@ +/* +catcrafts.net +Copyright (C) 2025 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:Root_impl; +import :Root; +import :Views; +import :Blog; +import std; + +namespace Catcrafts { + void RenderRoot(const std::string_view route) { + std::string currentRoute = std::string(route); + + if(currentRoute == "/blog" || currentRoute == "/") { + RenderBlog(); + } else if(currentRoute.rfind("/blog/", 0) == 0) { + // Handle individual blog post routes like /blog/0, /blog/1, etc. + std::size_t pos = currentRoute.find_last_of('/'); + std::cout << pos << std::endl; + std::cout << std::string::npos << std::endl; + std::cout << (pos != std::string::npos) << std::endl; + if(pos != std::string::npos) { + std::string postSlug = currentRoute.substr(pos + 1); + std::cout << postSlug << std::endl; + RenderBlogPost(postSlug); + } else { + main->SetInnerHTML("

Post Not Found

The requested blog post could not be found.

"); + } + } else { + RenderBlog(); //default route + } + } +} \ No newline at end of file diff --git a/implementations/main.cpp b/implementations/main.cpp index 9e7dbd8..a6a7943 100644 --- a/implementations/main.cpp +++ b/implementations/main.cpp @@ -15,27 +15,6 @@ using namespace Crafter::CppDOMBindings; HtmlElementView* blogButton; -void RenderRoot(const std::string_view route) { - std::string pageContent; - if(route == "/blog") { - pageContent = RenderBlog(); - } else { - pageContent = RenderBlog(); //default route - } - // Set body content - main->SetInnerHTML(pageContent); - - // Update active nav link - // auto navLinks = document->GetElementsByClassName("nav-container")[0]->GetElementsByTagName("a"); - // for(auto link : navLinks) { - // if(link->GetAttribute("id") == "blog-nav-button") { - // link->SetAttribute("class", "active"); - // } else { - // link->SetAttribute("class", ""); - // } - //} -} - int main() { AddPopStateListener([]() { RenderRoot(GetPathNameString()); @@ -44,7 +23,7 @@ int main() { blogButton = new HtmlElementView("blog-nav-button"); blogButton->AddClickListener([](Crafter::MouseEvent e) { PushState("{}", "", "/blog"); - RenderRoot("blog"); + RenderRoot("/blog"); }); RenderRoot("/"); diff --git a/interfaces/Catcrafts-Blog.cppm b/interfaces/Catcrafts-Blog.cppm index a7e15f7..cd9cb37 100644 --- a/interfaces/Catcrafts-Blog.cppm +++ b/interfaces/Catcrafts-Blog.cppm @@ -14,15 +14,18 @@ using namespace Crafter; export namespace Catcrafts { struct BlogPost { std::string name; + std::string slug; std::string date; std::string content; }; std::vector* posts = new std::vector{ { "Hello World!", + "hello-world", "2025-11-12", R"(Welcome to catcrafts.net!

This blog will mostly be dedicated to random tidbits i come across while working on my Crafter series of libraries, This website is fully written in C++ using the Crafter.CppDOM library.)" } }; - std::string RenderBlog(); + void RenderBlog(); + void RenderBlogPost(const std::string_view slug); } \ No newline at end of file diff --git a/interfaces/Catcrafts-Root.cppm b/interfaces/Catcrafts-Root.cppm new file mode 100644 index 0000000..e0429b7 --- /dev/null +++ b/interfaces/Catcrafts-Root.cppm @@ -0,0 +1,16 @@ +/* +catcrafts.net +Copyright (C) 2025 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:Root; +import Crafter.CppDOM; +import std; +using namespace Crafter; + +export namespace Catcrafts { + void RenderRoot(const std::string_view route); +} \ No newline at end of file diff --git a/interfaces/Catcrafts.cppm b/interfaces/Catcrafts.cppm index 457009d..d2ed576 100644 --- a/interfaces/Catcrafts.cppm +++ b/interfaces/Catcrafts.cppm @@ -8,4 +8,5 @@ No permission is granted to copy, modify, distribute, or create derivative works export module Catcrafts; export import :Views; -export import :Blog; \ No newline at end of file +export import :Blog; +export import :Root; \ No newline at end of file diff --git a/project.json b/project.json index 083a3ed..f74393b 100644 --- a/project.json +++ b/project.json @@ -3,10 +3,10 @@ "configurations": [ { "name": "executable", - "interfaces": ["interfaces/Catcrafts", "interfaces/Catcrafts-Views", "interfaces/Catcrafts-Blog"], - "implementations": ["implementations/main", "implementations/Catcrafts-Blog"], + "interfaces": ["interfaces/Catcrafts", "interfaces/Catcrafts-Views", "interfaces/Catcrafts-Blog", "interfaces/Catcrafts-Root"], + "implementations": ["implementations/main", "implementations/Catcrafts-Blog", "implementations/Catcrafts-Root"], "target": "wasm32-wasi", - "additional_files": ["styles/style.css"], + "additional_files": ["styles/styles.css"], "dependencies": [ { "path":"https://forgejo.catcrafts.net/Catcrafts/Crafter.CppDOM.git", diff --git a/styles/styles.css b/styles/styles.css index 840ae2b..2de91a4 100644 --- a/styles/styles.css +++ b/styles/styles.css @@ -222,6 +222,33 @@ main { .post-content a:hover { text-decoration: underline; color: var(--secondary-color); +}.post-content { + font-size: 1.1rem; + line-height: 1.8; + color: #333; + animation: fadeIn 0.6s ease-out 0.2s forwards; + opacity: 0; +} + +.post-content p { + margin-bottom: 1.2rem; +} + +.post-content a { + color: var(--primary-color); + text-decoration: none; + font-weight: 600; + transition: var(--transition); +} + +.post-content a:hover { + text-decoration: underline; + color: var(--secondary-color); +} + +.post-footer { + margin-top: 1.5rem; + text-align: right; } .post-content ul {