Skip to content

Commit

Permalink
Merge pull request #3 from geofmureithi/develop
Browse files Browse the repository at this point in the history
v0.2 Release
  • Loading branch information
geofmureithi authored Oct 1, 2022
2 parents d7891a3 + cdd1dc1 commit e31f1f0
Show file tree
Hide file tree
Showing 54 changed files with 1,149 additions and 787 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/browser.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
name: Integration Tests

on: [push, pull_request]

jobs:
Expand All @@ -10,4 +12,6 @@ jobs:
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

- run: wasm-pack test --headless --chrome
working-directory: crates/hirola-core
- run: wasm-pack test --headless --firefox
working-directory: crates/hirola-core
16 changes: 16 additions & 0 deletions .github/workflows/unit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Unit Tests

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- run: cargo test
working-directory: crates/hirola-core
48 changes: 44 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
[package]
name = "hirola"
version = "0.1.7"
version = "0.2.0"
authors = ["Geoffrey Mureithi <[email protected]>"]
description = "A html library for building client side webapps"
description = "Hirola is an un-opinionated web framework that is focused on simplicity and predictability"
repository = "https://github.com/geofmureithi/hirola"
documentation = "https://docs.rs/hirola"
documentation = "https://hirola-docs.vercel.app"
readme = "README.md"
license = "MIT OR Apache-2.0"
keywords = ["wasm", "html", "dom", "web"]
edition = "2021"

[dependencies]
hirola-core = { path = "crates/hirola-core", version = "0.1.7" }
hirola-macros = { path = "crates/hirola-macros", version = "0.1.7" }
hirola-form = { path = "crates/hirola-form", version = "0.1.7", optional = true }
hirola-core = { path = "crates/hirola-core", version = "0.2.0" }
hirola-macros = { path = "crates/hirola-macros", version = "0.2.0" }
hirola-form = { path = "crates/hirola-form", version = "0.2.0", optional = true }


[features]
Expand Down
6 changes: 5 additions & 1 deletion INSTALATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@ fn home() -> Dom {
}

fn main() {
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let body = document.body().unwrap();

let mut app = HirolaApp::new();
app.mount("body", home);
app.mount(&body, home);
}

```
Expand Down
119 changes: 62 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,98 +1,103 @@
# Hirola

[![Latest Version](https://img.shields.io/crates/v/hirola.svg)](https://crates.io/crates/hirola)
[![Build Status](https://travis-ci.org/geofmureithi/hirola.svg?branch=master)](https://travis-ci.org/geofmureithi/hirola)
[![Browser Tests](https://github.com/geofmureithi/hirola/actions/workflows/browser.yml/badge.svg)](https://github.com/geofmureithi/hirola/actions/workflows/browser.yml)
[![Unit Tests](https://github.com/geofmureithi/hirola/actions/workflows/unit.yml/badge.svg)](https://github.com/geofmureithi/hirola/actions/workflows/unit.yml)
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)

**Hirola** is an opinionated web framework for that is focused on simplicity and predictability.
**Hirola** is an un-opinionated webf ramework that is focused on simplicity and predictability.

## Goals

1. Keep it simple. Most Rust web frameworks have a huge learning curve and verbose syntaxes. We yearn to minimize these.
1. Keep it simple. A simple and declarative way to build web UIs in rust with a small learning curve.
2. Make it easy to read, extend and share code. Mixins and components are kept simple and macro-free.
3. No Context. You can choose passing props down, and/or use the global-state if routing. You can write hook-like functions though.
4. Familiality. Uses rsx which is very similar to JSX.
3. No context, you can choose passing props down, and/or use the `global-state`.
4. Familiality. Uses rsx which is very similar to jsx.

Here is a simple example:
## Example

We are going to create a simple counter program.

```
cargo new counter
```

With a new project, we need to create an index file which is the entry point and required by trunk

```
cd counter
```

Create an `index.html` in the root of counter. Add the contents below

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hirola Counter</title>
<body></body>
</head>
</html>
```

Lets add some code to `src/main.rs`

```rust
use hirola::prelude::*;

fn counter(_: &HirolaApp) -> Dom {
let state = Signal::new(99);
let decerement = state.mut_callback(|count, _| *count - 1);
let incerement = state.mut_callback(|count, _| *count + 1);

fn counter(app: &HirolaApp) -> Dom {
let count = Signal::new(0);
let increment = count.mut_callback(|c, _| c + 1)
html! {
<div>
<button on:click={decerement}>"-"</button>
<input value={state.get()} disabled/>
<button on:click={incerement}>"+"</button>
<button on:click=increment>"Increment"</button>
<span>{count.get()}</span>
</div>
}
}

fn main() {
let mut app = HirolaApp::new();
app.mount("body", counter);
}

```

### Mixins

Mixins are hirola's way of extending functionality and following DRY principles. Here is an example:
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let body = document.body().unwrap();

