");
} else {
diff --git a/examples/Website/backend/main.cpp b/examples/Website/backend/main.cpp
new file mode 100644
index 0000000..901aa77
--- /dev/null
+++ b/examples/Website/backend/main.cpp
@@ -0,0 +1,70 @@
+/*
+Crafter® Build
+Copyright (C) 2025 Catcrafts®
+Catcrafts.net
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License version 3.0 as published by the Free Software Foundation;
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+import Crafter.Network;
+import std;
+using namespace Crafter;
+
+struct Note {
+ std::uint32_t id;
+ std::string content;
+};
+std::vector notes;
+int next_id = 1;
+
+int main() {
+ ListenerHTTP listener(3000, {
+ {"/createNote", [&](const HTTPRequest& request) {
+ if(request.method == "OPTIONS") {
+ std::cout << CreateResponseHTTP("200 OK", {{"Access-Control-Allow-Origin", "*"}, {"Access-Control-Allow-Headers", "*"}, {"Access-Control-Allow-Methods", "*"}}) << std::endl;
+ return CreateResponseHTTP("200 OK", {{"Access-Control-Allow-Origin", "*"}, {"Access-Control-Allow-Headers", "*"}, {"Access-Control-Allow-Methods", "*"}});
+ }
+ std::uint32_t id = next_id++;
+ notes.emplace_back(id, request.body);
+ return CreateResponseHTTP("200 OK", {{"Content-Type", "application/json"}, {"Access-Control-Allow-Origin", "*"}, {"Access-Control-Allow-Headers", "*"}}, std::format("{}", id));
+ }},
+
+ {"/deleteNote", [&](const HTTPRequest& request) {
+ if(request.method == "OPTIONS") {
+ std::cout << CreateResponseHTTP("200 OK", {{"Access-Control-Allow-Origin", "*"}, {"Access-Control-Allow-Headers", "*"}, {"Access-Control-Allow-Methods", "*"}}) << std::endl;
+ return CreateResponseHTTP("200 OK", {{"Access-Control-Allow-Origin", "*"}, {"Access-Control-Allow-Headers", "*"}, {"Access-Control-Allow-Methods", "*"}});
+ }
+ int idToRemove = std::stoi(request.body);
+ notes.erase(std::remove_if(notes.begin(), notes.end(),
+ [idToRemove](Note note) {
+ return note.id == idToRemove;
+ }),
+ notes.end());
+ return CreateResponseHTTP("200 OK", {{"Content-Type", "application/json"}, {"Access-Control-Allow-Origin", "*"}, {"Access-Control-Allow-Headers", "*"}});
+ }},
+
+ {"/getNotes", [&](const HTTPRequest& request) {
+ if(request.method == "OPTIONS") {
+ std::cout << CreateResponseHTTP("200 OK", {{"Access-Control-Allow-Origin", "*"}, {"Access-Control-Allow-Headers", "*"}, {"Access-Control-Allow-Methods", "*"}}) << std::endl;
+ return CreateResponseHTTP("200 OK", {{"Access-Control-Allow-Origin", "*"}, {"Access-Control-Allow-Headers", "*"}, {"Access-Control-Allow-Methods", "*"}});
+ }
+ std::string result;
+ for(const Note& note : notes) {
+ result += std::format("{}\n{}\n\n", note.id, note.content);
+ }
+ return CreateResponseHTTP("200 OK", {{"Content-Type", "application/json"}, {"Access-Control-Allow-Origin", "*"}, {"Access-Control-Allow-Headers", "*"}}, result);
+ }}
+ });
+
+ listener.Listen();
+}
diff --git a/examples/Website/backend/project.json b/examples/Website/backend/project.json
new file mode 100644
index 0000000..fb2c752
--- /dev/null
+++ b/examples/Website/backend/project.json
@@ -0,0 +1,16 @@
+{
+ "name": "website-backend",
+ "configurations": [
+ {
+ "name": "executable",
+ "implementations": ["main"],
+ "libs": ["crafter-thread"],
+ "dependencies": [
+ {
+ "path":"/home/jorijn/repos/Crafter/Crafter.Network/project.json",
+ "configuration":"lib-debug"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/examples/Website/frontend/main.cpp b/examples/Website/frontend/main.cpp
new file mode 100644
index 0000000..80e70ca
--- /dev/null
+++ b/examples/Website/frontend/main.cpp
@@ -0,0 +1,256 @@
+import Crafter.CppDOM;
+import std;
+using namespace Crafter;
+using namespace Crafter::CppDOMBindings;
+
+// Structure to represent a note
+struct Note {
+ std::uint32_t id;
+ std::string content;
+};
+
+void RenderNotes();
+
+// Global vector to store notes
+std::vector notes;
+
+// Create the head section
+HtmlElementView* head = new HtmlElementView("head", R"(
+ Note Taking App
+
+)");
+
+// Create the body section
+HtmlElementView* body = new HtmlElementView("body", R"(
+
+
📝 Note Taking App
+
+
+
Add New Note
+
+
+
+
+
+
+
+
+
+
Your Notes
+
+
+
+)");
+HtmlElementView* addNoteBtn = new HtmlElementView("addNoteBtn");
+HtmlElementView* noteInput = new HtmlElementView("noteInput");
+
+// Function to fetch all notes from the backend
+void FetchNotes() {
+ HtmlElementView loadingIndicator("loading");
+ loadingIndicator.SetInnerHTML("
Loading notes...
");
+
+ // Make HTTP request to backend
+ Fetch("http://localhost:3000/getNotes", [](std::string content) {
+ // Parse response - each note is separated by \n\n
+ notes.clear();
+
+ // Simple parsing of note data
+ std::uint_fast32_t pos = 0;
+ std::uint_fast32_t prevPos = 0;
+
+ while ((pos = content.find('\n', prevPos)) != std::string::npos) {
+ if (pos > prevPos) {
+ // Extract ID
+ std::string idStr = content.substr(prevPos, pos - prevPos);
+ std::uint_fast32_t id = std::stoul(idStr);
+
+ // Find the next newline for content
+ std::uint_fast32_t contentStart = pos + 1;
+ std::uint_fast32_t contentEnd = content.find('\n', contentStart);
+ if (contentEnd != std::string::npos) {
+ std::string noteContent = content.substr(contentStart, contentEnd - contentStart);
+ notes.push_back({id, noteContent});
+ }
+ }
+ prevPos = content.find('\n', pos) + 1;
+ if (prevPos >= content.length()) break;
+ }
+
+ // Update UI with notes
+ //RenderNotes();
+ });
+}
+
+// Function to add a new note via the backend
+void AddNote(const std::string& content) {
+ if (content.empty()) return;
+
+ HtmlElementView loadingIndicator("loading");
+ loadingIndicator.SetInnerHTML("
Saving note...
");
+
+ // Make POST request to create note
+ Fetch("http://localhost:3000/createNote", content, [](std::string content) {});
+}
+
+// Function to delete a note via the backend
+void DeleteNote(std::uint32_t id) {
+ HtmlElementView loadingIndicator("loading");
+ loadingIndicator.SetInnerHTML("
Deleting note...
");
+
+ // Make POST request to delete note
+ Fetch("http://localhost:3000/deleteNote", std::to_string(id), [](std::string content) {
+ FetchNotes();
+ });
+}
+
+// Function to render all notes to the DOM
+void RenderNotes() {
+ HtmlElementView notesContainer("notesContainer");
+
+ if (notes.empty()) {
+ notesContainer.SetInnerHTML("
No notes yet. Add one below!
");
+ return;
+ }
+
+ std::string html = "
";
+ for (const Note& note : notes) {
+ html += std::format(
+ R"(