Git Product home page Git Product logo

livid's Introduction

Livid

Livid is a single header C++ wasm frontend library leveraging Emscripten.

Usage

The code looks something like this:

#include "livid/livid.hpp"
#include <string>

using namespace livid;

int main() {
    int count = 0;

    // This sets the document title
    Document::title("Hello");

    Widget div(WidgetType::Div);

    Widget result(WidgetType::Div);
    // We set the id to conveniently access the widget by id in the callback
    result.id("result");
    result.text("0");
    result.style(Style::FontSize, "22px");

    Widget btn1(WidgetType::Button);
    // This sets the textContent element property
    btn1.text("Increment!");
    // We set the style color to green
    btn1.style(Style::Color, "green");
    // This signals that clicks call the inc function
    btn1.handle(Event::Click, [&](auto) {
        count += 1;
        Console::log("%d", count);
        auto result = Widget::from_id("result");
        result.text(std::to_string(count));
    });
    // widgets are automatically appended to body, here we want to append to the div
    div.append(btn1);

    Widget btn2(WidgetType::Button);
    btn2.text("Decrement!");
    btn2.style(Style::Color, "red");
    btn2.handle(Event::Click, [&, result](auto) mutable {
        count -= 1;
        Console::log("%d", count);
        result.text(std::to_string(count));
    });
    div.append(btn2);

    // we get all elements by tagName BUTTON
    auto elems = Document::elems_by_tag("BUTTON");
    for (auto &elem : elems) {
        // set their fontSize to 22 pixesl
        elem.style(Style::FontSize, "22px");
    }
}

You can also use a builder pattern:

#include "livid/livid.hpp"
#include <string>

using namespace livid;

int main() {
    Form().klass("box").append(
        Div().klass("field") // the class attribute is used by many css libs for styling elements of the same class
            .append(Label().klass("label").text("Email"))
            .append(
                Div().klass("control").append(
                    Input()
                        .klass("input")
                        .attr("type", "email")
                        .attr("placeholder", "[email protected]")
                    )
                )
            .append(
                Div().klass("field").append(
                    Label().klass("label").text("Password")).append(
                        Div().klass("control").append(
                            Input()
                                .klass("input")
                                .attr("type", "password")
                                .attr("placeholder", "*******")
                        )
                    )
                )
            .append(Button().klass("button is-primary").text("Sign in"))
    );
}

This uses Bulma for css styling. image

You can also use an elmish architecture for your application:

#include "livid/livid.hpp"
#include <string>

using namespace livid;

class AppState {
    static inline int counter = 0;

  public:
    static void increment(emscripten::val) { counter++; update(); }
    
    static void decrement(emscripten::val) { counter--; update(); }
    
    static void update() { Widget::from_id("result").text(std::to_string(counter)); }
    
    static void view() {
        Div()
            .append(Button().text("+").handle(Event::Click, increment))
            .append(Button().text("-").handle(Event::Click, decrement))
            .append(Div().id("result").text(std::to_string(counter)));
    }
};

int main() {
    AppState::view();
}

Building

Assuming you have a working installation of Emscripten:

If you clone this repo, from the root you can directly invoke em++ to build any of the examples:

$ em++ -s WASM=1 -s EVAL_CTORS=2 --bind -std=c++17 -O3 -Iinclude examples/counter.cpp -o index.html --shell-file my_shell.html

With CMake: You need a CMakeLists.txt file with contents similar to:

cmake_minimum_required(VERSION 3.15)
project(cmake_livid_example)

set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-s WASM=1 -s EVAL_CTORS=2 --bind")

include(FetchContent)
FetchContent_Declare(
    LIVID
    GIT_REPOSITORY https://github.com/MoAlyousef/livid
    GIT_TAG main
    GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(LIVID)

add_executable(index main.cpp)
set_target_properties(index PROPERTIES SUFFIX .html)
target_compile_features(index PRIVATE cxx_std_17)
target_link_options(index PRIVATE --shell-file ${CMAKE_CURRENT_LIST_DIR}/my_shell.html)
target_link_libraries(index PRIVATE livid::livid)

Then configure with emcmake cmake -Bbin -DCMAKE_BUILD_TYPE=Release, and build with cmake --build bin.

There's also a Makefile in the examples directory (under make_proj) if you prefer to use make.

The build usually outputs 3 files, an html, wasm and js files, you need all 3 to run your program. Building in release mode (-O3 or -DCMAKE_BUILD_TYPE=Release), the total size of a simple project is around 30kb.

Running

Opening the html file directly in the browser won't work. To run, you need a server to serve the generated html file:

$ python3 -m http.server --directory .

Or you can use emrun which is provided by emscripten.

emrun opens a browser automatically, if you use another server program, you need to open your wasm-capable browser to the provided url, which is usually something like 127.0.0.1:8000

Html shell

You'll notice that the repo has a minimal shell which you can use, it's passed as an argument to emscripten. You can replace it with whatever shell you prefer, and include css etc. The login example uses Bulma for CSS:

<!doctype html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css">
    <title>My app</title>
  </head>
  <body>
  {{{ SCRIPT }}}
  </body>
</html>

Documentation

Still a work in progress, you can generate it using doxygen livid.dox.

livid's People

Contributors

moalyousef avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.