livid

livid is a lightweight frontend Rust crate for creating web apps via webassembly. - Thin wrapper around web-sys - No vdom. - No macros!

Requirements

rustup target add wasm32-unknown-unknown

Usage

cargo install livid-cli

In your Rust source file: ```rust,no_run use livid::{enums::, prelude::, *};

enum Action { Increment(i32), Decrement(i32), }

fn btn(action: Action) -> button::Button { let (label, color, step) = { match action { Action::Increment(v) => ("Increment", Color::Green, v), Action::Decrement(v) => ("Decrement", Color::Red, -v), } }; let btn = button::Button::default().withlabel(label); btn.setlabelsize(20); btn.setlabelcolor(color); btn.setmargin(10); btn.setpadding(10); btn.setframe(FrameType::RFlatBox); btn.addcallback(Event::Click, move || { let frame = widget::Widget::fromid("result").unwrap(); let mut old: i32 = frame.textcontent().unwrap().parse().unwrap(); old += step; frame.settextcontent(Some(&old.to_string())); }); btn }

fn main() { let win = window::Window::default().withsize(400, 300); win.setcolor(Color::Rgb(Rgb(250, 250, 250))); let col = group::Column::defaultfill(); col.setjustifycontent(AlignContent::Center); btn(Action::Increment(1)); let f = frame::Frame::default().withlabel("0").withid("result"); f.setpadding(20); f.setlabelsize(20); btn(Action::Decrement(1)); col.end(); win.end(); } ```

image

livid build or livid serve

livid deploy --width=600 --height=400

Low-level api

Livid also a lower level widgets api:

```rust,no_run use livid::{enums::, prelude::, *};

fn div() -> widget::Widget { widget::Widget::new(WidgetType::Div) }

fn btn(i: i32) -> widget::Widget { let btn = widget::Widget::new(WidgetType::Button); let (label, col) = if i > 0 { ("Increment", "Green") } else { ("Decrement", "Red") }; btn.settextcontent(Some(label)); btn.setstyle(Style::Color, col); btn.addcallback(Event::Click, move || { let result = widget::Widget::fromid("result").unwrap(); let mut old: i32 = result.textcontent().unwrap().parse().unwrap(); old += i; result.settextcontent(Some(&old.tostring())); }); btn }

fn main() { document::Document::get().set_title("Counter");

let btn_inc = btn(1);
let btn_dec = btn(-1);

let main_div = div();
main_div.append(&btn_inc);
main_div.append(&btn_dec);

let result = div();
result.set_id("result");
result.set_text_content(Some("0"));
result.set_style(Style::FontSize, "22px");

let btns = document::Document::get().get_elements_by_tag_name("BUTTON");
for btn in btns.iter() {
    // set their fontSize to 22 pixesl
    btn.set_style(Style::FontSize, "22px");
}

} ```

Low level example with CSS

```rust,no_run use livid::{ document::Document, enums::WidgetType::{self, *}, widget::Widget, };

fn w(typ: WidgetType) -> Widget { Widget::new(typ) }

fn main() { Document::get().settitle("Form"); Document::addcsslink("https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css"); Document::addcss_link("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css");

let form = w(Form);
form.set_class_name("box");
form.append(&{
    let div = w(Div);
    div.set_class_name("field");
    div.append(&{
        let label = w(Label);
        label.set_class_name("label");
        label.set_inner_html(r#"<span class='fa fa-envelope'></span> Email"#);
        label
    });
    div.append(&{
        let div = w(Div);
        div.set_class_name("control");
        div.append(&{
            let inp = w(Input);
            inp.set_class_name("input");
            inp.set_attribute("type", "email").unwrap();
            inp.set_attribute("placeholder", "m@gmail.com").unwrap();
            inp
        });
        div
    });
    div
});

} ```

image

Higher-level api

Livid is unopinionated. You can build higher-level abstractions on top: ```rust,no_run mod detail; // we define an OnEvent trait for our buttons use crate::detail::{OnEvent, App, Settings}; use livid::{enums::, prelude::, *};

[derive(Default, Copy, Clone)]

struct Counter { value: i32, }

[derive(Debug, Clone, Copy)]

enum Message { IncrementPressed, DecrementPressed, }

impl App for Counter { type Message = Message;

fn new() -> Self {
    Self::default()
}

fn title(&self) -> String {
    String::from("Counter - livid")
}

fn update(&mut self, message: Message) {
    match message {
        Message::IncrementPressed => {
            self.value += 1;
        }
        Message::DecrementPressed => {
            self.value -= 1;
        }
    }
}

fn view(&mut self) {
    let col = group::Column::default_fill();
    button::Button::default()
        .with_label("Increment")
        .on_trigger(Message::IncrementPressed);
    frame::Frame::default().with_label(&self.value.to_string());
    button::Button::default()
        .with_label("Decrement")
        .on_trigger(Message::DecrementPressed);
    col.end();
}

}

fn main() { Counter::new().run(Settings { size: (300, 200), win_color: Some(Color::Rgb(Rgb(250, 250, 250))), ..Default::default() }) } ```

Check the examples directory for fuller examples.