origami_engine/lib.rs
1//! # Origami Engine
2//! A Rust templating engine that allows for rendering HTML elements and building reusable components.
3//!
4//! ## Props Passing
5//!
6//! You can pass props to components to customize their behavior and appearance. Below is an example of a homepage and an about page, both utilizing a button component with various attributes.
7//! ```rust
8//! use origami_engine::comp;
9//!
10//! // Define a button component that takes props
11//! comp! {
12//! button_component(attr, label) =>
13//! button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600" @attr; {
14//! @label;
15//! }
16//! }
17//!
18//! // Define the homepage component
19//! comp! {
20//! home =>
21//! div {
22//! h1 { "Welcome to the Homepage!" }
23//! // Use the button_component with props
24//! call button_component { attr { onclick="alert('clicked')" }, label { "Click Me" } }
25//! }
26//! }
27//!
28//! let html = home!();
29//!
30//! assert_eq!(
31//! html.0,
32//! r#"<div><h1>Welcome to the Homepage!</h1><button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600" onclick="alert('clicked')">Click Me</button></div>"#
33//! );
34//!
35//! // Define the about page component
36//! comp! {
37//! about =>
38//! div {
39//! h1 { "About Us" }
40//! p { "We are committed to delivering quality service." }
41//! // Use the button_component with props
42//! call button_component { attr { onclick="alert('clicked learn more')" }, label { "Learn More" } }
43//! }
44//! }
45//!
46//! let html = about!();
47//! assert_eq!(
48//! html.0,
49//! r#"<div><h1>About Us</h1><p>We are committed to delivering quality service.</p><button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600" onclick="alert('clicked learn more')">Learn More</button></div>"#
50//! );
51//! ```
52//!
53//! ## Layout
54//!
55//! You can create a layout structure that includes a navigation bar, a body for dynamic content, and a footer. Below is an example demonstrating this layout.
56//!
57//! ```rust
58//! use origami_engine::comp;
59//!
60//! // Define a layout component with a navigation bar, body, and footer
61//! comp! {
62//! layout_component(content) =>
63//! // Navigation bar
64//! nav {
65//! ul {
66//! li { a { "Home" } }
67//! li { a { "About" } }
68//! li { a { "Contact" } }
69//! }
70//! }
71//! // Body placeholder for dynamic content
72//! main {
73//! @content;
74//! }
75//! // Footer
76//! footer {
77//! p { "© 2024 Your Company" }
78//! }
79//! }
80//!
81//! // Define the homepage component using the layout
82//! comp! {
83//! home =>
84//! call layout_component {
85//! content {
86//! h1 { "Welcome to the Homepage!" }
87//! p { "This is the main content of the homepage." }
88//! }
89//! }
90//! }
91//!
92//! let html = home!(cap => 250); // It is recommended to provide `cap`, i.e., the maximum length of html
93//! // to avoid unnecessary reallocations of strings
94//! assert_eq!(
95//! html.0,
96//! r#"<nav><ul><li><a>Home</a></li><li><a>About</a></li><li><a>Contact</a></li></ul></nav><main><h1>Welcome to the Homepage!</h1><p>This is the main content of the homepage.</p></main><footer><p>© 2024 Your Company</p></footer>"#
97//! );
98//!
99//! // Define the about page component using the layout
100//! comp! {
101//! about =>
102//! call layout_component {
103//! content {
104//! h1 { "About Us" }
105//! p { "We are committed to delivering quality service." }
106//! }
107//! }
108//! }
109//!
110//! let html = about!(cap => 250); // It is recommended to provide `cap`, i.e., the maximum length of html
111//! // to avoid unnecessary reallocations of strings
112//! assert_eq!(
113//! html.0,
114//! r#"<nav><ul><li><a>Home</a></li><li><a>About</a></li><li><a>Contact</a></li></ul></nav><main><h1>About Us</h1><p>We are committed to delivering quality service.</p></main><footer><p>© 2024 Your Company</p></footer>"#
115//! );
116//! ```
117//! ## Escape and Noescape
118//!
119//! You can use `escape` and `noescape` to control HTML escaping behavior in the template (`html_escape` is feature is required):
120//!
121//! ```rust
122//! #[cfg(feature = "html_escape")]
123//! {
124//! use origami_engine::comp;
125//!
126//! comp! {
127//! foo =>
128//! div noescape {
129//! div { "<div>Unsafe HTML</div>" } // Inherited, this will not be escaped
130//! div escape {
131//! "<div>Safe HTML</div>" // This will be escaped
132//! }
133//! }
134//! }
135//!
136//! let html = foo!();
137//! assert_eq!(html.0, "<div><div><div>Unsafe HTML</div></div><div><div>Safe HTML</div></div></div>");
138//! }
139//! ```
140//!
141//! You can also use `noescape` or `escape` with conditional rendering:
142//!
143//! ```rust
144//! #[cfg(feature = "html_escape")]
145//! {
146//! use origami_engine::comp;
147//!
148//! let text = "bar";
149//!
150//! comp! {
151//! foo =>
152//! div noescape {
153//! if text == "foo"; noescape {
154//! "<div>Unsafe HTML</div>"
155//! } else if text == "bar"; escape {
156//! "<div>Safe HTML</div>"
157//! } else noescape {
158//! "<div>Default HTML</div>"
159//! }
160//! }
161//! }
162//!
163//! let html = foo!();
164//! assert_eq!(html.0, "<div><div>Safe HTML</div></div>");
165//! }
166//! ```
167//!
168//! Or with expressions:
169//!
170//! ```rust
171//! #[cfg(feature = "html_escape")]
172//! {
173//! use origami_engine::comp;
174//!
175//! let text = "<div>foo</div>";
176//! comp! {
177//! foo =>
178//! div { @text;! }
179//! }
180//!
181//! let html = foo!();
182//! assert_eq!(html.0, "<div><div>foo</div></div>");
183//! }
184//! ```
185//!
186//! Or with literals:
187//!
188//! ```rust
189//! #[cfg(feature = "html_escape")]
190//! {
191//! use origami_engine::comp;
192//!
193//! comp! {
194//! foo =>
195//! div {
196//! "<div>foo</div>"!
197//! }
198//! }
199//!
200//! let html = foo!();
201//! assert_eq!(html.0, "<div><div>foo</div></div>");
202//! }
203//! ```
204//!
205//! Or match expressions:
206//! ```rust
207//! #[cfg(feature = "html_escape")]
208//! {
209//! use origami_engine::comp;
210//!
211//! let text = "foo";
212//! comp! {
213//! foo =>
214//! div {
215//! match text; noescape {
216//! "foo" => {
217//! "<div>foo</div>" // Inherited, this will not be escaped
218//! },
219//! _ => escape {
220//! "<div>foo</div>" // This will be escaped
221//! }
222//! }
223//! }
224//! }
225//!
226//! let html = foo!();
227//! assert_eq!(html.0, "<div><div>foo</div></div>");
228//! }
229//! ```
230
231pub use origami_macros::anon;
232pub use origami_macros::comp;
233
234#[derive(Debug, Clone)]
235pub struct Origami(pub String);
236
237#[cfg(feature = "html_escape")]
238#[doc(no_inline)]
239pub use html_escape::encode_text_to_string;
240
241#[cfg(feature = "minify_html")]
242#[doc(no_inline)]
243pub use minify_html::*;
244
245#[cfg(feature = "axum")]
246use ::axum::response::{Html, IntoResponse, Response};
247#[cfg(feature = "axum")]
248impl IntoResponse for Origami {
249 fn into_response(self) -> Response {
250 Html(self.0).into_response()
251 }
252}