Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d3dd4b1f7a | |||
| 13a12c2a2c |
17 changed files with 344 additions and 126 deletions
96
.forgejo/workflows/deploy.yaml
Normal file
96
.forgejo/workflows/deploy.yaml
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
name: Deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# One deploy at a time; if you push twice quickly, cancel the older run so the
|
||||||
|
# newest commit is what lands on the server.
|
||||||
|
concurrency:
|
||||||
|
group: deploy
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-deploy:
|
||||||
|
runs-on: arch-latest
|
||||||
|
steps:
|
||||||
|
- name: Install build dependencies
|
||||||
|
run: |
|
||||||
|
# Same keyring bootstrap the Crafter.Build CI does: the slim
|
||||||
|
# archlinux:latest image ships without a populated pacman keyring
|
||||||
|
# or local master key.
|
||||||
|
pacman-key --init
|
||||||
|
pacman-key --populate archlinux
|
||||||
|
pacman -Sy --noconfirm --needed archlinux-keyring
|
||||||
|
pacman -Syu --noconfirm --needed \
|
||||||
|
clang lld libc++ \
|
||||||
|
wasi-libc wasi-libc++ wasi-libc++abi wasi-compiler-rt \
|
||||||
|
git curl tar rsync
|
||||||
|
# Container runs as root; workspace may be owned by another uid.
|
||||||
|
git config --global --add safe.directory '*'
|
||||||
|
|
||||||
|
- name: Install crafter-build
|
||||||
|
# Pull the rolling 'latest' Linux build from the Crafter.Build repo and
|
||||||
|
# install it distro-style so it auto-discovers its modules under
|
||||||
|
# /usr/share/crafter-build. v2 = SSE4.2 baseline, safe on the CI SBC.
|
||||||
|
run: |
|
||||||
|
set -eux
|
||||||
|
url="https://forgejo.catcrafts.net/Catcrafts/Crafter.Build/releases/download/latest/crafter-build-linux-x86_64-v2.tar.gz"
|
||||||
|
mkdir -p /tmp/cb
|
||||||
|
curl -fsSL "$url" -o /tmp/cb.tar.gz
|
||||||
|
tar -xzf /tmp/cb.tar.gz -C /tmp/cb
|
||||||
|
install -Dm755 /tmp/cb/bin/crafter-build /usr/bin/crafter-build
|
||||||
|
cp -r /tmp/cb/share/crafter-build /usr/share/
|
||||||
|
crafter-build --version || true
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Cache crafter-build dependency clones
|
||||||
|
# ~/.cache/crafter.build holds the Crafter.Graphics clone and prebuilt
|
||||||
|
# module cache. crafter-build still git-pulls the dep each run, so a
|
||||||
|
# stale cache only means a smaller delta fetch, never a stale build.
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.cache/crafter.build
|
||||||
|
key: crafter-cache-${{ runner.os }}-${{ hashFiles('project.cpp') }}
|
||||||
|
restore-keys: |
|
||||||
|
crafter-cache-${{ runner.os }}-
|
||||||
|
|
||||||
|
- name: Build (wasm bundle)
|
||||||
|
run: crafter-build
|
||||||
|
|
||||||
|
- name: Locate build output
|
||||||
|
id: out
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
dist=$(find bin -maxdepth 1 -type d -name 'Catcrafts.Net-wasm32-wasip1-*' | head -n1)
|
||||||
|
if [ -z "$dist" ]; then
|
||||||
|
echo "No build output directory found under bin/" >&2
|
||||||
|
ls -la bin || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "dist=$dist" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Built bundle: $dist"
|
||||||
|
ls -la "$dist"
|
||||||
|
|
||||||
|
- name: Deploy to web root
|
||||||
|
# No SSH: the job already runs on the deploy box. The server's web root
|
||||||
|
# is bind-mounted into this container at /deploy via the runner config
|
||||||
|
# (container.options: "-v /path/to/webroot:/deploy"). We just copy into
|
||||||
|
# it. --delete makes the root an exact mirror of the build; Caddyfile.coi
|
||||||
|
# is a local dev helper (its 'root' points at the build machine), so the
|
||||||
|
# server's own Caddy config supplies the headers instead.
|
||||||
|
env:
|
||||||
|
DIST: ${{ steps.out.outputs.dist }}
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
if [ ! -d /deploy ]; then
|
||||||
|
echo "ERROR: /deploy is not mounted into the runner container." >&2
|
||||||
|
echo "Add '-v /your/webroot:/deploy' to the runner's container.options" >&2
|
||||||
|
echo "in config.yaml and restart the runner." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
rsync -a --delete --exclude 'Caddyfile.coi' "$DIST"/ /deploy/
|
||||||
|
echo "Deployed $DIST -> /deploy (host web root)"
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# catcrafts.net
|
# catcrafts.net
|
||||||
|
|
||||||
This is the source code for catcrafts.net, a website built entirely in C++ using the Crafter.CppDOM library.
|
This is the source code for catcrafts.net, a website built entirely in C++ using the Crafter.Graphics library.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
crafter-build build executable
|
crafter-build build executable
|
||||||
|
|
|
||||||
24
catcrafts-head.js
Normal file
24
catcrafts-head.js
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Head-element setup for catcrafts.net. The Crafter.Graphics Dom partition
|
||||||
|
// only exposes element creation under <body>, so anything that has to live in
|
||||||
|
// <head> (title, stylesheet link, favicon link) gets injected from this
|
||||||
|
// loader. EnableWasiBrowserRuntime auto-picks up every *.js in cfg.files and
|
||||||
|
// emits a <script type="module"> tag for it ahead of runtime.js, so this
|
||||||
|
// runs before the wasm module starts and styles are in place by first paint.
|
||||||
|
|
||||||
|
document.title = "Catcrafts.net";
|
||||||
|
|
||||||
|
const styles = document.createElement("link");
|
||||||
|
styles.rel = "stylesheet";
|
||||||
|
styles.href = "styles.css";
|
||||||
|
document.head.appendChild(styles);
|
||||||
|
|
||||||
|
const favicon = document.createElement("link");
|
||||||
|
favicon.rel = "icon";
|
||||||
|
favicon.type = "image/svg+xml";
|
||||||
|
favicon.href = "favicon.svg";
|
||||||
|
document.head.appendChild(favicon);
|
||||||
|
|
||||||
|
const viewport = document.createElement("meta");
|
||||||
|
viewport.name = "viewport";
|
||||||
|
viewport.content = "width=device-width, initial-scale=1.0";
|
||||||
|
document.head.appendChild(viewport);
|
||||||
21
deploy/Caddyfile.example
Normal file
21
deploy/Caddyfile.example
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
# catcrafts.net Caddy site block
|
||||||
|
#
|
||||||
|
# The WASM app (Crafter.Graphics) needs a cross-origin-isolated context
|
||||||
|
# (SharedArrayBuffer / threads), which requires these response headers. They
|
||||||
|
# are NOT optional — without them the page loads but the runtime fails.
|
||||||
|
#
|
||||||
|
# If you already have a `catcrafts.net { ... }` block, you only need to ADD the
|
||||||
|
# three Cross-Origin-* header lines to it. This file is the complete block for
|
||||||
|
# reference. Point `root` at the host directory you bind-mount into the runner
|
||||||
|
# as /deploy (the "-v /path/to/webroot:/deploy" in the runner's config.yaml).
|
||||||
|
|
||||||
|
catcrafts.net {
|
||||||
|
root * /srv/catcrafts.net
|
||||||
|
|
||||||
|
header Cross-Origin-Opener-Policy "same-origin"
|
||||||
|
header Cross-Origin-Embedder-Policy "require-corp"
|
||||||
|
header Cross-Origin-Resource-Policy "same-origin"
|
||||||
|
|
||||||
|
encode zstd gzip
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<!-- save this as emoji-favicon.svg -->
|
<!-- save this as emoji-favicon.svg -->
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64">
|
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128">
|
||||||
<text x="50%" y="50%" font-size="48" text-anchor="middle" dominant-baseline="central">
|
<text x="50%" y="50%" font-size="110" text-anchor="middle" dominant-baseline="central">
|
||||||
🐱
|
🐱
|
||||||
</text>
|
</text>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 219 B After Width: | Height: | Size: 222 B |
|
|
@ -1,8 +1,8 @@
|
||||||
/*
|
/*
|
||||||
catcrafts.net
|
catcrafts.net
|
||||||
Copyright (C) 2025 Catcrafts
|
Copyright (C) 2026 Catcrafts
|
||||||
|
|
||||||
The source code of this website is made available for viewing purposes only.
|
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.
|
No permission is granted to copy, modify, distribute, or create derivative works.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -10,22 +10,24 @@ export module Catcrafts:Blog_impl;
|
||||||
import :Blog;
|
import :Blog;
|
||||||
import :Root;
|
import :Root;
|
||||||
import :Views;
|
import :Views;
|
||||||
|
import Crafter.Graphics;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
using namespace Crafter::CppDOMBindings;
|
using namespace Crafter;
|
||||||
|
|
||||||
export namespace Catcrafts {
|
export namespace Catcrafts {
|
||||||
std::vector<HtmlElementView> blogButtons;
|
// 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;
|
||||||
|
|
||||||
void RenderBlog() {
|
void RenderBlog() {
|
||||||
blogButtons.clear();
|
blogButtons.clear();
|
||||||
std::string html = "";
|
std::string html = "";
|
||||||
for(const BlogPost& post : posts) {
|
for(const BlogPost& post : posts) {
|
||||||
std::cout << "test" << std::endl;
|
|
||||||
// For preview, we'll limit the content to first 200 characters
|
|
||||||
std::string previewContent = post.content;
|
std::string previewContent = post.content;
|
||||||
if(previewContent.length() > 200) {
|
if(previewContent.length() > 200) {
|
||||||
// Find the last space before 200 characters to avoid cutting words
|
|
||||||
std::size_t lastSpace = previewContent.find_last_of(' ', 200);
|
std::size_t lastSpace = previewContent.find_last_of(' ', 200);
|
||||||
if(lastSpace != std::string::npos) {
|
if(lastSpace != std::string::npos) {
|
||||||
previewContent = previewContent.substr(0, lastSpace) + "...";
|
previewContent = previewContent.substr(0, lastSpace) + "...";
|
||||||
|
|
@ -47,24 +49,21 @@ export namespace Catcrafts {
|
||||||
</div>
|
</div>
|
||||||
</div>)", post.slug, post.name, post.date, previewContent);
|
</div>)", post.slug, post.name, post.date, previewContent);
|
||||||
}
|
}
|
||||||
main.SetInnerHTML(std::format(R"(<div class="blog-posts">{}</div>)", html));
|
MainContent().SetInnerHTML(std::format(R"(<div class="blog-posts">{}</div>)", html));
|
||||||
|
|
||||||
for(const BlogPost& post : posts) {
|
for(const BlogPost& post : posts) {
|
||||||
// Add click listener to the entire post card
|
Dom::HtmlElementPtr& cardView = blogButtons.emplace_back(std::format("blog-post-{}", post.slug));
|
||||||
HtmlElementView& cardView = blogButtons.emplace_back(std::format("blog-post-{}", post.slug));
|
cardView.AddClickListener([slug = post.slug](Dom::MouseEvent) {
|
||||||
cardView.AddClickListener([slug = post.slug](Crafter::MouseEvent e) {
|
Router::PushState("{}", "", std::format("/blog/{}", slug));
|
||||||
PushState("{}", "", std::format("/blog/{}", slug));
|
|
||||||
RenderRoot(std::format("/blog/{}", slug));
|
RenderRoot(std::format("/blog/{}", slug));
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderBlogPost(const std::string_view slug) {
|
void RenderBlogPost(const std::string_view slug) {
|
||||||
std::cout << "render "<< std::endl;
|
|
||||||
for(const BlogPost& post : posts) {
|
for(const BlogPost& post : posts) {
|
||||||
if(post.slug == slug) {
|
if(post.slug == slug) {
|
||||||
main.SetInnerHTML(std::format(R"(
|
MainContent().SetInnerHTML(std::format(R"(
|
||||||
<div class="blog-post-page">
|
<div class="blog-post-page">
|
||||||
<div class="post-header">
|
<div class="post-header">
|
||||||
<h1 class="post-title">{}</h1>
|
<h1 class="post-title">{}</h1>
|
||||||
|
|
@ -78,6 +77,6 @@ export namespace Catcrafts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main.SetInnerHTML("<h1>Post Not Found</h1><p>The requested blog post could not be found.</p>");
|
MainContent().SetInnerHTML("<h1>Post Not Found</h1><p>The requested blog post could not be found.</p>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/*
|
/*
|
||||||
catcrafts.net
|
catcrafts.net
|
||||||
Copyright (C) 2025 Catcrafts
|
Copyright (C) 2026 Catcrafts
|
||||||
|
|
||||||
The source code of this website is made available for viewing purposes only.
|
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.
|
No permission is granted to copy, modify, distribute, or create derivative works.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -10,29 +10,27 @@ export module Catcrafts:Root_impl;
|
||||||
import :Root;
|
import :Root;
|
||||||
import :Views;
|
import :Views;
|
||||||
import :Blog;
|
import :Blog;
|
||||||
|
import Crafter.Graphics;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
|
using namespace Crafter;
|
||||||
|
|
||||||
namespace Catcrafts {
|
namespace Catcrafts {
|
||||||
void RenderRoot(const std::string_view route) {
|
void RenderRoot(const std::string_view route) {
|
||||||
std::string currentRoute = std::string(route);
|
std::string currentRoute = std::string(route);
|
||||||
|
|
||||||
if(currentRoute == "/blog" || currentRoute == "/") {
|
if(currentRoute == "/blog" || currentRoute == "/") {
|
||||||
RenderBlog();
|
RenderBlog();
|
||||||
} else if(currentRoute.rfind("/blog/", 0) == 0) {
|
} 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::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) {
|
if(pos != std::string::npos) {
|
||||||
std::string postSlug = currentRoute.substr(pos + 1);
|
std::string postSlug = currentRoute.substr(pos + 1);
|
||||||
std::cout << postSlug << std::endl;
|
|
||||||
RenderBlogPost(postSlug);
|
RenderBlogPost(postSlug);
|
||||||
} else {
|
} else {
|
||||||
main.SetInnerHTML("<h1>Post Not Found</h1><p>The requested blog post could not be found.</p>");
|
MainContent().SetInnerHTML("<h1>Post Not Found</h1><p>The requested blog post could not be found.</p>");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RenderBlog(); //default route
|
RenderBlog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
51
implementations/Catcrafts-Views.cpp
Normal file
51
implementations/Catcrafts-Views.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
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:Views_impl;
|
||||||
|
import :Views;
|
||||||
|
import Crafter.Graphics;
|
||||||
|
import std;
|
||||||
|
|
||||||
|
using namespace Crafter;
|
||||||
|
|
||||||
|
namespace Catcrafts {
|
||||||
|
namespace {
|
||||||
|
// Owning handle for the page-chrome root. `std::optional` lets us
|
||||||
|
// defer construction until InitializePage() runs (the CreateInBody
|
||||||
|
// call would otherwise fire at static-init time, before main()).
|
||||||
|
std::optional<Dom::HtmlElement> root;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializePage() {
|
||||||
|
root.emplace(Dom::HtmlElement::CreateInBody("div", "catcrafts-root"));
|
||||||
|
root->SetInnerHTML(R"(
|
||||||
|
<header>
|
||||||
|
<div class="nav-container">
|
||||||
|
<a href="/" class="logo">🐱 Catcrafts</a>
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
<li><a id="blog-nav-button" style="cursor: pointer;" class="active">Blog</a></li>
|
||||||
|
<li><a href="https://forgejo.catcrafts.net/Catcrafts/">Forgejo</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main id="main"></main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div class="footer-content">
|
||||||
|
<div class="footer-links">
|
||||||
|
Powered by Crafter.Graphics, Running near native with WASM!
|
||||||
|
<a href="https://forgejo.catcrafts.net/Catcrafts/catcrafts.net">View source</a>
|
||||||
|
</div>
|
||||||
|
<p>© 2026 Catcrafts®. All rights reserved. Crafter® and Catcrafts® are registered trademarks with the EUIPO</p>
|
||||||
|
</div>
|
||||||
|
</footer>)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,30 +1,40 @@
|
||||||
/*
|
/*
|
||||||
catcrafts.net
|
catcrafts.net
|
||||||
Copyright (C) 2025 Catcrafts
|
Copyright (C) 2026 Catcrafts
|
||||||
|
|
||||||
The source code of this website is made available for viewing purposes only.
|
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.
|
No permission is granted to copy, modify, distribute, or create derivative works.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Catcrafts;
|
import Catcrafts;
|
||||||
import Crafter.CppDOM;
|
import Crafter.Graphics;
|
||||||
import std;
|
import std;
|
||||||
using namespace Catcrafts;
|
using namespace Catcrafts;
|
||||||
using namespace Crafter;
|
using namespace Crafter;
|
||||||
using namespace Crafter::CppDOMBindings;
|
|
||||||
|
|
||||||
HtmlElementView* blogButton;
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
AddPopStateListener([]() {
|
Device::Initialize();
|
||||||
RenderRoot(GetPathNameString());
|
// Window in CRAFTER_GRAPHICS_WINDOW_DOM mode is a page-level event hub
|
||||||
|
// plus the rAF driver; even without subscribing to its events we need
|
||||||
|
// it so StartSync() can keep the wasm module alive past main() (the
|
||||||
|
// bridge stashes a raw pointer, so the storage has to outlive main).
|
||||||
|
static Window window(0, 0, "Catcrafts");
|
||||||
|
|
||||||
|
InitializePage();
|
||||||
|
|
||||||
|
Router::AddPopStateListener([]{
|
||||||
|
RenderRoot(Router::GetPath());
|
||||||
});
|
});
|
||||||
|
|
||||||
blogButton = new HtmlElementView("blog-nav-button");
|
static Dom::HtmlElementPtr blogButton("blog-nav-button");
|
||||||
blogButton->AddClickListener([](Crafter::MouseEvent e) {
|
blogButton.AddClickListener([](Dom::MouseEvent) {
|
||||||
PushState("{}", "", "/blog");
|
Router::PushState("{}", "", "/blog");
|
||||||
RenderRoot("/blog");
|
RenderRoot("/blog");
|
||||||
});
|
});
|
||||||
|
|
||||||
RenderRoot(GetPathNameString());
|
RenderRoot(Router::GetPath());
|
||||||
}
|
|
||||||
|
window.StartUpdate();
|
||||||
|
window.StartSync();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
/*
|
/*
|
||||||
catcrafts.net
|
catcrafts.net
|
||||||
Copyright (C) 2025 Catcrafts
|
Copyright (C) 2026 Catcrafts
|
||||||
|
|
||||||
The source code of this website is made available for viewing purposes only.
|
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.
|
No permission is granted to copy, modify, distribute, or create derivative works.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export module Catcrafts:Blog;
|
export module Catcrafts:Blog;
|
||||||
import Crafter.CppDOM;
|
import Crafter.Graphics;
|
||||||
import std;
|
import std;
|
||||||
using namespace Crafter;
|
using namespace Crafter;
|
||||||
|
|
||||||
|
|
@ -22,8 +22,8 @@ export namespace Catcrafts {
|
||||||
{
|
{
|
||||||
"In WASM, Exit doesn't mean done.",
|
"In WASM, Exit doesn't mean done.",
|
||||||
"in-wasm-exit-doesnt-mean-done",
|
"in-wasm-exit-doesnt-mean-done",
|
||||||
"2025-11-14",
|
"2026-11-14",
|
||||||
R"(So if anyone looked at the source code for this website pefore this post you would have seen that every is allocated with new, for example this very blog was defined as <code>std::vector<BlogPost> posts = new std::vector<BlogPost>{...</code><br><br>
|
R"(So if anyone looked at the source code for this website pefore this post you would have seen that everything was allocated with new, for example this very blog was defined as <code>std::vector<BlogPost> posts = new std::vector<BlogPost>{...};</code><br><br>
|
||||||
|
|
||||||
Reason for this was that everything became corrupted when callbacking from JS, not knowing sure as to why this was the fastest solution, but after debugging the problem became clear.<br><br>
|
Reason for this was that everything became corrupted when callbacking from JS, not knowing sure as to why this was the fastest solution, but after debugging the problem became clear.<br><br>
|
||||||
|
|
||||||
|
|
@ -31,7 +31,7 @@ export namespace Catcrafts {
|
||||||
|
|
||||||
This caused all the memory corruption errors since everything was destructed.<br><br>
|
This caused all the memory corruption errors since everything was destructed.<br><br>
|
||||||
|
|
||||||
Luckily this is a very simple fix of adding <code>-fno-c++-static-destructors</code>, and things like this are is also the reason i use clang instead of gcc.<br><br>
|
Luckily this is a very simple fix of adding <code>-fno-c++-static-destructors</code>, and the ease of things like this is also one of the reasons i use clang instead of gcc.<br><br>
|
||||||
|
|
||||||
So now all examples and this site have been updated to use normal variables again.<br><br>
|
So now all examples and this site have been updated to use normal variables again.<br><br>
|
||||||
|
|
||||||
|
|
@ -40,12 +40,12 @@ export namespace Catcrafts {
|
||||||
{
|
{
|
||||||
"Hello World!",
|
"Hello World!",
|
||||||
"hello-world",
|
"hello-world",
|
||||||
"2025-11-12",
|
"2026-11-12",
|
||||||
R"(Welcome to catcrafts.net!<br><br>
|
R"(Welcome to catcrafts.net!<br><br>
|
||||||
Here we believe optimization is everything and C++ is a gift from god.<br>
|
Here we believe optimization is everything and C++ is a gift from god.<br>
|
||||||
This blog will mostly be dedicated to random tidbits i come across while working on my Crafter series of libraries.<br><br>
|
This blog will mostly be dedicated to random tidbits i come across while working on my Crafter series of libraries.<br><br>
|
||||||
|
|
||||||
Like this website which is fully written in C++ using the Crafter.CppDOM library.<br>
|
Like this website which is fully written in C++ using the Crafter.Graphics library.<br>
|
||||||
And source available too!<br>
|
And source available too!<br>
|
||||||
<a href="https://forgejo.catcrafts.net/Catcrafts/catcrafts.net">https://forgejo.catcrafts.net/Catcrafts/catcrafts.net<a>)"
|
<a href="https://forgejo.catcrafts.net/Catcrafts/catcrafts.net">https://forgejo.catcrafts.net/Catcrafts/catcrafts.net<a>)"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
/*
|
|
||||||
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:Component;
|
|
||||||
using namespace Crafter;
|
|
||||||
|
|
||||||
export namespace Catcrafts {
|
|
||||||
class Component {
|
|
||||||
std::string render();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
/*
|
/*
|
||||||
catcrafts.net
|
catcrafts.net
|
||||||
Copyright (C) 2025 Catcrafts
|
Copyright (C) 2026 Catcrafts
|
||||||
|
|
||||||
The source code of this website is made available for viewing purposes only.
|
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.
|
No permission is granted to copy, modify, distribute, or create derivative works.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export module Catcrafts:Root;
|
export module Catcrafts:Root;
|
||||||
import Crafter.CppDOM;
|
import Crafter.Graphics;
|
||||||
import std;
|
import std;
|
||||||
using namespace Crafter;
|
using namespace Crafter;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,27 @@
|
||||||
/*
|
/*
|
||||||
catcrafts.net
|
catcrafts.net
|
||||||
Copyright (C) 2025 Catcrafts
|
Copyright (C) 2026 Catcrafts
|
||||||
|
|
||||||
The source code of this website is made available for viewing purposes only.
|
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.
|
No permission is granted to copy, modify, distribute, or create derivative works.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export module Catcrafts:Views;
|
export module Catcrafts:Views;
|
||||||
import Crafter.CppDOM;
|
import Crafter.Graphics;
|
||||||
|
import std;
|
||||||
using namespace Crafter;
|
using namespace Crafter;
|
||||||
|
|
||||||
export namespace Catcrafts {
|
export namespace Catcrafts {
|
||||||
HtmlElementPtr body("body", R"(
|
// Builds the persistent page chrome (header / <main id="main"> / footer)
|
||||||
<header>
|
// under <body>. Owns the root element for the page's lifetime so its
|
||||||
<div class="nav-container">
|
// children don't get yanked out of the DOM. Must be called from main()
|
||||||
<a href="/" class="logo">🐱 Catcrafts</a>
|
// — the Crafter.Graphics Dom bridge is only safe to use after wasm
|
||||||
<nav>
|
// instantiation hands control to user code.
|
||||||
<ul>
|
void InitializePage();
|
||||||
<li><a id="blog-nav-button" style="cursor: pointer;" class="active">Blog</a></li>
|
|
||||||
<li><a href="https://forgejo.catcrafts.net/Catcrafts/">Forgejo</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main id="main"></main>
|
// Per-render scratch ref to the <main> content container created by
|
||||||
|
// InitializePage(). Looking it up fresh on every call costs one
|
||||||
<footer>
|
// document.getElementById; in return we don't have to thread a long-lived
|
||||||
<div class="footer-content">
|
// reference across module boundaries.
|
||||||
<div class="footer-links">
|
inline Dom::HtmlElementPtr MainContent() { return Dom::HtmlElementPtr("main"); }
|
||||||
Powered by Crafter.CppDOM, Running near native with WASM!
|
|
||||||
<a href="https://forgejo.catcrafts.net/Catcrafts/catcrafts.net">View source</a>
|
|
||||||
</div>
|
|
||||||
<p>© 2025 Catcrafts®. All rights reserved. Crafter® and Catcrafts® are registered trademarks with the EUIPO</p>
|
|
||||||
</div>
|
|
||||||
</footer>)");
|
|
||||||
|
|
||||||
HtmlElementPtr head("head", R"(
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Catcrafts.net</title>
|
|
||||||
<link rel="stylesheet" href="/styles.css">
|
|
||||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
|
||||||
)");
|
|
||||||
|
|
||||||
HtmlElementPtr main("main");
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
catcrafts.net
|
catcrafts.net
|
||||||
Copyright (C) 2025 Catcrafts
|
Copyright (C) 2026 Catcrafts
|
||||||
|
|
||||||
The source code of this website is made available for viewing purposes only.
|
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.
|
No permission is granted to copy, modify, distribute, or create derivative works.
|
||||||
|
|
|
||||||
75
project.cpp
Normal file
75
project.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import std;
|
||||||
|
import Crafter.Build;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
using namespace Crafter;
|
||||||
|
|
||||||
|
extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> args) {
|
||||||
|
std::vector<std::string> depArgs(args.begin(), args.end());
|
||||||
|
depArgs.push_back("--target=wasm32-wasip1");
|
||||||
|
|
||||||
|
// --local resolves the Crafter.Graphics dep from a sibling working tree
|
||||||
|
// instead of fetching it from forgejo. Mirrors Crafter.Graphics's own
|
||||||
|
// project.cpp convention so edits across the two repos pick up without
|
||||||
|
// commit-and-pull.
|
||||||
|
bool useLocal = false;
|
||||||
|
for (std::string_view a : args) {
|
||||||
|
if (a == "--local") { useLocal = true; break; }
|
||||||
|
}
|
||||||
|
if (useLocal && std::find(depArgs.begin(), depArgs.end(), std::string("--local")) == depArgs.end()) {
|
||||||
|
depArgs.push_back("--local");
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration* graphics = useLocal
|
||||||
|
? LocalProject({
|
||||||
|
.projectFile = "../Crafter/Crafter.Graphics/project.cpp",
|
||||||
|
.args = depArgs,
|
||||||
|
})
|
||||||
|
: GitProject({
|
||||||
|
.source = { .url = "https://forgejo.catcrafts.net/Catcrafts/Crafter.Graphics.git" },
|
||||||
|
.args = depArgs,
|
||||||
|
});
|
||||||
|
|
||||||
|
Configuration cfg;
|
||||||
|
cfg.path = "./";
|
||||||
|
cfg.name = "Catcrafts.Net";
|
||||||
|
cfg.outputName = "catcrafts";
|
||||||
|
cfg.type = ConfigurationType::Executable;
|
||||||
|
cfg.target = "wasm32-wasip1";
|
||||||
|
ApplyStandardArgs(cfg, args);
|
||||||
|
cfg.dependencies = { graphics };
|
||||||
|
|
||||||
|
std::array<fs::path, 4> ifaces = {
|
||||||
|
"interfaces/Catcrafts",
|
||||||
|
"interfaces/Catcrafts-Views",
|
||||||
|
"interfaces/Catcrafts-Blog",
|
||||||
|
"interfaces/Catcrafts-Root",
|
||||||
|
};
|
||||||
|
std::array<fs::path, 4> impls = {
|
||||||
|
"implementations/main",
|
||||||
|
"implementations/Catcrafts-Blog",
|
||||||
|
"implementations/Catcrafts-Root",
|
||||||
|
"implementations/Catcrafts-Views",
|
||||||
|
};
|
||||||
|
cfg.GetInterfacesAndImplementations(ifaces, impls);
|
||||||
|
|
||||||
|
cfg.files.emplace_back(fs::path("styles/styles.css"));
|
||||||
|
cfg.files.emplace_back(fs::path("robots.txt"));
|
||||||
|
cfg.files.emplace_back(fs::path("sitemap.xml"));
|
||||||
|
cfg.files.emplace_back(fs::path("favicon.svg"));
|
||||||
|
// Loaded as a <script type="module"> before runtime.js by
|
||||||
|
// EnableWasiBrowserRuntime — sets <title>/<link> tags since the
|
||||||
|
// Dom partition has no head-element access.
|
||||||
|
cfg.files.emplace_back(fs::path("catcrafts-head.js"));
|
||||||
|
|
||||||
|
EnableWasiBrowserRuntime(cfg);
|
||||||
|
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
18
project.json
18
project.json
|
|
@ -1,18 +0,0 @@
|
||||||
{
|
|
||||||
"name": "main",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "executable",
|
|
||||||
"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/styles.css", "robots.txt", "sitemap.xml", "favicon.svg"],
|
|
||||||
"dependencies": [
|
|
||||||
{
|
|
||||||
"path":"https://forgejo.catcrafts.net/Catcrafts/Crafter.CppDOM.git",
|
|
||||||
"configuration":"lib"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
1
run.sh
1
run.sh
|
|
@ -1 +0,0 @@
|
||||||
caddy file-server --listen :8080 --root bin/executable
|
|
||||||
Loading…
Reference in a new issue