refactor(serialization): 重构颜色模块的序列化实现

将手动实现的序列化逻辑替换为派生宏实现
添加foreign_serializer模块处理特殊序列化需求
优化代码结构并减少重复代码
This commit is contained in:
徐涛 2025-07-20 07:25:13 +08:00
parent f82575c49b
commit edc2a0546e
6 changed files with 64 additions and 91 deletions

View File

@ -1,10 +1,10 @@
use std::str::FromStr;
use palette::{
FromColor, Hsl, IntoColor, IsWithinBounds, Lab, Oklch, Srgb,
cam16::{Cam16Jch, Parameters},
color_difference::Wcag21RelativeContrast,
convert::FromColorUnclamped,
FromColor, Hsl, IntoColor, IsWithinBounds, Lab, Oklch, Srgb,
};
use wasm_bindgen::prelude::*;
@ -14,6 +14,7 @@ mod color_differ;
mod color_shifting;
mod convert;
mod errors;
mod foreign_serializer;
mod palettes;
mod reversing;
mod schemes;
@ -139,10 +140,6 @@ pub fn wacg_relative_contrast(fg_color: &str, bg_color: &str) -> Result<f32, err
#[macro_export]
macro_rules! cond {
($s: expr, $a: expr, $b: expr) => {
if $s {
$a
} else {
$b
}
if $s { $a } else { $b }
};
}

View File

@ -1,11 +1,12 @@
use std::collections::HashMap;
use internment::Intern;
use material_design_2::MaterialDesign2Scheme;
use material_design_3::MaterialDesign3Scheme;
use material_design_3_dynamic::{build_baseline, build_dynamic_scheme, build_swatches, Variant};
use material_design_3_dynamic::{Variant, build_baseline, build_dynamic_scheme, build_swatches};
use q_style::{QScheme, SchemeSetting};
use swatch_style::{SwatchEntry, SwatchSchemeSetting};
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
use wasm_bindgen::{JsValue, prelude::wasm_bindgen};
use crate::{errors, schemes::q_style_2::QScheme2};
@ -23,6 +24,10 @@ pub trait SchemeExport {
fn output_javascript_object(&self) -> String;
}
pub fn get_static_str(s: &str) -> &'static str {
Intern::new(s.to_string()).as_ref()
}
#[wasm_bindgen]
pub fn generate_material_design_3_scheme(
source_color: &str,

View File

@ -5,7 +5,7 @@ use palette::{
Oklch, ShiftHue,
color_theory::{Analogous, Complementary, SplitComplementary, Tetradic, Triadic},
};
use serde::{Serialize, ser::SerializeStruct};
use serde::Serialize;
use crate::{
convert::map_oklch_to_srgb_hex,
@ -16,7 +16,8 @@ use crate::{
},
};
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ColorUnit {
pub root: ColorSet,
pub surface: ColorSet,
@ -82,20 +83,8 @@ impl ColorUnit {
}
}
impl Serialize for ColorUnit {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_struct("ColorUnit", 3)?;
state.serialize_field("root", &self.root)?;
state.serialize_field("surface", &self.surface)?;
state.serialize_field("swatch", &self.swatch)?;
state.end()
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Baseline {
pub primary: ColorUnit,
pub secondary: Option<ColorUnit>,
@ -105,18 +94,26 @@ pub struct Baseline {
pub neutral_variant: ColorSet,
pub surface: ColorSet,
pub surface_variant: ColorSet,
#[serde(serialize_with = "crate::schemes::q_style_2::swatch::serialize_neutral_swatch")]
pub neutral_swatch: Arc<NeutralSwatch>,
pub danger: ColorUnit,
pub success: ColorUnit,
pub warn: ColorUnit,
pub info: ColorUnit,
pub custom_colors: HashMap<String, ColorUnit>,
#[serde(serialize_with = "crate::foreign_serializer::serialize_oklch_to_hex")]
pub shadow: Oklch,
#[serde(serialize_with = "crate::foreign_serializer::serialize_oklch_to_hex")]
pub overlay: Oklch,
#[serde(serialize_with = "crate::foreign_serializer::serialize_oklch_to_hex")]
pub outline: Oklch,
#[serde(serialize_with = "crate::foreign_serializer::serialize_oklch_to_hex")]
pub outline_variant: Oklch,
#[serde(skip)]
pub neutral_lightness: f32,
#[serde(skip)]
pub scheme_settings: Arc<SchemeSetting>,
#[serde(skip)]
pub is_dark: bool,
}
@ -514,35 +511,3 @@ impl Baseline {
javascript_fields
}
}
impl Serialize for Baseline {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_struct("Baseline", 17)?;
state.serialize_field("primary", &self.primary)?;
state.serialize_field("secondary", &self.secondary)?;
state.serialize_field("tertiary", &self.tertiary)?;
state.serialize_field("accent", &self.accent)?;
state.serialize_field("neutral", &self.neutral)?;
state.serialize_field("neutralVariant", &self.neutral_variant)?;
state.serialize_field("surface", &self.surface)?;
state.serialize_field("surfaceVariant", &self.surface_variant)?;
state.serialize_field("danger", &self.danger)?;
state.serialize_field("success", &self.success)?;
state.serialize_field("warn", &self.warn)?;
state.serialize_field("info", &self.info)?;
state.serialize_field("shadow", &map_oklch_to_srgb_hex(&self.shadow))?;
state.serialize_field("overlay", &map_oklch_to_srgb_hex(&self.overlay))?;
state.serialize_field("outline", &map_oklch_to_srgb_hex(&self.outline))?;
state.serialize_field(
"outlineVariant",
&map_oklch_to_srgb_hex(&self.outline_variant),
)?;
state.serialize_field("custom", &self.custom_colors)?;
state.end()
}
}

View File

@ -3,7 +3,7 @@ use std::sync::Arc;
use linked_hash_map::LinkedHashMap;
use palette::{Oklch, color_difference::Wcag21RelativeContrast, luma::Luma};
use serde::{Serialize, ser::SerializeStruct};
use serde::Serialize;
use crate::{
convert::{map_oklch_to_luma, map_oklch_to_srgb_hex},
@ -13,17 +13,28 @@ use crate::{
},
};
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ColorSet {
#[serde(serialize_with = "crate::foreign_serializer::serialize_oklch_to_hex")]
pub root: Oklch,
#[serde(serialize_with = "crate::foreign_serializer::serialize_oklch_to_hex")]
pub active: Oklch,
#[serde(serialize_with = "crate::foreign_serializer::serialize_oklch_to_hex")]
pub focus: Oklch,
#[serde(serialize_with = "crate::foreign_serializer::serialize_oklch_to_hex")]
pub hover: Oklch,
#[serde(serialize_with = "crate::foreign_serializer::serialize_oklch_to_hex")]
pub disabled: Oklch,
#[serde(serialize_with = "crate::foreign_serializer::serialize_oklch_to_hex")]
pub on_root: Oklch,
#[serde(serialize_with = "crate::foreign_serializer::serialize_oklch_to_hex")]
pub on_disabled: Oklch,
#[serde(skip)]
pub neutral_swatch: Arc<NeutralSwatch>,
#[serde(skip)]
pub neutral_lightness: f32,
#[serde(skip)]
pub scheme_settings: Arc<SchemeSetting>,
}
@ -266,28 +277,3 @@ impl ColorSet {
variables
}
}
impl Serialize for ColorSet {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let root = map_oklch_to_srgb_hex(&self.root);
let hover = map_oklch_to_srgb_hex(&self.hover);
let active = map_oklch_to_srgb_hex(&self.active);
let focus = map_oklch_to_srgb_hex(&self.focus);
let disabled = map_oklch_to_srgb_hex(&self.disabled);
let on_root = map_oklch_to_srgb_hex(&self.on_root);
let on_disabled = map_oklch_to_srgb_hex(&self.on_disabled);
let mut state = serializer.serialize_struct("ColorSet", 6)?;
state.serialize_field("root", &root)?;
state.serialize_field("hover", &hover)?;
state.serialize_field("active", &active)?;
state.serialize_field("focus", &focus)?;
state.serialize_field("disabled", &disabled)?;
state.serialize_field("onRoot", &on_root)?;
state.serialize_field("onDisabled", &on_disabled)?;
state.end()
}
}

