1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! Savory is library for building user interface.
//!
//!
//! [](https://malrusayni.gitlab.io/savory/savory/)
//! ·
//! [](https://crates.io/crates/savory)
//! ·
//! [](https://gitlab.com/MAlrusayni/savory/pipelines)
//! ·
//! [](https://crates.io/crates/savory)
//! ·
//! [](https://github.com/rust-secure-code/safety-dance/)
//!
//! # Core Concept
//!
//! There are two main types in Savory, **Views** and **Elements**. View types
//! produce static HTML nodes, while Element types produce dynamic HTML nodes,
//! as simple as that.
//!
//! # View types
//!
//! View types implements [`View`] trait, this trait have one method that
//! generate the resulted HTML nodes, here is simple example:
//!
//! ```rust
//! # use savory::prelude::*;
//! struct HomePage;
//!
//! impl<Msg> View<Node<Msg>> for HomePage {
//! fn view(&self) -> Node<Msg> {
//! html::div().push("Home page")
//! }
//! }
//! ```
//!
//! # Element types
//!
//! Element types implements [`Element`] trait, most of the time elements have
//! logic inside them, they commonly carry their state inside them, and since
//! Savory follow Elm style we need message type and lastly we need config type
//! that is used to config the element on it's initialization, here is simple
//! example:
//!
//! ```rust
//! # use savory::prelude::*;
//! // Element module
//! struct Counter(u32);
//!
//! enum Msg {
//! Increase,
//! Decrease,
//! }
//!
//! impl Element for Counter {
//! type Config = u32;
//! type Message = Msg;
//!
//! fn init(config: u32, _orders: &mut impl Orders<Msg>) -> Self {
//! Counter(config)
//! }
//!
//! fn update(&mut self, msg: Self::Message, _orders: &mut impl Orders<Self::Message>) {
//! match msg {
//! Msg::Increase => self.0 += 1,
//! Msg::Decrease => self.0 -= 1,
//! }
//! }
//! }
//!
//! impl View<Node<Msg>> for Counter {
//! fn view(&self) -> Node<Msg> {
//! html::div()
//! .push(
//! html::button()
//! .push("+")
//! .on_click(|_| Msg::Increase)
//! )
//! .push(
//! html::button()
//! .push("-")
//! .on_click(|_| Msg::Decrease)
//! )
//! .push(html::h1().push(self.0.to_string()))
//! }
//! }
//! ```
//!
//! This example shows how to wirte counter element, so you can write your own
//! elements.
//!
//! ## Ecosystem
//!
//! - `savory` (this crate) - Core library for building user interface
//! - [`savory-router`] - Savory Router used to generate router for your app
//! - [`savory-style`] - Typed CSS style for Savory
//! - [`savory-elements`] - Collection of UI elements based on Savory
//! - [`savory-elements-derive`] - Crate that provide `Element` derive
//!
//! [`savory-router`]: https://malrusayni.gitlab.io/savory/savory_router/index.html
//! [`savory-style`]: https://malrusayni.gitlab.io/savory/savory_style/index.html
//! [`savory-elements`]: https://malrusayni.gitlab.io/savory/savory_elements/index.html
//! [`savory-elements-derive`]: https://malrusayni.gitlab.io/savory/savory_elements_derive/index.html
//! [`View`]: crate::view
//! [`Element`]: crate::prelude::Element
pub extern crate seed;
pub use web_sys;