utkarshkukreti / markup.rs

A blazing fast, type-safe template engine for Rust.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Component way CSS

imbolc opened this issue · comments

commented

I was thinking on a possibility of rendering a <style> tag once with multiple component usage. Here's what I ended up with. What do you think on the approach? Would you consider adding something like this into the markup?

use std::any::type_name;
use std::cell::Cell;
use std::collections::HashSet;

#[derive(Default)]
pub struct CssOnce(Cell<HashSet<&'static str>>);

impl CssOnce {
    fn new() -> Self {
        Self::default()
    }

    fn insert<T>(&self) -> bool {
        let mut inner = self.0.take();
        let inserted = inner.insert(type_name::<T>());
        self.0.set(inner);
        inserted
    }
}

macro_rules! css_once {
    ($rend:ident, $($str:tt)+) => {
        if CssOnce::insert::<Self>($rend) {
            markup::raw(concat!("<style>", $($str),+, "</style>\n"))
        } else {
            markup::raw("")
        }
    };
}

markup::define! {
    Hello<'a>(
        css: &'a CssOnce,
        name: &'a str,
    ) {
        @css_once!(css,
            ".hello { background: blue }"
            ".hello b { color: yellow }"
        )
        p.hello { "Hello, " b { @name } }
    }

    Body<'a>(
        css: &'a CssOnce,
    ) {
        @Hello {css, name: "World"}
        @Hello {css, name: "Self"}
    }
}

fn main() {
    let css = CssOnce::new();
    println!("{}", Body { css: &css });
}