增加Swatch Scheme主题的生成和导出。
This commit is contained in:
		@@ -70,6 +70,13 @@ macro_rules! parse_to_oklch {
 | 
				
			|||||||
                .into_format::<f32>(),
 | 
					                .into_format::<f32>(),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					    ($origin: expr) => {
 | 
				
			||||||
 | 
					        palette::Oklch::from_color(
 | 
				
			||||||
 | 
					            palette::Srgb::from_str($origin)
 | 
				
			||||||
 | 
					                .map_err(|_| crate::errors::ColorError::UnrecogniazedRGB($origin.to_string()))?
 | 
				
			||||||
 | 
					                .into_format::<f32>(),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[macro_export]
 | 
					#[macro_export]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ use std::collections::HashMap;
 | 
				
			|||||||
use material_design_2::MaterialDesign2Scheme;
 | 
					use material_design_2::MaterialDesign2Scheme;
 | 
				
			||||||
use material_design_3::MaterialDesign3Scheme;
 | 
					use material_design_3::MaterialDesign3Scheme;
 | 
				
			||||||
use q_style::{QScheme, SchemeSetting};
 | 
					use q_style::{QScheme, SchemeSetting};
 | 
				
			||||||
 | 
					use swatch_style::{SwatchEntry, SwatchSchemeSetting};
 | 
				
			||||||
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
 | 
					use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::errors;
 | 
					use crate::errors;
 | 
				
			||||||
@@ -126,3 +127,18 @@ pub fn generate_q_scheme_manually(
 | 
				
			|||||||
    ))
 | 
					    ))
 | 
				
			||||||
    .map_err(|_| errors::ColorError::UnableToAssembleOutput)?)
 | 
					    .map_err(|_| errors::ColorError::UnableToAssembleOutput)?)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[wasm_bindgen]
 | 
				
			||||||
 | 
					pub fn generate_swatch_scheme(
 | 
				
			||||||
 | 
					    colors: Vec<SwatchEntry>,
 | 
				
			||||||
 | 
					    setting: SwatchSchemeSetting,
 | 
				
			||||||
 | 
					) -> Result<JsValue, errors::ColorError> {
 | 
				
			||||||
 | 
					    let scheme = swatch_style::SwatchScheme::new(colors, setting)?;
 | 
				
			||||||
 | 
					    Ok(serde_wasm_bindgen::to_value(&(
 | 
				
			||||||
 | 
					        scheme.swatches(),
 | 
				
			||||||
 | 
					        scheme.output_css_variables(),
 | 
				
			||||||
 | 
					        scheme.output_scss_variables(),
 | 
				
			||||||
 | 
					        scheme.output_javascript_object(),
 | 
				
			||||||
 | 
					    ))
 | 
				
			||||||
 | 
					    .map_err(|_| errors::ColorError::UnableToAssembleOutput)?)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										122
									
								
								color-module/src/schemes/swatch_style/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								color-module/src/schemes/swatch_style/mod.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,122 @@
 | 
				
			|||||||
 | 
					use palette::FromColor;
 | 
				
			||||||
 | 
					use std::collections::HashMap;
 | 
				
			||||||
 | 
					use std::str::FromStr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub use setting::SwatchSchemeSetting;
 | 
				
			||||||
 | 
					use swatch::Swatch;
 | 
				
			||||||
 | 
					use wasm_bindgen::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{errors, parse_to_oklch};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::SchemeExport;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod setting;
 | 
				
			||||||
 | 
					mod swatch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct SwatchScheme {
 | 
				
			||||||
 | 
					    light: HashMap<String, Swatch>,
 | 
				
			||||||
 | 
					    dark: HashMap<String, Swatch>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
 | 
					#[wasm_bindgen(getter_with_clone)]
 | 
				
			||||||
 | 
					pub struct SwatchEntry {
 | 
				
			||||||
 | 
					    pub name: String,
 | 
				
			||||||
 | 
					    pub color: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl SwatchScheme {
 | 
				
			||||||
 | 
					    pub fn new(
 | 
				
			||||||
 | 
					        colors: Vec<SwatchEntry>,
 | 
				
			||||||
 | 
					        setting: SwatchSchemeSetting,
 | 
				
			||||||
 | 
					    ) -> Result<Self, errors::ColorError> {
 | 
				
			||||||
 | 
					        let mut light = HashMap::new();
 | 
				
			||||||
 | 
					        let mut dark = HashMap::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for entry in colors {
 | 
				
			||||||
 | 
					            let color = parse_to_oklch!(&entry.color);
 | 
				
			||||||
 | 
					            let darken_color = color * setting.dark_convert;
 | 
				
			||||||
 | 
					            light.insert(entry.name.clone(), Swatch::new(&color, &setting));
 | 
				
			||||||
 | 
					            dark.insert(entry.name, Swatch::new(&darken_color, &setting));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(Self { light, dark })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn swatches(&self) -> HashMap<String, HashMap<String, Vec<String>>> {
 | 
				
			||||||
 | 
					        let mut light_swatches = HashMap::new();
 | 
				
			||||||
 | 
					        let mut dark_swatches = HashMap::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (name, swatch) in &self.light {
 | 
				
			||||||
 | 
					            light_swatches.insert(name.clone(), swatch.swtch_hex());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (name, swatch) in &self.dark {
 | 
				
			||||||
 | 
					            dark_swatches.insert(name.clone(), swatch.swtch_hex());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        HashMap::from([
 | 
				
			||||||
 | 
					            ("light".to_string(), light_swatches),
 | 
				
			||||||
 | 
					            ("dark".to_string(), dark_swatches),
 | 
				
			||||||
 | 
					        ])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl SchemeExport for SwatchScheme {
 | 
				
			||||||
 | 
					    fn output_css_variables(&self) -> String {
 | 
				
			||||||
 | 
					        let mut variables = Vec::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (name, swatch) in &self.light {
 | 
				
			||||||
 | 
					            variables.extend(swatch.to_css_variables("light", name));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (name, swatch) in &self.dark {
 | 
				
			||||||
 | 
					            variables.extend(swatch.to_css_variables("dark", name));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        variables.join("\n")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn output_scss_variables(&self) -> String {
 | 
				
			||||||
 | 
					        let mut variables = Vec::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (name, swatch) in &self.light {
 | 
				
			||||||
 | 
					            variables.extend(swatch.to_scss_variables("light", name));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (name, swatch) in &self.dark {
 | 
				
			||||||
 | 
					            variables.extend(swatch.to_scss_variables("dark", name));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        variables.join("\n")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn output_javascript_object(&self) -> String {
 | 
				
			||||||
 | 
					        let mut object = Vec::new();
 | 
				
			||||||
 | 
					        object.push("{".to_string());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        object.push("  light: {".to_string());
 | 
				
			||||||
 | 
					        for (name, swatch) in &self.light {
 | 
				
			||||||
 | 
					            object.extend(
 | 
				
			||||||
 | 
					                swatch
 | 
				
			||||||
 | 
					                    .to_javascript_fields("light", name)
 | 
				
			||||||
 | 
					                    .iter()
 | 
				
			||||||
 | 
					                    .map(|s| format!("    {}", s)),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        object.push("  },".to_string());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        object.push("  dark: {".to_string());
 | 
				
			||||||
 | 
					        for (name, swatch) in &self.dark {
 | 
				
			||||||
 | 
					            object.extend(
 | 
				
			||||||
 | 
					                swatch
 | 
				
			||||||
 | 
					                    .to_javascript_fields("dark", name)
 | 
				
			||||||
 | 
					                    .iter()
 | 
				
			||||||
 | 
					                    .map(|s| format!("    {}", s)),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        object.push("  },".to_string());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        object.push("}".to_string());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        object.join("\n")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										29
									
								
								color-module/src/schemes/swatch_style/setting.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								color-module/src/schemes/swatch_style/setting.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					use serde::Serialize;
 | 
				
			||||||
 | 
					use wasm_bindgen::prelude::wasm_bindgen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::schemes::q_style::ColorShifting;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Serialize)]
 | 
				
			||||||
 | 
					#[wasm_bindgen]
 | 
				
			||||||
 | 
					pub struct SwatchSchemeSetting {
 | 
				
			||||||
 | 
					    pub amount: usize,
 | 
				
			||||||
 | 
					    pub min_lightness: f32,
 | 
				
			||||||
 | 
					    pub max_lightness: f32,
 | 
				
			||||||
 | 
					    pub include_primary: bool,
 | 
				
			||||||
 | 
					    pub dark_convert: ColorShifting,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for SwatchSchemeSetting {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            amount: 10,
 | 
				
			||||||
 | 
					            min_lightness: 10.0,
 | 
				
			||||||
 | 
					            max_lightness: 90.0,
 | 
				
			||||||
 | 
					            include_primary: false,
 | 
				
			||||||
 | 
					            dark_convert: ColorShifting {
 | 
				
			||||||
 | 
					                chroma: -0.3,
 | 
				
			||||||
 | 
					                lightness: -0.3,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										133
									
								
								color-module/src/schemes/swatch_style/swatch.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								color-module/src/schemes/swatch_style/swatch.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,133 @@
 | 
				
			|||||||
 | 
					use palette::Oklch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::convert::map_oklch_to_srgb_hex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::setting::SwatchSchemeSetting;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct Swatch {
 | 
				
			||||||
 | 
					    min_key: f32,
 | 
				
			||||||
 | 
					    max_key: f32,
 | 
				
			||||||
 | 
					    primary_key: Oklch,
 | 
				
			||||||
 | 
					    include_primary: bool,
 | 
				
			||||||
 | 
					    color_amount: usize,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Swatch {
 | 
				
			||||||
 | 
					    pub fn new(primary: &Oklch, setting: &SwatchSchemeSetting) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            min_key: primary.l.min(setting.min_lightness),
 | 
				
			||||||
 | 
					            max_key: primary.l.max(setting.max_lightness),
 | 
				
			||||||
 | 
					            primary_key: primary.clone(),
 | 
				
			||||||
 | 
					            include_primary: setting.include_primary,
 | 
				
			||||||
 | 
					            color_amount: setting.amount,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn find_interval(&self) -> (usize, usize) {
 | 
				
			||||||
 | 
					        if !self.include_primary {
 | 
				
			||||||
 | 
					            return (0, 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if self.primary_key.l == self.min_key {
 | 
				
			||||||
 | 
					            return (0, 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if self.primary_key.l == self.max_key {
 | 
				
			||||||
 | 
					            return (self.color_amount - 2, self.color_amount - 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let step = (self.max_key - self.min_key) / (self.color_amount - 1) as f32;
 | 
				
			||||||
 | 
					        let index = ((self.primary_key.l - self.min_key) / step) as usize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        (index, index + 1)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn swatch(&self) -> Vec<Oklch> {
 | 
				
			||||||
 | 
					        let mut swatch = Vec::new();
 | 
				
			||||||
 | 
					        if self.include_primary {
 | 
				
			||||||
 | 
					            let (_, primary_index) = self.find_interval();
 | 
				
			||||||
 | 
					            if primary_index > 0 {
 | 
				
			||||||
 | 
					                let step = (self.max_key - self.min_key) / primary_index as f32;
 | 
				
			||||||
 | 
					                for i in 0..primary_index {
 | 
				
			||||||
 | 
					                    let lightness = self.min_key + step * i as f32;
 | 
				
			||||||
 | 
					                    swatch.push(Oklch {
 | 
				
			||||||
 | 
					                        l: lightness,
 | 
				
			||||||
 | 
					                        ..self.primary_key
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if primary_index < self.color_amount - 1 {
 | 
				
			||||||
 | 
					                let step =
 | 
				
			||||||
 | 
					                    (self.max_key - self.min_key) / (self.color_amount - primary_index) as f32;
 | 
				
			||||||
 | 
					                for i in primary_index..self.color_amount {
 | 
				
			||||||
 | 
					                    let lightness = self.min_key + step * i as f32;
 | 
				
			||||||
 | 
					                    swatch.push(Oklch {
 | 
				
			||||||
 | 
					                        l: lightness,
 | 
				
			||||||
 | 
					                        ..self.primary_key
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            let step = (self.max_key - self.min_key) / (self.color_amount - 1) as f32;
 | 
				
			||||||
 | 
					            for i in 0..self.color_amount {
 | 
				
			||||||
 | 
					                let lightness = self.min_key + step * i as f32;
 | 
				
			||||||
 | 
					                swatch.push(Oklch {
 | 
				
			||||||
 | 
					                    l: lightness,
 | 
				
			||||||
 | 
					                    ..self.primary_key
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        swatch
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn swtch_hex(&self) -> Vec<String> {
 | 
				
			||||||
 | 
					        self.swatch().iter().map(map_oklch_to_srgb_hex).collect()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn to_css_variables(&self, prefix: &str, name: &str) -> Vec<String> {
 | 
				
			||||||
 | 
					        let mut variables = Vec::new();
 | 
				
			||||||
 | 
					        for (i, color) in self.swatch().iter().enumerate() {
 | 
				
			||||||
 | 
					            variables.push(format!(
 | 
				
			||||||
 | 
					                "--color-{}-{}-{}: #{};",
 | 
				
			||||||
 | 
					                prefix,
 | 
				
			||||||
 | 
					                name,
 | 
				
			||||||
 | 
					                i * 100,
 | 
				
			||||||
 | 
					                map_oklch_to_srgb_hex(color)
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        variables
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn to_scss_variables(&self, prefix: &str, name: &str) -> Vec<String> {
 | 
				
			||||||
 | 
					        let mut variables = Vec::new();
 | 
				
			||||||
 | 
					        for (i, color) in self.swatch().iter().enumerate() {
 | 
				
			||||||
 | 
					            variables.push(format!(
 | 
				
			||||||
 | 
					                "${}-{}-{}: #{};",
 | 
				
			||||||
 | 
					                prefix,
 | 
				
			||||||
 | 
					                name,
 | 
				
			||||||
 | 
					                i * 100,
 | 
				
			||||||
 | 
					                map_oklch_to_srgb_hex(color)
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        variables
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn to_javascript_fields(&self, prefix: &str, name: &str) -> Vec<String> {
 | 
				
			||||||
 | 
					        let mut variables = Vec::new();
 | 
				
			||||||
 | 
					        let capitalized_name = name
 | 
				
			||||||
 | 
					            .chars()
 | 
				
			||||||
 | 
					            .next()
 | 
				
			||||||
 | 
					            .unwrap()
 | 
				
			||||||
 | 
					            .to_ascii_uppercase()
 | 
				
			||||||
 | 
					            .to_string()
 | 
				
			||||||
 | 
					            + &name[1..];
 | 
				
			||||||
 | 
					        for (i, color) in self.swatch().iter().enumerate() {
 | 
				
			||||||
 | 
					            variables.push(format!(
 | 
				
			||||||
 | 
					                "{}{}{}: '#{}',",
 | 
				
			||||||
 | 
					                prefix,
 | 
				
			||||||
 | 
					                capitalized_name,
 | 
				
			||||||
 | 
					                i * 100,
 | 
				
			||||||
 | 
					                map_oklch_to_srgb_hex(color)
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        variables
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user