```rust
// Mixin that controls tailwind opacity based on a bool signal
fn opacity<'a>(signal: &'a Signal<bool>) -> Box<dyn Fn(DomNode) -> () + 'a> {
let cb = move |node: DomNode| {
let element = node.unchecked_into::<Element>();
if *signal.get() {
element.class_list().add_1("opacity-100").unwrap();
element.class_list().remove_1("opacity-0").unwrap();
} else {
element.class_list().add_1("opacity-0").unwrap();
element.class_list().remove_1("opacity-100").unwrap();
}
};
Box::new(cb)
let app = HirolaApp::new();
app.mount(&body, counter);
}
```

You can now use you mixin on a dom node eg:
Now lets run our project

```rust
html! {
<div class="bla blah" mixin:transition=opacity(&display)/>
}
```
trunk serve
```

Since you are passing a signal, you can now manipulate the signal to change the opacity.

Mixins run in namespaces, eg the one above is run in `transition` namespace.
This allows you to only run specific mixins. The inbuilt form mixins can only be run in `mixin:form` namespace.
You should be able to get counter running: [Live Example](https://hirola-docs.vercel.app/basics/getting-started)

## Ecosystem

Check out [Hirola Docs](https://hirola-docs.vercel.app/basics/getting-started) written with Hirola itself!

Here are some extensions for hirola:

1. [Form](https://crates.io/crates/hirola-form)
1. [Form](https://hirola-docs.vercel.app/plugins/form)
2. [Router](https://hirola-docs.vercel.app/plugins/router)
3. [State](https://hirola-docs.vercel.app/plugins/state)

### Milestones

| Status | Goal | Labels |
| :----: | :------------------------------------------------------------------------ | ------------- |
|| Write code that is declarative and easy to follow | `ready` |
|| Allow extensibility via mixins | `ready` |
| | [Standardize Components](https://github.com/geofmureithi/hirola/issues/1) | `inprogress` |
| 🚀 | SSR First Approach | `help wanted` |
| 🚀 | Hydration | `help wanted` |
| 🚀 | Serverside integrations | `help wanted` |
| Status | Goal | Labels |
| :----: | :------------------------------------------------------------------------ | ------- |
|| Write code that is declarative and easy to follow | `ready` |
|| Allow extensibility via mixins | `ready` |
| 🚀 | [Standardize Components](https://github.com/geofmureithi/hirola/issues/1) | `ready` |
| 🚀 | SSR | `ready` |
| 🚀 | Hydration | `todo` |
| 🚀 | Serverside integrations | `todo` |

### Inspiration

- Sycamore/Maple
- Sycamore
- Alpine.js
- React.js
- Yew
Expand Down
10 changes: 8 additions & 2 deletions crates/hirola-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "hirola-core"
version = "0.1.7"
version = "0.2.0"
authors = ["Geoffrey Mureithi <[email protected]>"]
edition = "2021"
description = "An html library for building client side webapps"
Expand All @@ -15,8 +15,10 @@ keywords = ["wasm", "html", "dom", "web"]

[dependencies]
chrono = { version = "0.4", features = ["wasmbind"] }
anyhow = "1.0"
thiserror = "1.0"
html-escape = { version = "0.2.7", optional = true }
hirola-macros = { path = "../hirola-macros", version = "0.1.3" }
hirola-macros = { path = "../hirola-macros", version = "0.2.0" }
ref-cast = "1.0"
serde = { version = "1.0", optional = true }
wasm-bindgen = { version = "0.2", optional = true }
Expand All @@ -25,6 +27,8 @@ matchit = { version = "0.6", optional = true }
anymap = { version = "1.0.0-beta.2", optional = true }
wasm-bindgen-futures = { version = "0.4.29", optional = true }



[dependencies.web-sys]
features = [
"console",
Expand All @@ -50,6 +54,8 @@ version = "0.3"
[dev-dependencies]
criterion = {version = "0.3", features = ["html_reports"]}
wasm-bindgen-test = "0.3"
hirola = { path ="../../" }
web-sys = { version = "0.3", features =["DomTokenList", "Element", "Window"]}

[features]
default = ["dom", "wasm-bindgen", "web-sys"]
Expand Down
12 changes: 3 additions & 9 deletions crates/hirola-core/src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,9 @@ impl HirolaApp {
}

/// Render a view

pub fn mount<M: Mountable>(self, element: &str, view: M) {
#[cfg(not(feature = "ssr"))]
{
let window = web_sys::window().unwrap();
let document = window.document().unwrap();

render_to(|| view.mount(&self), &document.body().unwrap());
}
#[cfg(not(feature = "ssr"))]
pub fn mount<M: Mountable>(self, element: &web_sys::Node, view: M) {
render_to(|| view.mount(&self), element);
}

/// Extend global data
Expand Down
Loading

0 comments on commit e31f1f0

Please sign in to comment.