inline-css 0.0.3

Embed CSS directly in your Rust code
Documentation
// Copyright (C) 2023 Benjamin Stürz
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
use crate as inline_css;
use inline_css::*;

fn simple_selector(s: &str) -> Selector {
    Selector::Simple {
        ty: Some(s.into()),
        class: None,
        id: None,
    }
}

fn simple_decl(name: &str, v: Value) -> Declaration {
    Declaration {
        name: name.into(),
        value: vec![v],
    }
}

fn simple_css(sname: &str, dname: &str, dval: Value) -> CSS {
    CSS(vec![
        Rule {
            selector: simple_selector(sname),
            declarations: vec![simple_decl(dname, dval)],
        }
    ])
}

#[test]
fn extern_int() {
    let x = 42;
    let css = css! {
        h1 {
            width: {x};
        }
    };
    let css2 = simple_css("h1", "width", Value::Int(x, "".into()));
    assert_eq!(css, css2);
}

#[test]
fn simple() {
    let css = css! {
        h1 {
            color: red;
        }
    };
    let css2 = simple_css("h1", "color", Value::Ident("red".into()));
    assert_eq!(css, css2);
}


#[test]
fn custom_color() {
    #[allow(dead_code)]
    enum Color {
        Red,
        Green,
        Blue,
    }

    impl Into<Value> for Color {
        fn into(self) -> Value {
            let color = match self {
                Self::Red   => "red",
                Self::Green => "green",
                Self::Blue  => "blue",
            };
            Value::Ident(color.into())
        }
    }
    let red = Color::Red;
    let css = css! {
        h1 {
            color: {red};
        }
    };
    let css2 = simple_css("h1", "color", Value::Ident("red".into()));
    assert_eq!(css, css2);
}

#[test]
fn multiple_selectors() {
    let css = css! {
        h1, h2 {
            padding: 10px;
        }
    };

    let css2 = CSS(vec![
        Rule {
            selector: Selector::Comma {
                left: Box::new(simple_selector("h1")),
                right: Box::new(simple_selector("h2")),
            },
            declarations: vec![simple_decl("padding", Value::Int(10, "px".into()))],
        }
    ]);
    assert_eq!(css, css2);
}

#[test]
fn color_code() {
    let css = css! {
        p {
            color: #0xff00ff;
        }
    };
    let css2 = simple_css("p", "color", Value::ColorCode(0xff00ff));
    assert_eq!(css, css2);
}

#[test]
fn int_perc() {
    let css = css! {
        h1 {
            width: 50%;
        }
    };
    let css2 = simple_css("h1", "width", Value::Int(50, "%".into()));
    assert_eq!(css, css2);
}

#[test]
fn real_world() {
    let _css = css! {
      :root {
            /* Foreground Colors */
            --primaryfg1: #0xe0e0e0;
            --primaryfg2: #0xf0f0f0;

            /* Background Colors */
            --primarybg1: #0x808080;
            --primarybg2: #0x909090;
            --primarybgh: #0xa0a0a0;
            --secondarybg1: #0xe0e0e0;
            --secondarybg2: #0xe8e8e8;
            --secondarybgh: #0xd0d0d0;
        }

        .files {
            list-style-type: none;
            padding: 0;
            margin: 0;
        }

        .files li {
            display: flex;
            margin-top: -1px;
            border: 1px solid black;
            width: 100%;
            background-color: var(--secondarybg1);
        }

        .files li:nth-child(even) {
            background-color: var(--secondarybg2);
        }

        .files li:hover {
            background-color: var(--secondarybgh);
        }

        .files .tools button {
            background-color: inherit;
            color: inherit;
            border: none;
        }

        .files .tools div {
            background-color: var(--primarybg1);
            padding-left: 0.5m;
            padding-right: 0.5m;
            color: var(--primaryfg1);
        }

        .files .tools div:nth-child(even) {
            background-color: var(--primarybg2);
        }

        .files .tools div:hover {
            background-color: var(--primarybgh);
        }

        .files .tools div form {
            display: none;
            position: absolute;
            background-color: var(--primarybgh);
            left: 0.5m;
            padding: 0.5m;
        }

        .files .tools div:hover form {
            display: block;
        }

        .files .item {
            flex-direction: row;
            justify-content: space-between;
        }

        .files .item a {
            margin-left: 0.5m;
        }

        .files-dropdown button {
            background-color: var(--primarybg1);
            color: var(--primaryfg1);
            margin: 0;
            border: none;
            float: right;
        }

        .files-dropdown div {
            display: none;
            border: none;
            margin-right: 1m;
            background-color: var(--primarybgh);
        }

        .files-dropdown div a {
            color: var(--primaryfg2);
        }

        .files-dropdown:hover div {
            display: flex;
        }
    };
}

#[test]
fn selector_any() {
    let css = css_rule! {
        * {
            box-sizing: border-box;
        }
    };

    let css2 = Rule {
        selector: Selector::Any,
        declarations: vec![
            Declaration {
                name: "box-sizing".into(),
                value: vec![Value::Ident("border-box".into())],
            }
        ]
    };

    assert_eq!(css, css2);
}