feat(q_style_2): 新增QStyle2颜色方案模块
添加QStyle2颜色方案模块,包含基础颜色集、色板生成和自动配色功能 实现颜色方案的CSS、SCSS和JavaScript输出支持 新增generate_q_scheme_2_manually函数用于手动生成QStyle2方案
This commit is contained in:
parent
2bbb46ced1
commit
bd4a2c9b49
@ -7,12 +7,13 @@ use q_style::{QScheme, SchemeSetting};
|
||||
use swatch_style::{SwatchEntry, SwatchSchemeSetting};
|
||||
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
|
||||
|
||||
use crate::errors;
|
||||
use crate::{errors, schemes::q_style_2::QScheme2};
|
||||
|
||||
pub mod material_design_2;
|
||||
pub mod material_design_3;
|
||||
pub mod material_design_3_dynamic;
|
||||
pub mod q_style;
|
||||
pub mod q_style_2;
|
||||
pub mod swatch_style;
|
||||
|
||||
pub trait SchemeExport {
|
||||
@ -135,6 +136,50 @@ pub fn generate_q_scheme_manually(
|
||||
.map_err(|_| errors::ColorError::UnableToAssembleOutput)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn generate_q_scheme_2_manually(
|
||||
primary_color: &str,
|
||||
secondary_color: Option<String>,
|
||||
tertiary_color: Option<String>,
|
||||
accent_color: Option<String>,
|
||||
danger_color: &str,
|
||||
success_color: &str,
|
||||
warn_color: &str,
|
||||
info_color: &str,
|
||||
fg_color: &str,
|
||||
bg_color: &str,
|
||||
custom_colors: JsValue,
|
||||
setting: SchemeSetting,
|
||||
) -> Result<JsValue, errors::ColorError> {
|
||||
let mut scheme = QScheme2::new(
|
||||
primary_color,
|
||||
secondary_color.as_deref(),
|
||||
tertiary_color.as_deref(),
|
||||
accent_color.as_deref(),
|
||||
danger_color,
|
||||
success_color,
|
||||
warn_color,
|
||||
info_color,
|
||||
fg_color,
|
||||
bg_color,
|
||||
setting,
|
||||
)?;
|
||||
let custom_colors: HashMap<String, String> = serde_wasm_bindgen::from_value(custom_colors)
|
||||
.map_err(|_| errors::ColorError::UnableToParseArgument)?;
|
||||
for (name, color) in custom_colors {
|
||||
scheme.add_custom_color(&name, &color)?;
|
||||
}
|
||||
|
||||
Ok(serde_wasm_bindgen::to_value(&(
|
||||
scheme.clone(),
|
||||
scheme.output_css_variables(),
|
||||
scheme.output_css_auto_scheme_variables(),
|
||||
scheme.output_scss_variables(),
|
||||
scheme.output_javascript_object(),
|
||||
))
|
||||
.map_err(|_| errors::ColorError::UnableToAssembleOutput)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn generate_swatch_scheme(
|
||||
colors: Vec<SwatchEntry>,
|
||||
|
@ -3,7 +3,6 @@ use std::str::FromStr;
|
||||
use baseline::Baseline;
|
||||
use linked_hash_set::LinkedHashSet;
|
||||
use palette::FromColor;
|
||||
use scheme_setting::{ColorExpand, WACGSetting};
|
||||
use serde::Serialize;
|
||||
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
|
||||
|
||||
@ -16,7 +15,8 @@ mod color_set;
|
||||
mod neutral_swatch;
|
||||
mod scheme_setting;
|
||||
|
||||
pub use scheme_setting::{ColorShifting, SchemeSetting};
|
||||
pub use neutral_swatch::NeutralSwatch;
|
||||
pub use scheme_setting::{ColorExpand, ColorShifting, SchemeSetting, WACGSetting};
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct QScheme {
|
||||
|
545
color-module/src/schemes/q_style_2/baseline.rs
Normal file
545
color-module/src/schemes/q_style_2/baseline.rs
Normal file
@ -0,0 +1,545 @@
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use linked_hash_map::LinkedHashMap;
|
||||
use palette::{
|
||||
color_theory::{Analogous, Complementary, SplitComplementary, Tetradic, Triadic},
|
||||
Oklch, ShiftHue,
|
||||
};
|
||||
use serde::{ser::SerializeStruct, Serialize};
|
||||
|
||||
use crate::{
|
||||
convert::map_oklch_to_srgb_hex,
|
||||
errors,
|
||||
schemes::{
|
||||
q_style::{ColorExpand, NeutralSwatch, SchemeSetting},
|
||||
q_style_2::{color_set::ColorSet, swatch::Swatch},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ColorUnit {
|
||||
pub root: ColorSet,
|
||||
pub surface: ColorSet,
|
||||
pub swatch: Swatch,
|
||||
}
|
||||
|
||||
impl ColorUnit {
|
||||
pub fn new(
|
||||
color: &Oklch,
|
||||
neutral_swatch: &Arc<NeutralSwatch>,
|
||||
foreground_lightness: f32,
|
||||
settings: &Arc<SchemeSetting>,
|
||||
) -> Self {
|
||||
let root = ColorSet::new(color, neutral_swatch, foreground_lightness, settings);
|
||||
let surface = root.generate_surface_set();
|
||||
let swatch = root.generate_swatch();
|
||||
|
||||
Self {
|
||||
root,
|
||||
surface,
|
||||
swatch,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_css_variables(&self, prefix: &str, name: &str) -> Vec<String> {
|
||||
let mut css_variables = Vec::new();
|
||||
|
||||
css_variables.extend(self.root.to_css_variables(prefix, name));
|
||||
css_variables.extend(self.surface.to_css_variables(prefix, name));
|
||||
css_variables.extend(self.swatch.to_css_variables(prefix, name));
|
||||
|
||||
css_variables
|
||||
}
|
||||
|
||||
pub fn to_css_auto_scheme_collection(&self, name: &str) -> LinkedHashMap<String, String> {
|
||||
let mut css_auto_scheme_collection = LinkedHashMap::new();
|
||||
|
||||
css_auto_scheme_collection.extend(self.root.to_css_auto_scheme_collection(name));
|
||||
css_auto_scheme_collection.extend(self.surface.to_css_auto_scheme_collection(name));
|
||||
css_auto_scheme_collection.extend(self.swatch.to_css_auto_scheme_collection(name));
|
||||
|
||||
css_auto_scheme_collection
|
||||
}
|
||||
|
||||
pub fn to_scss_variables(&self, prefix: &str, name: &str) -> Vec<String> {
|
||||
let mut scss_variables = Vec::new();
|
||||
|
||||
scss_variables.extend(self.root.to_scss_variables(prefix, name));
|
||||
scss_variables.extend(self.surface.to_scss_variables(prefix, name));
|
||||
scss_variables.extend(self.swatch.to_scss_variables(prefix, name));
|
||||
|
||||
scss_variables
|
||||
}
|
||||
|
||||
pub fn to_javascript_fields(&self, name: &str) -> Vec<String> {
|
||||
let mut js_object_fields = Vec::new();
|
||||
|
||||
js_object_fields.extend(self.root.to_javascript_fields(name));
|
||||
js_object_fields.extend(self.surface.to_javascript_fields(name));
|
||||
js_object_fields.extend(self.swatch.to_javascript_fields(name));
|
||||
|
||||
js_object_fields
|
||||
}
|
||||
}
|
||||
|
||||
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)]
|
||||
pub struct Baseline {
|
||||
pub primary: ColorUnit,
|
||||
pub secondary: Option<ColorUnit>,
|
||||
pub tertiary: Option<ColorUnit>,
|
||||
pub accent: Option<ColorUnit>,
|
||||
pub neutral: ColorSet,
|
||||
pub neutral_variant: ColorSet,
|
||||
pub surface: ColorSet,
|
||||
pub surface_variant: ColorSet,
|
||||
pub neutral_swatch: Arc<NeutralSwatch>,
|
||||
pub danger: ColorUnit,
|
||||
pub success: ColorUnit,
|
||||
pub warn: ColorUnit,
|
||||
pub info: ColorUnit,
|
||||
pub custom_colors: HashMap<String, ColorUnit>,
|
||||
pub shadow: Oklch,
|
||||
pub overlay: Oklch,
|
||||
pub outline: Oklch,
|
||||
pub outline_variant: Oklch,
|
||||
pub neutral_lightness: f32,
|
||||
pub scheme_settings: Arc<SchemeSetting>,
|
||||
pub is_dark: bool,
|
||||
}
|
||||
|
||||
impl Baseline {
|
||||
pub fn new(
|
||||
primary: &Oklch,
|
||||
secondary: Option<&Oklch>,
|
||||
tertiary: Option<&Oklch>,
|
||||
accent: Option<&Oklch>,
|
||||
danger: &Oklch,
|
||||
success: &Oklch,
|
||||
warn: &Oklch,
|
||||
info: &Oklch,
|
||||
neutral_lightest: &Oklch,
|
||||
neutral_darkest: &Oklch,
|
||||
settings: &Arc<SchemeSetting>,
|
||||
is_dark: bool,
|
||||
) -> Self {
|
||||
let (final_secondary, final_tertiary, final_accent) = match settings.expand_method {
|
||||
ColorExpand::Complementary => {
|
||||
let sec_color = secondary.cloned().or(Some(primary.complementary()));
|
||||
(sec_color, tertiary.cloned(), accent.cloned())
|
||||
}
|
||||
ColorExpand::Analogous => {
|
||||
let analogous_color = primary.analogous();
|
||||
(
|
||||
secondary.cloned().or(Some(analogous_color.0)),
|
||||
tertiary.cloned().or(Some(analogous_color.1)),
|
||||
accent.cloned(),
|
||||
)
|
||||
}
|
||||
ColorExpand::AnalogousAndComplementary => {
|
||||
let analogous_color = primary.analogous();
|
||||
let complementary_color = primary.complementary();
|
||||
(
|
||||
secondary.cloned().or(Some(analogous_color.0)),
|
||||
tertiary.cloned().or(Some(analogous_color.1)),
|
||||
accent.cloned().or(Some(complementary_color)),
|
||||
)
|
||||
}
|
||||
ColorExpand::Triadic => {
|
||||
let triadic_color = primary.triadic();
|
||||
(
|
||||
secondary.cloned().or(Some(triadic_color.0)),
|
||||
tertiary.cloned().or(Some(triadic_color.1)),
|
||||
accent.cloned(),
|
||||
)
|
||||
}
|
||||
ColorExpand::SplitComplementary => {
|
||||
let split_complementary_color = primary.split_complementary();
|
||||
(
|
||||
secondary.cloned().or(Some(split_complementary_color.0)),
|
||||
tertiary.cloned(),
|
||||
accent.cloned().or(Some(split_complementary_color.1)),
|
||||
)
|
||||
}
|
||||
ColorExpand::Tetradic => {
|
||||
let tetradic_color = primary.tetradic();
|
||||
(
|
||||
secondary.cloned().or(Some(tetradic_color.0)),
|
||||
tertiary.cloned().or(Some(tetradic_color.2)),
|
||||
accent.cloned().or(Some(tetradic_color.1)),
|
||||
)
|
||||
}
|
||||
ColorExpand::Square => {
|
||||
let c_90 = primary.shift_hue(90.0);
|
||||
let complementary_color = primary.complementary();
|
||||
let c_270 = primary.shift_hue(270.0);
|
||||
(
|
||||
secondary.cloned().or(Some(c_90)),
|
||||
tertiary.cloned().or(Some(c_270)),
|
||||
accent.cloned().or(Some(complementary_color)),
|
||||
)
|
||||
}
|
||||
};
|
||||
let reference_lightness = if is_dark {
|
||||
neutral_lightest.l
|
||||
} else {
|
||||
neutral_darkest.l
|
||||
};
|
||||
let neutral_swatch = Arc::new(NeutralSwatch::new(*neutral_lightest, *neutral_darkest));
|
||||
let outline_color = neutral_swatch.get(reference_lightness * 0.8);
|
||||
let outline_variant_color = neutral_swatch.get(reference_lightness * 0.6);
|
||||
let shadow_color = neutral_swatch.get(10.0);
|
||||
let overlay_color = neutral_swatch.get(reference_lightness * 0.2);
|
||||
|
||||
let neutral_color = neutral_swatch.get(75.0);
|
||||
let neutral_variant_color = neutral_swatch.get(55.0);
|
||||
let surface_color = neutral_swatch.get(98.0);
|
||||
let surface_variant_color = neutral_swatch.get(90.0);
|
||||
|
||||
let neutral_set = ColorSet::new(
|
||||
&neutral_color,
|
||||
&neutral_swatch,
|
||||
reference_lightness,
|
||||
settings,
|
||||
);
|
||||
let neutral_variant_set = ColorSet::new(
|
||||
&neutral_variant_color,
|
||||
&neutral_swatch,
|
||||
reference_lightness,
|
||||
settings,
|
||||
);
|
||||
let surface_set = ColorSet::new(
|
||||
&surface_color,
|
||||
&neutral_swatch,
|
||||
reference_lightness,
|
||||
settings,
|
||||
);
|
||||
let surface_variant_set = ColorSet::new(
|
||||
&surface_variant_color,
|
||||
&neutral_swatch,
|
||||
reference_lightness,
|
||||
settings,
|
||||
);
|
||||
|
||||
let primary_unit = ColorUnit::new(primary, &neutral_swatch, reference_lightness, settings);
|
||||
let secondary_unit = final_secondary
|
||||
.map(|color| ColorUnit::new(&color, &neutral_swatch, reference_lightness, settings));
|
||||
let tertiary_unit = final_tertiary
|
||||
.map(|color| ColorUnit::new(&color, &neutral_swatch, reference_lightness, settings));
|
||||
let accent_unit = final_accent
|
||||
.map(|color| ColorUnit::new(&color, &neutral_swatch, reference_lightness, settings));
|
||||
|
||||
let danger_unit = ColorUnit::new(danger, &neutral_swatch, reference_lightness, settings);
|
||||
let success_unit = ColorUnit::new(success, &neutral_swatch, reference_lightness, settings);
|
||||
let warn_unit = ColorUnit::new(warn, &neutral_swatch, reference_lightness, settings);
|
||||
let info_unit = ColorUnit::new(info, &neutral_swatch, reference_lightness, settings);
|
||||
|
||||
Self {
|
||||
primary: primary_unit,
|
||||
secondary: secondary_unit,
|
||||
tertiary: tertiary_unit,
|
||||
accent: accent_unit,
|
||||
neutral: neutral_set,
|
||||
neutral_variant: neutral_variant_set,
|
||||
surface: surface_set,
|
||||
surface_variant: surface_variant_set,
|
||||
neutral_swatch,
|
||||
danger: danger_unit,
|
||||
success: success_unit,
|
||||
warn: warn_unit,
|
||||
info: info_unit,
|
||||
custom_colors: HashMap::new(),
|
||||
shadow: shadow_color,
|
||||
overlay: overlay_color,
|
||||
outline: outline_color,
|
||||
outline_variant: outline_variant_color,
|
||||
neutral_lightness: reference_lightness,
|
||||
scheme_settings: settings.clone(),
|
||||
is_dark,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_custom_color(
|
||||
&mut self,
|
||||
name: &str,
|
||||
color: &Oklch,
|
||||
) -> Result<(), errors::ColorError> {
|
||||
let custom_color = ColorUnit::new(
|
||||
color,
|
||||
&self.neutral_swatch,
|
||||
self.neutral_lightness,
|
||||
&self.scheme_settings,
|
||||
);
|
||||
self.custom_colors.insert(name.to_string(), custom_color);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn to_css_variables(&self) -> Vec<String> {
|
||||
let mut css_variables = Vec::new();
|
||||
let scheme_mode = if self.is_dark { "dark" } else { "light" };
|
||||
|
||||
css_variables.extend(self.primary.to_css_variables(scheme_mode, "primary"));
|
||||
if let Some(secondary) = &self.secondary {
|
||||
css_variables.extend(secondary.to_css_variables(scheme_mode, "secondary"));
|
||||
}
|
||||
if let Some(tertiary) = &self.tertiary {
|
||||
css_variables.extend(tertiary.to_css_variables(scheme_mode, "tertiary"));
|
||||
}
|
||||
if let Some(accent) = &self.accent {
|
||||
css_variables.extend(accent.to_css_variables(scheme_mode, "accent"));
|
||||
}
|
||||
css_variables.extend(self.neutral.to_css_variables(scheme_mode, "neutral"));
|
||||
css_variables.extend(
|
||||
self.neutral_variant
|
||||
.to_css_variables(scheme_mode, "neutral-variant"),
|
||||
);
|
||||
css_variables.extend(self.surface.to_css_variables(scheme_mode, "surface"));
|
||||
css_variables.extend(
|
||||
self.surface_variant
|
||||
.to_css_variables(scheme_mode, "surface-variant"),
|
||||
);
|
||||
css_variables.extend(self.danger.to_css_variables(scheme_mode, "danger"));
|
||||
css_variables.extend(self.success.to_css_variables(scheme_mode, "success"));
|
||||
css_variables.extend(self.warn.to_css_variables(scheme_mode, "warn"));
|
||||
css_variables.extend(self.info.to_css_variables(scheme_mode, "info"));
|
||||
|
||||
css_variables.push(format!(
|
||||
"--color-{scheme_mode}-shadow: #{};",
|
||||
map_oklch_to_srgb_hex(&self.shadow)
|
||||
));
|
||||
css_variables.push(format!(
|
||||
"--color-{scheme_mode}-overlay: #{};",
|
||||
map_oklch_to_srgb_hex(&self.overlay)
|
||||
));
|
||||
css_variables.push(format!(
|
||||
"--color-{scheme_mode}-outlint: #{};",
|
||||
map_oklch_to_srgb_hex(&self.outline)
|
||||
));
|
||||
css_variables.push(format!(
|
||||
"--color-{scheme_mode}-outline-variant: #{};",
|
||||
map_oklch_to_srgb_hex(&self.outline_variant)
|
||||
));
|
||||
|
||||
for (name, color_unit) in &self.custom_colors {
|
||||
css_variables.extend(color_unit.to_css_variables(scheme_mode, name));
|
||||
}
|
||||
|
||||
css_variables
|
||||
}
|
||||
|
||||
pub fn to_css_auto_scheme_collection(&self) -> LinkedHashMap<String, String> {
|
||||
let mut css_variables = LinkedHashMap::new();
|
||||
|
||||
css_variables.extend(self.primary.to_css_auto_scheme_collection("primary"));
|
||||
if let Some(secondary) = &self.secondary {
|
||||
css_variables.extend(secondary.to_css_auto_scheme_collection("secondary"));
|
||||
}
|
||||
if let Some(tertiary) = &self.tertiary {
|
||||
css_variables.extend(tertiary.to_css_auto_scheme_collection("tertiary"));
|
||||
}
|
||||
if let Some(accent) = &self.accent {
|
||||
css_variables.extend(accent.to_css_auto_scheme_collection("accent"));
|
||||
}
|
||||
css_variables.extend(self.neutral.to_css_auto_scheme_collection("neutral"));
|
||||
css_variables.extend(
|
||||
self.neutral_variant
|
||||
.to_css_auto_scheme_collection("neutral-variant"),
|
||||
);
|
||||
css_variables.extend(self.surface.to_css_auto_scheme_collection("surface"));
|
||||
css_variables.extend(
|
||||
self.surface_variant
|
||||
.to_css_auto_scheme_collection("surface-variant"),
|
||||
);
|
||||
|
||||
css_variables.insert("shadow".to_string(), map_oklch_to_srgb_hex(&self.shadow));
|
||||
css_variables.insert("overlay".to_string(), map_oklch_to_srgb_hex(&self.overlay));
|
||||
css_variables.insert("outline".to_string(), map_oklch_to_srgb_hex(&self.outline));
|
||||
css_variables.insert(
|
||||
"outline-variant".to_string(),
|
||||
map_oklch_to_srgb_hex(&self.outline_variant),
|
||||
);
|
||||
|
||||
for (name, color) in &self.custom_colors {
|
||||
css_variables.extend(color.to_css_auto_scheme_collection(name));
|
||||
}
|
||||
|
||||
css_variables
|
||||
}
|
||||
|
||||
pub fn to_scss_variables(&self) -> Vec<String> {
|
||||
let mut scss_variables = Vec::new();
|
||||
let scheme_mode = if self.is_dark { "dark" } else { "light" };
|
||||
|
||||
scss_variables.extend(self.primary.to_scss_variables(scheme_mode, "primary"));
|
||||
if let Some(secondary) = &self.secondary {
|
||||
scss_variables.extend(secondary.to_scss_variables(scheme_mode, "secondary"));
|
||||
}
|
||||
if let Some(tertiary) = &self.tertiary {
|
||||
scss_variables.extend(tertiary.to_scss_variables(scheme_mode, "tertiary"));
|
||||
}
|
||||
if let Some(accent) = &self.accent {
|
||||
scss_variables.extend(accent.to_scss_variables(scheme_mode, "accent"));
|
||||
}
|
||||
|
||||
scss_variables.extend(self.neutral.to_scss_variables(scheme_mode, "neutral"));
|
||||
scss_variables.extend(
|
||||
self.neutral_variant
|
||||
.to_scss_variables(scheme_mode, "neutral-variant"),
|
||||
);
|
||||
scss_variables.extend(self.surface.to_scss_variables(scheme_mode, "surface"));
|
||||
scss_variables.extend(
|
||||
self.surface_variant
|
||||
.to_scss_variables(scheme_mode, "surface-variant"),
|
||||
);
|
||||
|
||||
scss_variables.push(format!(
|
||||
"--color-{scheme_mode}-shadow: #{};",
|
||||
map_oklch_to_srgb_hex(&self.shadow)
|
||||
));
|
||||
scss_variables.push(format!(
|
||||
"--color-{scheme_mode}-overlay: #{};",
|
||||
map_oklch_to_srgb_hex(&self.overlay)
|
||||
));
|
||||
scss_variables.push(format!(
|
||||
"--color-{scheme_mode}-outlint: #{};",
|
||||
map_oklch_to_srgb_hex(&self.outline)
|
||||
));
|
||||
scss_variables.push(format!(
|
||||
"--color-{scheme_mode}-outline-variant: #{};",
|
||||
map_oklch_to_srgb_hex(&self.outline_variant)
|
||||
));
|
||||
|
||||
scss_variables
|
||||
}
|
||||
|
||||
pub fn to_javascript_fields(&self) -> Vec<String> {
|
||||
let mut javascript_fields = Vec::new();
|
||||
let scheme_mode = if self.is_dark { "dark" } else { "light" };
|
||||
|
||||
javascript_fields.push(format!("{scheme_mode}: {{"));
|
||||
let indent = " ".repeat(4);
|
||||
|
||||
for line in self.primary.to_javascript_fields("primary").iter() {
|
||||
javascript_fields.push(format!("{indent}{line:4}"));
|
||||
}
|
||||
for line in self
|
||||
.secondary
|
||||
.as_ref()
|
||||
.map(|s| s.to_javascript_fields("secondary"))
|
||||
.unwrap_or(Vec::new())
|
||||
.iter()
|
||||
{
|
||||
javascript_fields.push(format!("{indent}{line:4}"));
|
||||
}
|
||||
for line in self
|
||||
.tertiary
|
||||
.as_ref()
|
||||
.map(|s| s.to_javascript_fields("tertiary"))
|
||||
.unwrap_or(Vec::new())
|
||||
.iter()
|
||||
{
|
||||
javascript_fields.push(format!("{indent}{line:4}"));
|
||||
}
|
||||
for line in self
|
||||
.accent
|
||||
.as_ref()
|
||||
.map(|s| s.to_javascript_fields("accent"))
|
||||
.unwrap_or(Vec::new())
|
||||
.iter()
|
||||
{
|
||||
javascript_fields.push(format!("{indent}{line:4}"));
|
||||
}
|
||||
|
||||
for line in self.neutral.to_javascript_fields("neutral").iter() {
|
||||
javascript_fields.push(format!("{indent}{line:4}"));
|
||||
}
|
||||
for line in self
|
||||
.neutral_variant
|
||||
.to_javascript_fields("neutral_variant")
|
||||
.iter()
|
||||
{
|
||||
javascript_fields.push(format!("{indent}{line:4}"));
|
||||
}
|
||||
for line in self.surface.to_javascript_fields("surface").iter() {
|
||||
javascript_fields.push(format!("{indent}{line:4}"));
|
||||
}
|
||||
for line in self
|
||||
.surface_variant
|
||||
.to_javascript_fields("surface_variant")
|
||||
.iter()
|
||||
{
|
||||
javascript_fields.push(format!("{indent}{line:4}"));
|
||||
}
|
||||
|
||||
javascript_fields.push(format!(
|
||||
"{indent}shadow: '#{}',",
|
||||
map_oklch_to_srgb_hex(&self.shadow)
|
||||
));
|
||||
javascript_fields.push(format!(
|
||||
"{indent}overlay: '#{}',",
|
||||
map_oklch_to_srgb_hex(&self.overlay)
|
||||
));
|
||||
javascript_fields.push(format!(
|
||||
"{indent}outline: '#{}',",
|
||||
map_oklch_to_srgb_hex(&self.outline)
|
||||
));
|
||||
javascript_fields.push(format!(
|
||||
"{indent}outlineVariant: '#{}',",
|
||||
map_oklch_to_srgb_hex(&self.outline_variant)
|
||||
));
|
||||
|
||||
for (name, color) in &self.custom_colors {
|
||||
let color_lines = color.to_javascript_fields(name);
|
||||
javascript_fields.extend(color_lines.iter().map(|s| format!("{indent}{s}")));
|
||||
}
|
||||
|
||||
javascript_fields.push("}".to_string());
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
291
color-module/src/schemes/q_style_2/color_set.rs
Normal file
291
color-module/src/schemes/q_style_2/color_set.rs
Normal file
@ -0,0 +1,291 @@
|
||||
use core::f32;
|
||||
use std::sync::Arc;
|
||||
|
||||
use linked_hash_map::LinkedHashMap;
|
||||
use palette::{color_difference::Wcag21RelativeContrast, luma::Luma, Oklch};
|
||||
use serde::{ser::SerializeStruct, Serialize};
|
||||
|
||||
use crate::{
|
||||
convert::{map_oklch_to_luma, map_oklch_to_srgb_hex},
|
||||
schemes::{
|
||||
q_style::{NeutralSwatch, SchemeSetting, WACGSetting},
|
||||
q_style_2::swatch::Swatch,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ColorSet {
|
||||
pub root: Oklch,
|
||||
pub active: Oklch,
|
||||
pub focus: Oklch,
|
||||
pub hover: Oklch,
|
||||
pub disabled: Oklch,
|
||||
pub on_root: Oklch,
|
||||
pub on_disabled: Oklch,
|
||||
pub neutral_swatch: Arc<NeutralSwatch>,
|
||||
pub neutral_lightness: f32,
|
||||
pub scheme_settings: Arc<SchemeSetting>,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn match_wacg(original: &Oklch<f32>, reference: &Luma) -> f32 {
|
||||
let luma_original = map_oklch_to_luma(original);
|
||||
luma_original.relative_contrast(*reference)
|
||||
}
|
||||
|
||||
fn search_for_common_wacg_color(
|
||||
reference_colors: &[&Oklch],
|
||||
neutral_swatch: &NeutralSwatch,
|
||||
minium_ratio: f32,
|
||||
) -> Oklch {
|
||||
// store in: (lightness, min_wacg_abs)
|
||||
let mut minium_match: (f32, f32) = (0.0, f32::INFINITY);
|
||||
let mut closest_match: (f32, f32) = (f32::INFINITY, f32::INFINITY);
|
||||
for scan_lightness in (0..=100).map(|x| x as f32 / 100.0) {
|
||||
let new_target = neutral_swatch.get(scan_lightness);
|
||||
let new_target_luma = map_oklch_to_luma(&new_target);
|
||||
let reference_wacgs = reference_colors
|
||||
.iter()
|
||||
.map(|ref_color| match_wacg(&ref_color, &new_target_luma) - minium_ratio)
|
||||
.min_by(|a, b| a.abs().total_cmp(&b.abs()))
|
||||
.unwrap_or(f32::NEG_INFINITY);
|
||||
if reference_wacgs.abs() < closest_match.1.abs() {
|
||||
closest_match = (scan_lightness, reference_wacgs);
|
||||
}
|
||||
if reference_wacgs >= 0.0 && reference_wacgs.abs() < minium_match.1.abs() {
|
||||
minium_match = (scan_lightness, reference_wacgs);
|
||||
}
|
||||
}
|
||||
if minium_match.1 != f32::INFINITY {
|
||||
neutral_swatch.get(minium_match.0)
|
||||
} else {
|
||||
neutral_swatch.get(closest_match.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorSet {
|
||||
pub fn new(
|
||||
color: &Oklch,
|
||||
neutral_swatch: &Arc<NeutralSwatch>,
|
||||
neutral_lightness: f32,
|
||||
settings: &Arc<SchemeSetting>,
|
||||
) -> Self {
|
||||
let neutral_swatch = Arc::clone(neutral_swatch);
|
||||
let settings = Arc::clone(settings);
|
||||
|
||||
let root = color.clone();
|
||||
let hover = color * settings.hover;
|
||||
let active = color * settings.active;
|
||||
let focus = color * settings.focus;
|
||||
let disabled = color * settings.disabled;
|
||||
|
||||
let color_list = &[&root, &hover, &active, &focus];
|
||||
|
||||
let (on_root, on_disabled) = match settings.wacg_follows {
|
||||
WACGSetting::Fixed => (
|
||||
neutral_swatch.get(neutral_lightness),
|
||||
neutral_swatch.get(neutral_lightness),
|
||||
),
|
||||
WACGSetting::AutomaticAA => (
|
||||
search_for_common_wacg_color(color_list, &neutral_swatch, 4.5),
|
||||
search_for_common_wacg_color(&[&disabled], &neutral_swatch, 4.5),
|
||||
),
|
||||
WACGSetting::AutomaticAAA => (
|
||||
search_for_common_wacg_color(color_list, &neutral_swatch, 7.0),
|
||||
search_for_common_wacg_color(&[&disabled], &neutral_swatch, 7.0),
|
||||
),
|
||||
WACGSetting::HighContrast => (
|
||||
search_for_common_wacg_color(color_list, &neutral_swatch, 21.0),
|
||||
search_for_common_wacg_color(&[&disabled], &neutral_swatch, 21.0),
|
||||
),
|
||||
};
|
||||
|
||||
Self {
|
||||
root,
|
||||
active,
|
||||
focus,
|
||||
hover,
|
||||
disabled,
|
||||
on_root,
|
||||
on_disabled,
|
||||
neutral_swatch,
|
||||
neutral_lightness,
|
||||
scheme_settings: settings,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_surface_set(&self) -> Self {
|
||||
let root_swatch = Swatch::new(&self.root);
|
||||
let root_lightness = self.root.l;
|
||||
let surface_lightness = if root_lightness + 40.0 > 90.0 {
|
||||
root_lightness - 40.0
|
||||
} else {
|
||||
root_lightness + 40.0
|
||||
};
|
||||
let surface_color = root_swatch.get(surface_lightness);
|
||||
|
||||
Self::new(
|
||||
&surface_color,
|
||||
&self.neutral_swatch,
|
||||
self.neutral_lightness,
|
||||
&self.scheme_settings,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn generate_swatch(&self) -> Swatch {
|
||||
Swatch::new(&self.root)
|
||||
}
|
||||
|
||||
fn root_hex(&self) -> String {
|
||||
map_oklch_to_srgb_hex(&self.root)
|
||||
}
|
||||
|
||||
fn hover_hex(&self) -> String {
|
||||
map_oklch_to_srgb_hex(&self.hover)
|
||||
}
|
||||
|
||||
fn active_hex(&self) -> String {
|
||||
map_oklch_to_srgb_hex(&self.active)
|
||||
}
|
||||
|
||||
fn focus_hex(&self) -> String {
|
||||
map_oklch_to_srgb_hex(&self.focus)
|
||||
}
|
||||
|
||||
fn disabled_hex(&self) -> String {
|
||||
map_oklch_to_srgb_hex(&self.disabled)
|
||||
}
|
||||
|
||||
fn on_root_hex(&self) -> String {
|
||||
map_oklch_to_srgb_hex(&self.on_root)
|
||||
}
|
||||
|
||||
fn on_disabled_hex(&self) -> String {
|
||||
map_oklch_to_srgb_hex(&self.on_disabled)
|
||||
}
|
||||
|
||||
pub fn to_css_variables(&self, prefix: &str, name: &str) -> Vec<String> {
|
||||
let mut variables = Vec::new();
|
||||
|
||||
variables.push(format!("--color-{prefix}-{name}: #{};", self.root_hex()));
|
||||
variables.push(format!(
|
||||
"--color-{prefix}-{name}-hover: #{};",
|
||||
self.hover_hex()
|
||||
));
|
||||
variables.push(format!(
|
||||
"--color-{prefix}-{name}-active: #{};",
|
||||
self.active_hex()
|
||||
));
|
||||
variables.push(format!(
|
||||
"--color-{prefix}-{name}-focus: #{};",
|
||||
self.focus_hex()
|
||||
));
|
||||
variables.push(format!(
|
||||
"--color-{prefix}-{name}-disabled: ${};",
|
||||
self.disabled_hex()
|
||||
));
|
||||
variables.push(format!(
|
||||
"--color-{prefix}-on-{name}: #{};",
|
||||
self.on_root_hex()
|
||||
));
|
||||
variables.push(format!(
|
||||
"--color-{prefix}-on-{name}-disabled: #{};",
|
||||
self.on_disabled_hex()
|
||||
));
|
||||
|
||||
variables
|
||||
}
|
||||
|
||||
pub fn to_css_auto_scheme_collection(&self, name: &str) -> LinkedHashMap<String, String> {
|
||||
let mut collection = LinkedHashMap::new();
|
||||
|
||||
collection.insert(format!("{name}"), self.root_hex());
|
||||
collection.insert(format!("{name}-hover"), self.hover_hex());
|
||||
collection.insert(format!("{name}-active"), self.active_hex());
|
||||
collection.insert(format!("{name}-focus"), self.focus_hex());
|
||||
collection.insert(format!("{name}-disabled"), self.disabled_hex());
|
||||
collection.insert(format!("on-{name}"), self.on_root_hex());
|
||||
collection.insert(format!("on-{name}-disabled"), self.on_disabled_hex());
|
||||
|
||||
collection
|
||||
}
|
||||
|
||||
pub fn to_scss_variables(&self, prefix: &str, name: &str) -> Vec<String> {
|
||||
let mut variables = Vec::new();
|
||||
|
||||
variables.push(format!("&color-{prefix}-{name}: #{};", self.root_hex()));
|
||||
variables.push(format!(
|
||||
"$color-{prefix}-{name}-hover: #{};",
|
||||
self.hover_hex()
|
||||
));
|
||||
variables.push(format!(
|
||||
"$color-{prefix}-{name}-active: #{};",
|
||||
self.active_hex()
|
||||
));
|
||||
variables.push(format!(
|
||||
"$color-{prefix}-{name}-focus: ${};",
|
||||
self.focus_hex()
|
||||
));
|
||||
variables.push(format!(
|
||||
"$color-{prefix}-{name}-disabled: #{};",
|
||||
self.disabled_hex()
|
||||
));
|
||||
variables.push(format!(
|
||||
"$color-{prefix}-on-{name}: #{};",
|
||||
self.on_root_hex()
|
||||
));
|
||||
variables.push(format!(
|
||||
"$color-{prefix}-on-{name}-disabled: #{};",
|
||||
self.on_disabled_hex()
|
||||
));
|
||||
|
||||
variables
|
||||
}
|
||||
|
||||
pub fn to_javascript_fields(&self, name: &str) -> Vec<String> {
|
||||
let mut variables = Vec::new();
|
||||
let capitalized_name = name
|
||||
.chars()
|
||||
.next()
|
||||
.unwrap()
|
||||
.to_ascii_uppercase()
|
||||
.to_string()
|
||||
+ &name[1..];
|
||||
|
||||
variables.push(format!("{name}: '#{}',", self.root_hex()));
|
||||
variables.push(format!("{name}Hover: '#{}',", self.hover_hex()));
|
||||
variables.push(format!("{name}Active: '#{}',", self.active_hex()));
|
||||
variables.push(format!("{name}Focus: '#{}',", self.focus_hex()));
|
||||
variables.push(format!("{name}Disabled: '#{}',", self.disabled_hex()));
|
||||
variables.push(format!("on{capitalized_name}: '#{}',", self.on_root_hex()));
|
||||
variables.push(format!(
|
||||
"on{capitalized_name}Disabled: '#{}',",
|
||||
self.on_disabled_hex()
|
||||
));
|
||||
|
||||
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 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("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()
|
||||
}
|
||||
}
|
157
color-module/src/schemes/q_style_2/mod.rs
Normal file
157
color-module/src/schemes/q_style_2/mod.rs
Normal file
@ -0,0 +1,157 @@
|
||||
use std::{str::FromStr, sync::Arc};
|
||||
|
||||
use linked_hash_set::LinkedHashSet;
|
||||
use palette::FromColor;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
errors, parse_option_to_oklch, parse_to_oklch,
|
||||
schemes::{q_style::SchemeSetting, q_style_2::baseline::Baseline, SchemeExport},
|
||||
};
|
||||
|
||||
mod baseline;
|
||||
mod color_set;
|
||||
mod swatch;
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct QScheme2 {
|
||||
pub light: Baseline,
|
||||
pub dark: Baseline,
|
||||
#[serde(skip)]
|
||||
_settings: Arc<SchemeSetting>,
|
||||
}
|
||||
|
||||
impl QScheme2 {
|
||||
pub fn new(
|
||||
primary: &str,
|
||||
secondary: Option<&str>,
|
||||
tertiary: Option<&str>,
|
||||
accent: Option<&str>,
|
||||
danger: &str,
|
||||
success: &str,
|
||||
warn: &str,
|
||||
info: &str,
|
||||
foreground: &str,
|
||||
background: &str,
|
||||
setting: SchemeSetting,
|
||||
) -> Result<Self, errors::ColorError> {
|
||||
let primary = parse_to_oklch!(primary);
|
||||
let secondary = parse_option_to_oklch!(secondary);
|
||||
let tertiary = parse_option_to_oklch!(tertiary);
|
||||
let accent = parse_option_to_oklch!(accent);
|
||||
|
||||
let danger = parse_to_oklch!(danger);
|
||||
let success = parse_to_oklch!(success);
|
||||
let warn = parse_to_oklch!(warn);
|
||||
let info = parse_to_oklch!(info);
|
||||
|
||||
let foreground = parse_to_oklch!(foreground);
|
||||
let background = parse_to_oklch!(background);
|
||||
|
||||
let settings = Arc::new(setting);
|
||||
|
||||
let light_scheme = Baseline::new(
|
||||
&primary,
|
||||
secondary.as_ref(),
|
||||
tertiary.as_ref(),
|
||||
accent.as_ref(),
|
||||
&danger,
|
||||
&success,
|
||||
&warn,
|
||||
&info,
|
||||
&foreground,
|
||||
&background,
|
||||
&settings,
|
||||
false,
|
||||
);
|
||||
let dark_scheme = Baseline::new(
|
||||
&(&primary * settings.dark_convert),
|
||||
secondary.map(|c| c * settings.dark_convert).as_ref(),
|
||||
tertiary.map(|c| c * settings.dark_convert).as_ref(),
|
||||
accent.map(|c| c * settings.dark_convert).as_ref(),
|
||||
&(danger * settings.dark_convert),
|
||||
&(success * settings.dark_convert),
|
||||
&(warn * settings.dark_convert),
|
||||
&(info * settings.dark_convert),
|
||||
&foreground,
|
||||
&background,
|
||||
&settings,
|
||||
true,
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
light: light_scheme,
|
||||
dark: dark_scheme,
|
||||
_settings: settings,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_custom_color(&mut self, name: &str, color: &str) -> Result<(), errors::ColorError> {
|
||||
let custom_color = parse_to_oklch!(color);
|
||||
|
||||
self.light.add_custom_color(name, &custom_color)?;
|
||||
self.dark
|
||||
.add_custom_color(name, &(custom_color * self._settings.dark_convert))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SchemeExport for QScheme2 {
|
||||
fn output_css_variables(&self) -> String {
|
||||
let mut variables = Vec::new();
|
||||
|
||||
variables.extend(self.light.to_css_variables());
|
||||
variables.extend(self.dark.to_css_variables());
|
||||
|
||||
variables.join("\n")
|
||||
}
|
||||
|
||||
fn output_css_auto_scheme_variables(&self) -> String {
|
||||
let mut collection = Vec::new();
|
||||
let mut keys = LinkedHashSet::new();
|
||||
let light_collection = self.light.to_css_auto_scheme_collection();
|
||||
let dark_collection = self.dark.to_css_auto_scheme_collection();
|
||||
|
||||
keys.extend(light_collection.keys().cloned());
|
||||
keys.extend(dark_collection.keys().cloned());
|
||||
for key in keys {
|
||||
match (light_collection.get(&key), dark_collection.get(&key)) {
|
||||
(Some(light), Some(dark)) => {
|
||||
collection.push(format!("--color-{key}: light-dark(#{light}, #{dark});"));
|
||||
}
|
||||
(Some(color), None) | (None, Some(color)) => {
|
||||
collection.push(format!("--color-{key}: #{color}"));
|
||||
}
|
||||
(None, None) => {}
|
||||
}
|
||||
}
|
||||
|
||||
collection.join("\n")
|
||||
}
|
||||
|
||||
fn output_scss_variables(&self) -> String {
|
||||
let mut variables = Vec::new();
|
||||
|
||||
variables.extend(self.light.to_scss_variables());
|
||||
variables.extend(self.dark.to_scss_variables());
|
||||
|
||||
variables.join("\n")
|
||||
}
|
||||
|
||||
fn output_javascript_object(&self) -> String {
|
||||
let mut javascript_object = Vec::new();
|
||||
|
||||
let indent = " ".repeat(4);
|
||||
javascript_object.push("{".to_string());
|
||||
for line in self.light.to_javascript_fields() {
|
||||
javascript_object.push(format!("{indent}{line}"));
|
||||
}
|
||||
for line in self.dark.to_javascript_fields() {
|
||||
javascript_object.push(format!("{indent}{line}"));
|
||||
}
|
||||
javascript_object.push("}".to_string());
|
||||
|
||||
javascript_object.join("\n")
|
||||
}
|
||||
}
|
93
color-module/src/schemes/q_style_2/swatch.rs
Normal file
93
color-module/src/schemes/q_style_2/swatch.rs
Normal file
@ -0,0 +1,93 @@
|
||||
use linked_hash_map::LinkedHashMap;
|
||||
use palette::Oklch;
|
||||
use serde::{ser::SerializeMap, Serialize};
|
||||
|
||||
use crate::convert::map_oklch_to_srgb_hex;
|
||||
|
||||
static SWATCH_LIGHTINGS: [u8; 16] = [
|
||||
10, 15, 20, 25, 30, 35, 40, 50, 60, 70, 75, 80, 85, 90, 95, 98,
|
||||
];
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Swatch(Oklch);
|
||||
|
||||
impl Swatch {
|
||||
pub fn new(color: &Oklch) -> Self {
|
||||
Self(color.clone())
|
||||
}
|
||||
|
||||
pub fn get<L: Into<f32>>(&self, lightness: L) -> Oklch {
|
||||
let request_lightness: f32 = lightness.into();
|
||||
Oklch {
|
||||
l: request_lightness.clamp(10.0, 98.0),
|
||||
..self.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_hex<L: Into<f32>>(&self, lightness: L) -> String {
|
||||
let c = self.get(lightness.into());
|
||||
map_oklch_to_srgb_hex(&c)
|
||||
}
|
||||
|
||||
pub fn to_css_variables(&self, prefix: &str, name: &str) -> Vec<String> {
|
||||
let mut variables = Vec::new();
|
||||
|
||||
for l in SWATCH_LIGHTINGS {
|
||||
variables.push(format!(
|
||||
"--color-{prefix}-swatch-{name}-{l:02}: #{};",
|
||||
self.get_hex(l)
|
||||
));
|
||||
}
|
||||
|
||||
variables
|
||||
}
|
||||
|
||||
pub fn to_css_auto_scheme_collection(&self, name: &str) -> LinkedHashMap<String, String> {
|
||||
let mut collection = LinkedHashMap::new();
|
||||
|
||||
for l in SWATCH_LIGHTINGS {
|
||||
collection.insert(format!("{name}-{l:02}"), self.get_hex(l));
|
||||
}
|
||||
|
||||
collection
|
||||
}
|
||||
|
||||
pub fn to_scss_variables(&self, prefix: &str, name: &str) -> Vec<String> {
|
||||
let mut variables = Vec::new();
|
||||
|
||||
for l in SWATCH_LIGHTINGS {
|
||||
variables.push(format!(
|
||||
"$color-{prefix}-swatch-{name}-{l:02}: #{};",
|
||||
self.get_hex(l)
|
||||
));
|
||||
}
|
||||
|
||||
variables
|
||||
}
|
||||
|
||||
pub fn to_javascript_fields(&self, name: &str) -> Vec<String> {
|
||||
let mut variables = Vec::new();
|
||||
|
||||
for l in SWATCH_LIGHTINGS {
|
||||
variables.push(format!("{name}{l:02}: '#{}',", self.get_hex(l)));
|
||||
}
|
||||
|
||||
variables
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Swatch {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut state = serializer.serialize_map(Some(SWATCH_LIGHTINGS.len()))?;
|
||||
|
||||
for l in SWATCH_LIGHTINGS {
|
||||
let color = self.get_hex(l);
|
||||
state.serialize_entry(&format!("{l:02}"), &color)?;
|
||||
}
|
||||
|
||||
state.end()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user