From f3f259fd1c4883b58bc7a28265d9e57f6932bb75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=B6=9B?= Date: Fri, 7 Mar 2025 09:42:24 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9E=84=E5=BB=BAM3=E5=90=84?= =?UTF-8?q?=E4=B8=AA=E8=89=B2=E7=9B=98=E7=9A=84=E8=83=BD=E5=8A=9B=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/schemes/material_design_3/mod.rs | 43 +++++++++-- .../src/schemes/material_design_3/swatch.rs | 72 +++++++++++++++++++ .../schemes/material_design_3_dynamic/mod.rs | 36 +++++++++- color-module/src/schemes/mod.rs | 3 +- 4 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 color-module/src/schemes/material_design_3/swatch.rs diff --git a/color-module/src/schemes/material_design_3/mod.rs b/color-module/src/schemes/material_design_3/mod.rs index f0518a9..2f9aba3 100644 --- a/color-module/src/schemes/material_design_3/mod.rs +++ b/color-module/src/schemes/material_design_3/mod.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::str::FromStr; pub use baseline::M3BaselineColors; @@ -5,6 +6,7 @@ pub use color_set::M3ColorSet; use palette::{IntoColor, Lch, Srgb}; use serde::Serialize; pub use surface::M3SurfaceSet; +pub use swatch::M3PaletteSwatch; pub use tonal_palette::TonalPalette; use crate::convert::map_lch_to_srgb_hex; @@ -15,6 +17,7 @@ use super::SchemeExport; mod baseline; mod color_set; mod surface; +mod swatch; mod tonal_palette; #[derive(Debug, Clone, Serialize)] @@ -23,6 +26,7 @@ pub struct MaterialDesign3Scheme { pub black: String, pub light_baseline: M3BaselineColors, pub dark_baseline: M3BaselineColors, + pub swatches: HashMap, } impl MaterialDesign3Scheme { @@ -43,11 +47,20 @@ impl MaterialDesign3Scheme { let nv = TonalPalette::from_hue_and_chroma(source_hue, (source.chroma / 6.0).min(8.0)); let e = TonalPalette::from_hue_and_chroma(error.hue.into_positive_degrees(), 84.0); + let mut swatches = HashMap::new(); + swatches.insert("primary".to_string(), M3PaletteSwatch::new(&p)); + swatches.insert("secondary".to_string(), M3PaletteSwatch::new(&s)); + swatches.insert("tertiary".to_string(), M3PaletteSwatch::new(&t)); + swatches.insert("error".to_string(), M3PaletteSwatch::new(&e)); + swatches.insert("neutral".to_string(), M3PaletteSwatch::new(&n)); + swatches.insert("neutral_variant".to_string(), M3PaletteSwatch::new(&nv)); + Ok(Self { white: map_lch_to_srgb_hex(&Lch::new(100.0, 0.0, 0.0)), black: map_lch_to_srgb_hex(&Lch::new(0.0, 0.0, 0.0)), light_baseline: M3BaselineColors::new(&p, &s, &t, &n, &nv, &e, false), dark_baseline: M3BaselineColors::new(&p, &s, &t, &n, &nv, &e, true), + swatches, }) } @@ -64,15 +77,21 @@ impl MaterialDesign3Scheme { let palette = TonalPalette::from_hue_and_chroma(hue, custom_color.chroma); self.light_baseline.add_custom_set(name.clone(), &palette); self.dark_baseline.add_custom_set(name.clone(), &palette); + self.swatches.insert(name, M3PaletteSwatch::new(&palette)); Ok(()) } - pub fn full_custom(light_baseline: M3BaselineColors, dark_baseline: M3BaselineColors) -> Self { + pub fn full_custom( + light_baseline: M3BaselineColors, + dark_baseline: M3BaselineColors, + swatches: HashMap, + ) -> Self { Self { white: map_lch_to_srgb_hex(&Lch::new(100.0, 0.0, 0.0)), black: map_lch_to_srgb_hex(&Lch::new(0.0, 0.0, 0.0)), light_baseline, dark_baseline, + swatches, } } } @@ -85,6 +104,9 @@ impl SchemeExport for MaterialDesign3Scheme { css_variables.push(format!("--color-black: #{};", self.black)); css_variables.extend(self.light_baseline.to_css_variables()); css_variables.extend(self.dark_baseline.to_css_variables()); + for (name, swatch) in &self.swatches { + css_variables.extend(swatch.to_css_variables(name)); + } css_variables.join("\n") } @@ -96,6 +118,9 @@ impl SchemeExport for MaterialDesign3Scheme { scss_variables.push(format!("$color-black: #{};", self.black)); scss_variables.extend(self.light_baseline.to_scss_variables()); scss_variables.extend(self.dark_baseline.to_scss_variables()); + for (name, swatch) in &self.swatches { + scss_variables.extend(swatch.to_scss_variables(name)); + } scss_variables.join("\n") } @@ -111,8 +136,7 @@ impl SchemeExport for MaterialDesign3Scheme { self.light_baseline .to_javascript_object_fields() .into_iter() - .map(|s| format!(" {}", s)) - .collect::>(), + .map(|s| format!(" {}", s)), ); js_object.push(" },".to_string()); js_object.push(" dark: {".to_string()); @@ -120,10 +144,19 @@ impl SchemeExport for MaterialDesign3Scheme { self.dark_baseline .to_javascript_object_fields() .into_iter() - .map(|s| format!(" {}", s)) - .collect::>(), + .map(|s| format!(" {}", s)), ); js_object.push(" },".to_string()); + js_object.push(" swatches: {".to_string()); + for (name, swatch) in &self.swatches { + js_object.extend( + swatch + .to_javascript_object_fields(name) + .into_iter() + .map(|s| format!(" {}", s)), + ); + } + js_object.push(" }".to_string()); js_object.push("}".to_string()); js_object.join("\n") diff --git a/color-module/src/schemes/material_design_3/swatch.rs b/color-module/src/schemes/material_design_3/swatch.rs new file mode 100644 index 0000000..2489d49 --- /dev/null +++ b/color-module/src/schemes/material_design_3/swatch.rs @@ -0,0 +1,72 @@ +use std::collections::HashMap; + +use serde::Serialize; + +use crate::convert::map_lch_to_srgb_hex; + +use super::TonalPalette; + +static SWATCH_TONES: [u8; 18] = [ + 0, 5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 70, 80, 90, 95, 98, 99, 100, +]; + +#[derive(Debug, Clone, Serialize)] +pub struct M3PaletteSwatch(HashMap); + +impl M3PaletteSwatch { + pub fn new(palette: &TonalPalette) -> Self { + let mut swatch = HashMap::new(); + for &tone in SWATCH_TONES.iter() { + let color = palette.tone(tone as f32); + swatch.insert(tone, map_lch_to_srgb_hex(&color)); + } + Self(swatch) + } + + pub fn to_css_variables(&self, name: &str) -> Vec { + let mut variable_lines = Vec::new(); + + for &tone in SWATCH_TONES.iter() { + let color = self.0.get(&tone).unwrap(); + variable_lines.push(format!("--color-swatch-{}-{}: #{};", name, tone, color)); + } + + variable_lines + } + + pub fn to_scss_variables(&self, name: &str) -> Vec { + let mut variable_lines = Vec::new(); + + for &tone in SWATCH_TONES.iter() { + let color = self.0.get(&tone).unwrap(); + variable_lines.push(format!("$color-swatch-{}-{}: #{};", name, tone, color)); + } + + variable_lines + } + + pub fn to_javascript_object_fields(&self, name: &str) -> Vec { + let mut js_object = Vec::new(); + let name = name + .split('_') + .enumerate() + .map(|(i, part)| { + if i == 0 { + part.to_string() + } else { + let mut c = part.chars(); + c.next().unwrap().to_uppercase().collect::() + c.as_str() + } + }) + .collect::(); + + js_object.push(format!("{}: {{", name)); + for &tone in SWATCH_TONES.iter() { + let color = self.0.get(&tone).unwrap(); + js_object.push(format!(" {}: '#{}',", tone, color)); + } + js_object.push("},".to_string()); + + js_object + } +} diff --git a/color-module/src/schemes/material_design_3_dynamic/mod.rs b/color-module/src/schemes/material_design_3_dynamic/mod.rs index 48fdc2b..c88050b 100644 --- a/color-module/src/schemes/material_design_3_dynamic/mod.rs +++ b/color-module/src/schemes/material_design_3_dynamic/mod.rs @@ -7,7 +7,7 @@ use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; use crate::{cond, convert::map_lch_to_srgb_hex, errors}; -use super::material_design_3::{M3BaselineColors, M3ColorSet, M3SurfaceSet}; +use super::material_design_3::{M3BaselineColors, M3ColorSet, M3PaletteSwatch, M3SurfaceSet}; pub use constants::Variant; mod constants; @@ -147,6 +147,40 @@ pub fn build_baseline(scheme: &DynamicScheme) -> M3BaselineColors { ) } +pub fn build_swatches(scheme: &DynamicScheme) -> HashMap { + let mut swatches = HashMap::new(); + swatches.insert( + "primary".to_string(), + M3PaletteSwatch::new(&scheme.primary_palette), + ); + swatches.insert( + "secondary".to_string(), + M3PaletteSwatch::new(&scheme.secondary_palette), + ); + swatches.insert( + "tertiary".to_string(), + M3PaletteSwatch::new(&scheme.tertiary_palette), + ); + swatches.insert( + "error".to_string(), + M3PaletteSwatch::new(&scheme.error_palette), + ); + swatches.insert( + "neutral".to_string(), + M3PaletteSwatch::new(&scheme.neutral_palette), + ); + swatches.insert( + "neutral_variant".to_string(), + M3PaletteSwatch::new(&scheme.neutral_variant_palette), + ); + + for (name, palette) in &scheme.custom_palettes { + swatches.insert(name.clone(), M3PaletteSwatch::new(palette)); + } + + swatches +} + pub fn build_dynamic_scheme( source_color: &str, error_color: Option, diff --git a/color-module/src/schemes/mod.rs b/color-module/src/schemes/mod.rs index dc133a5..e1767fd 100644 --- a/color-module/src/schemes/mod.rs +++ b/color-module/src/schemes/mod.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use material_design_2::MaterialDesign2Scheme; use material_design_3::MaterialDesign3Scheme; -use material_design_3_dynamic::{build_baseline, build_dynamic_scheme, Variant}; +use material_design_3_dynamic::{build_baseline, build_dynamic_scheme, build_swatches, Variant}; use q_style::{QScheme, SchemeSetting}; use swatch_style::{SwatchEntry, SwatchSchemeSetting}; use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; @@ -180,6 +180,7 @@ pub fn generate_material_design_3_dynamic_scheme( let scheme = MaterialDesign3Scheme::full_custom( build_baseline(&light_scheme), build_baseline(&dark_scheme), + build_swatches(&light_scheme), ); Ok(serde_wasm_bindgen::to_value(&(