diff --git a/examples/AllEventHandling/main.cpp b/examples/AllEventHandling/main.cpp index 584caf5..8a8778a 100644 --- a/examples/AllEventHandling/main.cpp +++ b/examples/AllEventHandling/main.cpp @@ -1,8 +1,3 @@ -/* - * Enhanced Event Handling Demo - * This example showcases all available event types in Crafter.CppDOM - */ - import Crafter.CppDOM; using namespace Crafter; import std; diff --git a/examples/FetchExample/main.cpp b/examples/FetchExample/main.cpp index 01dace9..f2209d4 100644 --- a/examples/FetchExample/main.cpp +++ b/examples/FetchExample/main.cpp @@ -7,7 +7,6 @@ int main(){ SetInnerHTML(body, "

Fetch Example

Testing HTTP requests...

"); Fetch("https://httpbin.org/get", [body](std::string result){ - std::cout << "callback recieved2" << std::endl; if (!result.empty()) { SetInnerHTML(body, "

Fetch Example

Response: " + result + "

"); } 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"(
+
{}
+ +
)", + note.id, note.content, note.id + ); + } + html += "
"; + + notesContainer.SetInnerHTML(html); + + // Add event listeners to delete buttons + for (const Note& note : notes) { + HtmlElementView deleteBtn(std::format("note-{}-delete", note.id)); + deleteBtn.AddClickListener([id = note.id](MouseEvent event) { + DeleteNote(id); + }); + } +} + +std::string* currentNoteValue = new std::string(); + +// Main function +int main() { + // Initialize the app + FetchNotes(); + + // Add input listener to track textarea changes + noteInput->AddInputListener([&](InputEvent event) { + *currentNoteValue += event.data; + std::cout << *currentNoteValue << std::endl; + }); + + // Add click listener to add note button + addNoteBtn->AddClickListener([&](MouseEvent event) { + std::cout << "click!" << std::endl; + std::cout << *currentNoteValue << std::endl; + // Use the captured value from input event + if (!currentNoteValue->empty()) { + AddNote(*currentNoteValue); + // Clear the textarea by setting its value to empty string + noteInput->SetInnerHTML(""); + *currentNoteValue = ""; // Reset the stored value + } + }); +} \ No newline at end of file diff --git a/examples/Website/frontend/project.json b/examples/Website/frontend/project.json new file mode 100644 index 0000000..8d02876 --- /dev/null +++ b/examples/Website/frontend/project.json @@ -0,0 +1,17 @@ +{ + "name": "main", + "configurations": [ + { + "name": "executable", + "implementations": ["main"], + "target": "wasm32-wasi", + "debug" : true, + "dependencies": [ + { + "path":"../../../project.json", + "configuration":"lib-debug" + } + ] + } + ] +} \ No newline at end of file diff --git a/examples/Website/frontend/run.sh b/examples/Website/frontend/run.sh new file mode 100755 index 0000000..e706621 --- /dev/null +++ b/examples/Website/frontend/run.sh @@ -0,0 +1 @@ +caddy file-server --listen :8080 --root bin/executable \ No newline at end of file