Crate origami_engine

source
Expand description

§Origami Engine

A Rust templating engine that allows for rendering HTML elements and building reusable components.

§Props Passing

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.

use origami_engine::comp;

// Define a button component that takes props
comp! {
    button_component =>
    button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600" $attr {
        $label
    }
}

// Define the homepage component
comp! {
    home =>
    div {
        h1 { "Welcome to the Homepage!" }
        // Use the button_component with props
        @button_component! { attr { onclick="alert('clicked')" }, label { "Click Me" } };
    }
}

let html = home!();

assert_eq!(
    html.0,
    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>"#
);

// Define the about page component
comp! {
    about =>
    div {
        h1 { "About Us" }
        p { "We are committed to delivering quality service." }
        // Use the button_component with props
        @button_component! { attr { onclick="alert('clicked learn more')" }, label { "Learn More" } };
    }
}

let html = about!();
assert_eq!(
    html.0,
    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>"#
);

§Layout

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.

use origami_engine::comp;

// Define a layout component with a navigation bar, body, and footer
comp! {
    layout_component =>
    // Navigation bar
    nav {
        ul {
            li { a { "Home" } }
            li { a { "About" } }
            li { a { "Contact" } }
        }
    }
    // Body placeholder for dynamic content
    main {
        $content
    }
    // Footer
    footer {
        p { "© 2024 Your Company" }
    }
}

// Define the homepage component using the layout
comp! {
    home =>
    @layout_component! {
        content {
            h1 { "Welcome to the Homepage!" }
            p { "This is the main content of the homepage." }
        }
    };
}

let html = home!();
assert_eq!(
    html.0,
    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>"#
);

// Define the about page component using the layout
comp! {
    about =>
    @layout_component! {
        content {
            h1 { "About Us" }
            p { "We are committed to delivering quality service." }
        }
    };
}

let html = about!();
assert_eq!(
    html.0,
    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>"#
);

§Escape and Noescape

You can use escape and noescape to control HTML escaping behavior in the template (html_escape is feature is required):

#[cfg(feature = "html_escape")]
{
    use origami_engine::comp;

    comp! {
        foo =>
        div noescape {
            div { "<div>Unsafe HTML</div>" } // Inherited, this will not be escaped
            div escape {
                "<div>Safe HTML</div>" // This will be escaped
            }
        }
    }

    let html = foo!();
    assert_eq!(html.0, "<div><div><div>Unsafe HTML</div></div><div>&lt;div&gt;Safe HTML&lt;/div&gt;</div></div>");
}

You can also use noescape or escape with conditional rendering:

#[cfg(feature = "html_escape")]
{
    use origami_engine::comp;

    let text = "bar";

    comp! {
        foo =>
        div noescape {
            if text == "foo"; noescape {
                "<div>Unsafe HTML</div>"
            } else if text == "bar"; escape {
                "<div>Safe HTML</div>"
            } else noescape {
                "<div>Default HTML</div>"
            }
        }
    }

    let html = foo!();
    assert_eq!(html.0, "<div>&lt;div&gt;Safe HTML&lt;/div&gt;</div>");
}

Or with expressions:

#[cfg(feature = "html_escape")]
{
    use origami_engine::comp;

    let text = "<div>foo</div>";
    comp! {
        foo =>
        div { *text;! }
    }

    let html = foo!();
    assert_eq!(html.0, "<div><div>foo</div></div>");
}

Or with literals:

#[cfg(feature = "html_escape")]
{
    use origami_engine::comp;

    comp! {
        foo =>
        div {
            "<div>foo</div>"!
        }
    }

    let html = foo!();
    assert_eq!(html.0, "<div><div>foo</div></div>");
}

Or match expressions:

#[cfg(feature = "html_escape")]
{
    use origami_engine::comp;

    let text = "foo";
    comp! {
        foo =>
        div {
            match text; noescape {
                "foo" => {
                    "<div>foo</div>" // Inherited, this will not be escaped
                },
                _ => escape {
                    "<div>foo</div>" // This will be escaped
                }
            }
        }
    }

    let html = foo!();
    assert_eq!(html.0, "<div><div>foo</div></div>");
}

§Moveable Scripts

To create moveable scripts, assign a unique name to the script. You can then use this name below the component call.

§Example

use origami_engine::comp;

// Define a component that includes a moveable script named "bar_script"
comp! {
    bar =>
    div {
        "bar_component"
        script script_name="bar_script" {
            r#"function foo() {
                return "hello world";
            }"#
        }
    }
}

// Define another component that uses the previously defined component
comp! {
    foo =>
    div {
        "foo_component"
        @bar!(); // Include the bar component
    }
    // Use the moveable script below the component call
    script_use bar_script; // Include the script with the specified name
}

let html = foo!();

#[cfg(feature = "minify_html")] // `minify_html` is required to minify the script
assert_eq!(
    html.0,
    "<div>foo_component<div>bar_component</div></div><script>function foo() { return \"hello world\"; }</script>"
);

Re-exports§

Macros§

Structs§