View File

@ -6,7 +6,7 @@ use serde::Serialize;
use crate::{
errors, parse_option_to_oklch, parse_to_oklch,
schemes::{q_style::SchemeSetting, q_style_2::baseline::Baseline, SchemeExport},
schemes::{SchemeExport, q_style::SchemeSetting, q_style_2::baseline::Baseline},
};
mod baseline;

View File

@ -1,9 +1,13 @@
use internment::Intern;
use std::sync::Arc;
use linked_hash_map::LinkedHashMap;
use palette::Oklch;
use serde::{Serialize, ser::SerializeStruct};
use serde::{Serialize, Serializer, ser::SerializeStruct};
use crate::convert::map_oklch_to_srgb_hex;
use crate::{
convert::map_oklch_to_srgb_hex,
schemes::{get_static_str, q_style::NeutralSwatch},
};
static SWATCH_LIGHTINGS: [u8; 16] = [
10, 15, 20, 25, 30, 35, 40, 50, 60, 70, 75, 80, 85, 90, 95, 98,
@ -77,10 +81,6 @@ impl Swatch {
}
}
fn get_static_str(s: &str) -> &'static str {
Intern::new(s.to_string()).as_ref()
}
impl Serialize for Swatch {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@ -97,3 +97,23 @@ impl Serialize for Swatch {
state.end()
}
}
pub fn serialize_neutral_swatch<S>(
swatch: &Arc<NeutralSwatch>,
serailizer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let swatch = swatch.clone();
let mut swatch_struct = serailizer.serialize_struct("NeutralSwatch", SWATCH_LIGHTINGS.len())?;
for l in SWATCH_LIGHTINGS {
let color = swatch.get((l as f32) / 100.0);
let color = map_oklch_to_srgb_hex(&color);
let key: &'static str = get_static_str(&format!("{l:02}"));
swatch_struct.serialize_field(key, &color)?;
}
swatch_struct.end()
}