From b6b7df0a052517f9a586fe25fc9d3c7bd4fd1ca4 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Fri, 3 May 2024 00:32:12 +0800 Subject: [PATCH] feat: component theme --- Cargo.toml | 10 ++- thaw/Cargo.toml | 1 + thaw/src/config_provider/mod.rs | 88 +----------------------- thaw/src/global_style/mod.rs | 6 +- thaw/src/theme/color.rs | 89 ++++++++++++++++++++++++ thaw/src/theme/common.rs | 115 +------------------------------- thaw/src/theme/mod.rs | 5 ++ thaw_macro/Cargo.toml | 14 ++++ thaw_macro/src/lib.rs | 57 ++++++++++++++++ 9 files changed, 181 insertions(+), 204 deletions(-) create mode 100644 thaw_macro/Cargo.toml create mode 100644 thaw_macro/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 72f1c9a..5df07a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,17 @@ [workspace] resolver = "2" -members = ["thaw", "thaw_components", "thaw_utils", "demo", "demo_markdown"] +members = [ + "thaw", + "thaw_components", + "thaw_macro", + "thaw_utils", + "demo", + "demo_markdown", +] exclude = ["examples"] [workspace.dependencies] thaw = { version = "0.3.1", path = "./thaw" } thaw_components = { version = "0.1.1", path = "./thaw_components" } +thaw_macro = { version = "0.1.0", path = "./thaw_macro" } thaw_utils = { version = "0.0.3", path = "./thaw_utils" } diff --git a/thaw/Cargo.toml b/thaw/Cargo.toml index 1e7b58a..6f96b64 100644 --- a/thaw/Cargo.toml +++ b/thaw/Cargo.toml @@ -15,6 +15,7 @@ license = "MIT" [dependencies] leptos = { version = "0.6.10" } thaw_components = { workspace = true } +thaw_macro = { workspace = true } thaw_utils = { workspace = true } web-sys = { version = "0.3.69", features = [ "DomRect", diff --git a/thaw/src/config_provider/mod.rs b/thaw/src/config_provider/mod.rs index ecf0532..bfb69db 100644 --- a/thaw/src/config_provider/mod.rs +++ b/thaw/src/config_provider/mod.rs @@ -58,92 +58,8 @@ pub fn ConfigProvider( "--curveEasyEase: {};", theme.common.curve_easy_ease )); - - css_vars.push_str(&format!( - "--colorNeutralBackground1: {};", - theme.common.color_neutral_background_1 - )); - css_vars.push_str(&format!( - "--colorNeutralBackground1Hover: {};", - theme.common.color_neutral_background_1_hover - )); - css_vars.push_str(&format!( - "--colorNeutralBackground1Pressed: {};", - theme.common.color_neutral_background_1_pressed - )); - - css_vars.push_str(&format!( - "--colorNeutralForeground1: {};", - theme.common.color_neutral_foreground_1 - )); - css_vars.push_str(&format!( - "--colorNeutralForeground1Hover: {};", - theme.common.color_neutral_foreground_1_hover - )); - css_vars.push_str(&format!( - "--colorNeutralForeground1Pressed: {};", - theme.common.color_neutral_foreground_1_pressed - )); - css_vars.push_str(&format!( - "--colorNeutralForeground2: {};", - theme.common.color_neutral_foreground_2 - )); - css_vars.push_str(&format!( - "--colorNeutralForeground2Hover: {};", - theme.common.color_neutral_foreground_2_hover - )); - css_vars.push_str(&format!( - "--colorNeutralForeground2Pressed: {};", - theme.common.color_neutral_foreground_2_pressed - )); - css_vars.push_str(&format!( - "--colorNeutralForeground2BrandHover: {};", - theme.common.color_neutral_foreground_2_brand_hover - )); - css_vars.push_str(&format!( - "--colorNeutralForeground2BrandPressed: {};", - theme.common.color_neutral_foreground_2_brand_pressed - )); - css_vars.push_str(&format!( - "--colorNeutralForegroundOnBrand: {};", - theme.common.color_neutral_foreground_on_brand - )); - css_vars.push_str(&format!( - "--colorNeutralStroke1: {};", - theme.common.color_neutral_stroke_1 - )); - css_vars.push_str(&format!( - "--colorNeutralStroke1Hover: {};", - theme.common.color_neutral_stroke_1_hover - )); - css_vars.push_str(&format!( - "--colorNeutralStroke1Pressed: {};", - theme.common.color_neutral_stroke_1_pressed - )); - css_vars.push_str(&format!( - "--colorBrandBackground: {};", - theme.common.color_brand_background - )); - css_vars.push_str(&format!( - "--colorBrandBackgroundHover: {};", - theme.common.color_brand_background_hover - )); - css_vars.push_str(&format!( - "--colorBrandBackgroundPressed: {};", - theme.common.color_brand_background_pressed - )); - css_vars.push_str(&format!( - "--colorSubtleBackground: {};", - theme.common.color_subtle_background - )); - css_vars.push_str(&format!( - "--colorSubtleBackgroundHover {};", - theme.common.color_subtle_background_hover - )); - css_vars.push_str(&format!( - "--colorSubtleBackgroundPressed: {};", - theme.common.color_subtle_background_pressed - )); + + theme.color.write_css_vars(&mut css_vars); }); css_vars }); diff --git a/thaw/src/global_style/mod.rs b/thaw/src/global_style/mod.rs index 917f32c..4a901d7 100644 --- a/thaw/src/global_style/mod.rs +++ b/thaw/src/global_style/mod.rs @@ -11,9 +11,9 @@ pub fn GlobalStyle() -> impl IntoView { .style() .set_property("background-color", &theme.common.background_color); _ = body.style().set_property("color", &theme.common.font_color); - _ = body - .style() - .set_property("font-size", &theme.common.font_size); + // _ = body + // .style() + // .set_property("font-size", &theme.common.font_size); _ = body .style() .set_property("color-scheme", &theme.common.color_scheme); diff --git a/thaw/src/theme/color.rs b/thaw/src/theme/color.rs index e69de29..5162a46 100644 --- a/thaw/src/theme/color.rs +++ b/thaw/src/theme/color.rs @@ -0,0 +1,89 @@ +use thaw_macro::WriteCSSVars; + +#[derive(Clone, WriteCSSVars)] +pub struct ColorTheme { + pub color_neutral_background_1: String, + pub color_neutral_background_1_hover: String, + pub color_neutral_background_1_pressed: String, + pub color_neutral_foreground_1: String, + pub color_neutral_foreground_1_hover: String, + pub color_neutral_foreground_1_pressed: String, + pub color_neutral_foreground_2: String, + pub color_neutral_foreground_2_hover: String, + pub color_neutral_foreground_2_pressed: String, + pub color_neutral_foreground_2_brand_hover: String, + pub color_neutral_foreground_2_brand_pressed: String, + pub color_neutral_foreground_on_brand: String, + pub color_neutral_stroke_1: String, + pub color_neutral_stroke_1_hover: String, + pub color_neutral_stroke_1_pressed: String, + pub color_brand_background: String, + pub color_brand_background_hover: String, + pub color_brand_background_pressed: String, + pub color_subtle_background: String, + pub color_subtle_background_hover: String, + pub color_subtle_background_pressed: String, + pub color_transparent_background: String, + pub color_transparent_background_hover: String, + pub color_transparent_background_pressed: String, +} + +impl ColorTheme { + pub fn light() -> Self { + Self { + color_neutral_background_1: "#fff".into(), + color_neutral_background_1_hover: "#f5f5f5".into(), + color_neutral_background_1_pressed: "#e0e0e0".into(), + color_neutral_foreground_1: "#242424".into(), + color_neutral_foreground_1_hover: "#242424".into(), + color_neutral_foreground_1_pressed: "#242424".into(), + color_neutral_foreground_2: "#424242".into(), + color_neutral_foreground_2_hover: "#242424".into(), + color_neutral_foreground_2_pressed: "#242424".into(), + color_neutral_foreground_2_brand_hover: "#0f6cbd".into(), + color_neutral_foreground_2_brand_pressed: "#115ea3".into(), + color_neutral_foreground_on_brand: "#fff".into(), + color_neutral_stroke_1: "#d1d1d1".into(), + color_neutral_stroke_1_hover: "#c7c7c7".into(), + color_neutral_stroke_1_pressed: "#b3b3b3".into(), + color_brand_background: "#0f6cbd".into(), + color_brand_background_hover: "#115ea3".into(), + color_brand_background_pressed: "#0c3b5e".into(), + color_subtle_background: "transparent".into(), + color_subtle_background_hover: "#f5f5f5".into(), + color_subtle_background_pressed: "#e0e0e0".into(), + color_transparent_background: "transparent".into(), + color_transparent_background_hover: "transparent".into(), + color_transparent_background_pressed: "transparent".into(), + } + } + + pub fn dark() -> Self { + Self { + color_neutral_background_1: "#292929".into(), + color_neutral_background_1_hover: "#3d3d3d".into(), + color_neutral_background_1_pressed: "#1f1f1f".into(), + color_neutral_foreground_1: "#fff".into(), + color_neutral_foreground_1_hover: "#fff".into(), + color_neutral_foreground_1_pressed: "#fff".into(), + color_neutral_foreground_2: "#d6d6d6".into(), + color_neutral_foreground_2_hover: "#fff".into(), + color_neutral_foreground_2_pressed: "#fff".into(), + color_neutral_foreground_2_brand_hover: "#479ef5".into(), + color_neutral_foreground_2_brand_pressed: "#2886de".into(), + color_neutral_foreground_on_brand: "#fff".into(), + color_neutral_stroke_1: "#666666".into(), + color_neutral_stroke_1_hover: "#757575".into(), + color_neutral_stroke_1_pressed: "#6b6b6b".into(), + color_brand_background: "#115ea3".into(), + color_brand_background_hover: "#0f6cbd".into(), + color_brand_background_pressed: "#0c3b5e".into(), + color_subtle_background: "transparent".into(), + color_subtle_background_hover: "#383838".into(), + color_subtle_background_pressed: "#2e2e2e".into(), + color_transparent_background: "transparent".into(), + color_transparent_background_hover: "transparent".into(), + color_transparent_background_pressed: "transparent".into(), + } + } +} \ No newline at end of file diff --git a/thaw/src/theme/common.rs b/thaw/src/theme/common.rs index 7cde7de..56fd03c 100644 --- a/thaw/src/theme/common.rs +++ b/thaw/src/theme/common.rs @@ -21,31 +21,6 @@ pub struct CommonTheme { pub color_error_hover: String, pub color_error_active: String, - pub color_neutral_background_1: String, - pub color_neutral_background_1_hover: String, - pub color_neutral_background_1_pressed: String, - pub color_neutral_foreground_1: String, - pub color_neutral_foreground_1_hover: String, - pub color_neutral_foreground_1_pressed: String, - pub color_neutral_foreground_2: String, - pub color_neutral_foreground_2_hover: String, - pub color_neutral_foreground_2_pressed: String, - pub color_neutral_foreground_2_brand_hover: String, - pub color_neutral_foreground_2_brand_pressed: String, - pub color_neutral_foreground_on_brand: String, - pub color_neutral_stroke_1: String, - pub color_neutral_stroke_1_hover: String, - pub color_neutral_stroke_1_pressed: String, - pub color_brand_background: String, - pub color_brand_background_hover: String, - pub color_brand_background_pressed: String, - pub color_subtle_background: String, - pub color_subtle_background_hover: String, - pub color_subtle_background_pressed: String, - pub color_transparent_background: String, - pub color_transparent_background_hover: String, - pub color_transparent_background_pressed: String, - pub font_size_base_300: String, pub line_height_base300: String, @@ -63,24 +38,11 @@ pub struct CommonTheme { pub duration_faster: String, pub curve_easy_ease: String, - pub font_size: String, - pub font_size_tiny: String, - pub font_size_small: String, - pub font_size_medium: String, - pub font_size_large: String, - pub font_size_huge: String, - pub height_tiny: String, pub height_small: String, pub height_medium: String, pub height_large: String, - pub line_height: String, - pub line_height_small: String, - pub line_height_medium: String, - pub line_height_large: String, - pub line_height_huge: String, - pub border_radius: String, pub border_radius_small: String, pub border_radius_large: String, @@ -107,31 +69,6 @@ impl CommonTheme { color_error_hover: "".into(), color_error_active: "".into(), - color_neutral_background_1: "".into(), - color_neutral_background_1_hover: "".into(), - color_neutral_background_1_pressed: "".into(), - color_neutral_foreground_1: "".into(), - color_neutral_foreground_1_hover: "".into(), - color_neutral_foreground_1_pressed: "".into(), - color_neutral_foreground_2: "".into(), - color_neutral_foreground_2_hover: "".into(), - color_neutral_foreground_2_pressed: "".into(), - color_neutral_foreground_2_brand_hover: "".into(), - color_neutral_foreground_2_brand_pressed: "".into(), - color_neutral_foreground_on_brand: "#fff".into(), - color_neutral_stroke_1: "".into(), - color_neutral_stroke_1_hover: "".into(), - color_neutral_stroke_1_pressed: "".into(), - color_brand_background: "".into(), - color_brand_background_hover: "".into(), - color_brand_background_pressed: "".into(), - color_subtle_background: "transparent".into(), - color_subtle_background_hover: "".into(), - color_subtle_background_pressed: "".into(), - color_transparent_background: "transparent".into(), - color_transparent_background_hover: "transparent".into(), - color_transparent_background_pressed: "transparent".into(), - font_size_base_300: "14px".into(), line_height_base300: "20px".into(), @@ -149,24 +86,11 @@ impl CommonTheme { duration_faster: "100ms".into(), curve_easy_ease: "cubic-bezier(0.33,0,0.67,1)".into(), - font_size: "14px".into(), - font_size_tiny: "12px".into(), - font_size_small: "14px".into(), - font_size_medium: "14px".into(), - font_size_large: "15px".into(), - font_size_huge: "16px".into(), - height_tiny: "22px".into(), height_small: "28px".into(), height_medium: "34px".into(), height_large: "40px".into(), - line_height: "22px".into(), - line_height_small: "22px".into(), - line_height_medium: "22px".into(), - line_height_large: "23px".into(), - line_height_huge: "24px".into(), - border_radius: "3px".into(), border_radius_small: "2px".into(), border_radius_large: "8px".into(), @@ -193,25 +117,7 @@ impl ThemeMethod for CommonTheme { color_error_hover: "#de576d".into(), color_error_active: "#ab1f3f".into(), border_color: "#e5e8eb".into(), - color_neutral_background_1: "#fff".into(), - color_neutral_background_1_hover: "#f5f5f5".into(), - color_neutral_background_1_pressed: "#e0e0e0".into(), - color_neutral_foreground_1: "#242424".into(), - color_neutral_foreground_1_hover: "#242424".into(), - color_neutral_foreground_1_pressed: "#242424".into(), - color_neutral_foreground_2: "#424242".into(), - color_neutral_foreground_2_hover: "#242424".into(), - color_neutral_foreground_2_pressed: "#242424".into(), - color_neutral_foreground_2_brand_hover: "#0f6cbd".into(), - color_neutral_foreground_2_brand_pressed: "#115ea3".into(), - color_neutral_stroke_1: "#d1d1d1".into(), - color_neutral_stroke_1_hover: "#c7c7c7".into(), - color_neutral_stroke_1_pressed: "#b3b3b3".into(), - color_brand_background: "#0f6cbd".into(), - color_brand_background_hover: "#115ea3".into(), - color_brand_background_pressed: "#0c3b5e".into(), - color_subtle_background_hover: "#f5f5f5".into(), - color_subtle_background_pressed: "#e0e0e0".into(), + ..CommonTheme::common() } } @@ -235,25 +141,6 @@ impl ThemeMethod for CommonTheme { color_error_hover: "#de576d".into(), color_error_active: "#e57272".into(), border_color: "#1f2537".into(), - color_neutral_background_1: "#292929".into(), - color_neutral_background_1_hover: "#3d3d3d".into(), - color_neutral_background_1_pressed: "#1f1f1f".into(), - color_neutral_foreground_1: "#fff".into(), - color_neutral_foreground_1_hover: "#fff".into(), - color_neutral_foreground_1_pressed: "#fff".into(), - color_neutral_foreground_2: "#d6d6d6".into(), - color_neutral_foreground_2_hover: "#fff".into(), - color_neutral_foreground_2_pressed: "#fff".into(), - color_neutral_foreground_2_brand_hover: "#479ef5".into(), - color_neutral_foreground_2_brand_pressed: "#2886de".into(), - color_neutral_stroke_1: "#666666".into(), - color_neutral_stroke_1_hover: "#757575".into(), - color_neutral_stroke_1_pressed: "#6b6b6b".into(), - color_brand_background: "#115ea3".into(), - color_brand_background_hover: "#0f6cbd".into(), - color_brand_background_pressed: "#0c3b5e".into(), - color_subtle_background_hover: "#383838".into(), - color_subtle_background_pressed: "#2e2e2e".into(), ..CommonTheme::common() } } diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 2f20a9a..1bf8d54 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -1,6 +1,8 @@ mod common; +mod color; use self::common::CommonTheme; +pub use color::ColorTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, AlertTheme, AnchorTheme, AutoCompleteTheme, AvatarTheme, BackTopTheme, BreadcrumbTheme, @@ -20,6 +22,7 @@ pub trait ThemeMethod { pub struct Theme { pub name: String, pub common: CommonTheme, + pub color: ColorTheme, pub button: ButtonTheme, pub input: InputTheme, pub menu: MenuTheme, @@ -56,6 +59,7 @@ impl Theme { Self { name: "light".into(), common: CommonTheme::light(), + color: ColorTheme::light(), button: ButtonTheme::light(), input: InputTheme::light(), menu: MenuTheme::light(), @@ -91,6 +95,7 @@ impl Theme { Self { name: "dark".into(), common: CommonTheme::dark(), + color: ColorTheme::dark(), button: ButtonTheme::dark(), input: InputTheme::dark(), menu: MenuTheme::dark(), diff --git a/thaw_macro/Cargo.toml b/thaw_macro/Cargo.toml new file mode 100644 index 0000000..772f53a --- /dev/null +++ b/thaw_macro/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "thaw_macro" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0.36" +syn = "2.0.60" +proc-macro2 = "1.0.81" \ No newline at end of file diff --git a/thaw_macro/src/lib.rs b/thaw_macro/src/lib.rs new file mode 100644 index 0000000..e1a0c28 --- /dev/null +++ b/thaw_macro/src/lib.rs @@ -0,0 +1,57 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, Data, DeriveInput, Fields}; + +#[proc_macro_derive(WriteCSSVars)] +pub fn write_css_vars(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let struct_name = &input.ident; + let data = match input.data { + Data::Struct(data) => data, + _ => panic!("Expected a struct!"), + }; + + let mut css_var_names = vec![]; + let mut field_names = vec![]; + match data.fields { + Fields::Named(fields) => { + for field in fields.named { + let field_name = field.ident.unwrap(); + css_var_names.push(format!( + "--{}: {{}};", + to_camel_case(field_name.to_string()) + )); + field_names.push(field_name); + } + } + _ => panic!("Expected named fields!"), + }; + + let field_names = field_names.iter(); + quote! { + impl #struct_name { + pub fn write_css_vars(&self, css_vars: &mut String) { + #(css_vars.push_str(&format!(#css_var_names, self.#field_names));)* + } + } + } + .into() +} + +fn to_camel_case(s: String) -> String { + let mut camel_case = String::new(); + let mut capitalize_next = false; + for c in s.chars() { + if c.is_alphanumeric() { + if capitalize_next { + camel_case.push(c.to_ascii_uppercase()); + capitalize_next = false; + } else { + camel_case.push(c.to_ascii_lowercase()); + } + } else { + capitalize_next = true; + } + } + camel_case +}