增加Swatch Scheme主题的生成和导出。
This commit is contained in:
parent
3ad637e1fa
commit
2d91f45809
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user