├── .gitignore ├── Cargo.toml ├── www ├── index.html └── css │ └── style.css ├── Makefile ├── README ├── Cargo.lock └── src └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | out/ 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wrust" 3 | version = "0.1.0" 4 | authors = ["Huy Tran "] 5 | 6 | [dependencies] 7 | stdweb = "*" 8 | -------------------------------------------------------------------------------- /www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | App 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: clean asmjs copy 2 | 3 | clean: 4 | rm -rf target/asmjs-unknown-emscripten/debug/wrust.* out 5 | 6 | asmjs: 7 | cargo build --target=asmjs-unknown-emscripten 8 | 9 | copy: 10 | mkdir out 11 | cp -rf www/* out 12 | cp target/asmjs-unknown-emscripten/debug/wrust.js out/main.js 13 | -------------------------------------------------------------------------------- /www/css/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | width: 100%; height: 100%; 3 | margin: 0; padding: 0; 4 | background: #FAFAFA; 5 | font-family: "Monaco", monospace; 6 | font-size: 14px; 7 | } 8 | 9 | #root { 10 | padding: 10px; 11 | } 12 | 13 | button { 14 | border: none; 15 | border-radius: 5px; 16 | background: #27ae60; 17 | color: #ffffff; 18 | padding: 5px; 19 | } 20 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | RUST WEB STARTER KIT 2 | -------------------- 3 | 4 | Template project for creating web app in Rust. 5 | 6 | This project use `stdweb` package for handling DOM manipulating and providing browser's API to Rust. 7 | 8 | To build the project, simply type: 9 | 10 | $ make 11 | 12 | The output will be populated to: 13 | 14 | > /out/main.js 15 | 16 | Run the web app with `index.html`. 17 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [root] 2 | name = "wrust" 3 | version = "0.1.0" 4 | dependencies = [ 5 | "stdweb 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 6 | ] 7 | 8 | [[package]] 9 | name = "dtoa" 10 | version = "0.4.1" 11 | source = "registry+https://github.com/rust-lang/crates.io-index" 12 | 13 | [[package]] 14 | name = "itoa" 15 | version = "0.3.1" 16 | source = "registry+https://github.com/rust-lang/crates.io-index" 17 | 18 | [[package]] 19 | name = "num-traits" 20 | version = "0.1.37" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | 23 | [[package]] 24 | name = "serde" 25 | version = "1.0.6" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | 28 | [[package]] 29 | name = "serde_json" 30 | version = "1.0.2" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | dependencies = [ 33 | "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 34 | "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 35 | "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", 36 | "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 37 | ] 38 | 39 | [[package]] 40 | name = "stdweb" 41 | version = "0.1.0" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | dependencies = [ 44 | "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 45 | "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 46 | ] 47 | 48 | [metadata] 49 | "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" 50 | "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" 51 | "checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" 52 | "checksum serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "38a3db3a5757f68069aba764b793823ea9fb9717c42c016f8903f8add50f508a" 53 | "checksum serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "48b04779552e92037212c3615370f6bd57a40ebba7f20e554ff9f55e41a69a7b" 54 | "checksum stdweb 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a771cb0c2ed37a23f3544fd252b1440e81760949eda5ef49cbeda68e93b14ac" 55 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate stdweb; 3 | 4 | use stdweb::web::{ 5 | document, 6 | INode, 7 | IEventTarget, 8 | IElement, 9 | Element 10 | }; 11 | use stdweb::web::event::ClickEvent; 12 | 13 | macro_rules! component { 14 | ( $name:ident => { 15 | init: $init_expression:block, 16 | render: $render_expression:expr 17 | } 18 | ) => ( 19 | struct $name { 20 | element: Element 21 | } 22 | 23 | impl $name { 24 | pub fn new() -> $name { 25 | let e = $name{ element: $init_expression }; 26 | e 27 | } 28 | 29 | pub fn get_element(&self) -> &Element { 30 | &self.element 31 | } 32 | 33 | pub fn render(&mut self) { 34 | $render_expression(&self.element); 35 | } 36 | } 37 | ) 38 | } 39 | 40 | macro_rules! mount_component { 41 | ($parent:expr, $target:expr, $element:ident) => { 42 | let target = $parent.query_selector($target).unwrap(); 43 | target.append_child($element.get_element()); 44 | $element.render(); 45 | } 46 | } 47 | 48 | macro_rules! html { 49 | ($html:expr) => { 50 | unsafe { 51 | js!( 52 | var parser = new DOMParser(); 53 | var el = parser.parseFromString($html, "text/html"); 54 | return el.documentElement; 55 | ).into_reference_unchecked() 56 | }.unwrap() 57 | } 58 | } 59 | 60 | component!(AppComponent => { 61 | init: { 62 | let e: Element = html!(" 63 |
64 |

65 | Hello 66 | World 67 |

68 | 69 |
70 | "); 71 | 72 | let mut button = GreenButton::new(); 73 | mount_component!(e, "GreenButton", button); 74 | 75 | e 76 | }, 77 | render: |this: &Element| { 78 | } 79 | }); 80 | 81 | component!(GreenButton => { 82 | init: { 83 | let button = document().create_element("button"); 84 | button.add_event_listener(move |_: ClickEvent| { 85 | js! { 86 | alert("Yo! This is the Green Button!"); 87 | } 88 | }); 89 | button 90 | }, 91 | render: |this: &Element| { 92 | this.set_text_content("This is a button"); 93 | } 94 | }); 95 | 96 | fn main() { 97 | stdweb::initialize(); 98 | 99 | let mut app = AppComponent::new(); 100 | mount_component!(document(), "#root", app); 101 | 102 | stdweb::event_loop(); 103 | } 104 | --------------------------------------------------------------------------------