add inventory

This commit is contained in:
annieversary 2022-07-02 16:42:02 +01:00
parent 47a260b7ee
commit 444dadedba
5 changed files with 122 additions and 12 deletions

View File

@ -3,7 +3,14 @@ name = "zephyr"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features]
default = []
inventory = ["dep:inventory"]
[dependencies] [dependencies]
once_cell = "1.10.0" inventory = { version = "0.3", optional = true }
[[example]]
name = "inventory"
required-features = ["inventory"]

View File

@ -1,6 +1,6 @@
fn main() { fn main() {
// this list would ideally be generated on the fly out of the written html, // this list of used classes would ideally be parsed out of the written html,
// but i don't want to unneeded dependencies to this crate // but i don't want to over complicate this example
let classes = [ let classes = [
"mt[10rem]", "mt[10rem]",
"color[#e20f00]", "color[#e20f00]",
@ -11,7 +11,7 @@ fn main() {
]; ];
let z = zephyr::Zephyr::new(); let z = zephyr::Zephyr::new();
let css = z.generate_css(&classes); let css = z.generate_classes(classes);
let html = format!( let html = format!(
r#" r#"

62
examples/inventory.rs Normal file
View File

@ -0,0 +1,62 @@
//! for situations where you have a set of components,
//! and you want to register the classes you use from different files without too much complexity
use zephyr::{register_class, Zephyr};
fn main() {
let z = Zephyr::new();
let generated_css = z.generate_from_inventory();
let head = head(&generated_css);
let header = header();
let body = body();
let html = format!(
r#"
<!DOCTYPE html>
<html>
{head}
<body>
{header}
{body}
</body>
</html>
"#
);
std::fs::write("./examples/index.html", html).unwrap();
}
fn head(generated_css: &str) -> String {
format!(
r#"
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style>{generated_css}</style>
</head>
"#
)
}
fn header() -> String {
let class = register_class!("color[#e20f00] color[green]hover content['*']$before");
format!(
r#"
<p class="{class}">
this text is red, but green on hover
</p>
"#
)
}
fn body() -> String {
let class = register_class!("mt[10rem] content[attr(after)]$after color[red]$after");
format!(
r#"
<p class="{class}" after="hi, this is an after text">
this text has a lot of margin
</p>
"#
)
}

36
src/inventory.rs Normal file
View File

@ -0,0 +1,36 @@
pub use inventory::submit;
use crate::Zephyr;
pub struct AddClassToInventory {
class: &'static str,
}
impl AddClassToInventory {
pub const fn new(class: &'static str) -> Self {
Self { class }
}
}
inventory::collect!(AddClassToInventory);
impl Zephyr {
pub fn generate_from_inventory(&self) -> String {
self.generate_classes(
inventory::iter::<AddClassToInventory>
.into_iter()
.map(|a| a.class),
)
}
}
#[macro_export]
macro_rules! register_class {
($c:literal) => {{
const C: &'static str = $c;
$crate::inventory::submit! {
$crate::inventory::AddClassToInventory::new(C)
}
C
}};
}

View File

@ -8,6 +8,10 @@ mod class;
mod defaults; mod defaults;
mod parse; mod parse;
#[cfg(feature = "inventory")]
#[macro_use]
pub mod inventory;
pub struct Zephyr { pub struct Zephyr {
/// for non-value rules /// for non-value rules
pub rules: HashMap<String, String>, pub rules: HashMap<String, String>,
@ -41,12 +45,13 @@ impl Zephyr {
} }
} }
pub fn generate_css(&self, classes: &[&str]) -> String { pub fn generate_classes<'a>(&self, classes: impl IntoIterator<Item = &'a str>) -> String {
// TODO when we have media queries, we can do something to group them together // TODO when we have media queries, we can do something to group them by the query, and then emit those together
classes classes
.into_iter() .into_iter()
.flat_map(|s| s.split_ascii_whitespace()) .flat_map(|s| s.split_ascii_whitespace())
// TODO skip duplicates, use hashset or smth
.flat_map(|c| self.generate_class(c)) .flat_map(|c| self.generate_class(c))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("") .join("")
@ -104,19 +109,19 @@ mod tests {
fn generate_classes_works() { fn generate_classes_works() {
let z = Zephyr::new(); let z = Zephyr::new();
let classes = z.generate_css(&["flex-row"]); let classes = z.generate_classes(["flex-row"]);
assert_eq!( assert_eq!(
classes, classes,
r#".flex-row { display: flex; flex-direction: row; }"# r#".flex-row { display: flex; flex-direction: row; }"#
); );
let classes = z.generate_css(&["m[3rem]hover,focus$placeholder"]); let classes = z.generate_classes(["m[3rem]hover,focus$placeholder"]);
assert_eq!( assert_eq!(
classes, classes,
r#".m\[3rem\]hover,focus\$placeholder:hover:focus::placeholder { margin: 3rem; }"# r#".m\[3rem\]hover,focus\$placeholder:hover:focus::placeholder { margin: 3rem; }"#
); );
let classes = z.generate_css(&["flex|hover,focus$placeholder"]); let classes = z.generate_classes(["flex|hover,focus$placeholder"]);
assert_eq!( assert_eq!(
classes, classes,
r#".flex\|hover,focus\$placeholder:hover:focus::placeholder { display: flex; }"# r#".flex\|hover,focus\$placeholder:hover:focus::placeholder { display: flex; }"#
@ -127,8 +132,8 @@ mod tests {
fn generate_multiple_works() { fn generate_multiple_works() {
let z = Zephyr::new(); let z = Zephyr::new();
let classes_joined = z.generate_css(&["flex-row mt[1rem]"]); let classes_joined = z.generate_classes(["flex-row mt[1rem]"]);
let classes_separate = z.generate_css(&["flex-row", "mt[1rem]"]); let classes_separate = z.generate_classes(["flex-row", "mt[1rem]"]);
assert_eq!( assert_eq!(
classes_joined, classes_joined,
r#".flex-row { display: flex; flex-direction: row; }.mt\[1rem\] { margin-top: 1rem; }"# r#".flex-row { display: flex; flex-direction: row; }.mt\[1rem\] { margin-top: 1rem; }"#