Compare commits

...

9 Commits

Author SHA1 Message Date
徐涛
8efb3ec318 将枚举换成整型值的输出。 2025-01-25 10:57:43 +08:00
徐涛
c4f703906e 增加获取Q Scheme默认配置功能。 2025-01-25 09:32:13 +08:00
徐涛
6dba92a2c5 修正SegmentControl解析Map格式的默认值。 2025-01-25 09:22:17 +08:00
徐涛
4b4428fd3b 增强SegmentControl系列组件对于Map的支持。 2025-01-25 08:56:57 +08:00
徐涛
1b41fb4d22 改进输入框包装器的样式。 2025-01-24 17:18:32 +08:00
徐涛
a3de0f961a 调整存储的Scheme内容。 2025-01-24 16:14:37 +08:00
徐涛
79794ed0f7 调整Scheme详细页面的布局。 2025-01-24 15:18:45 +08:00
徐涛
20757a789a 完善不可识别Scheme的警告页面。 2025-01-24 15:17:07 +08:00
徐涛
f9f984a1b4 重构Scheme编辑器结构。 2025-01-24 15:09:25 +08:00
29 changed files with 210 additions and 231 deletions

View File

@ -8,6 +8,7 @@ crate-type = ["cdylib"]
[dependencies] [dependencies]
color-name = "1.1.0" color-name = "1.1.0"
enum-iterator = "2.1.0"
palette = { version = "0.7.6", features = ["serde"] } palette = { version = "0.7.6", features = ["serde"] }
serde = { version = "1.0.216", features = ["derive"] } serde = { version = "1.0.216", features = ["derive"] }
serde-wasm-bindgen = "0.6.5" serde-wasm-bindgen = "0.6.5"

View File

@ -4,7 +4,6 @@ use baseline::Baseline;
use palette::FromColor; use palette::FromColor;
use scheme_setting::{ColorExpand, WACGSetting}; use scheme_setting::{ColorExpand, WACGSetting};
use serde::Serialize; use serde::Serialize;
use strum::IntoEnumIterator;
use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
use crate::{errors, parse_option_to_oklch, parse_to_oklch}; use crate::{errors, parse_option_to_oklch, parse_to_oklch};
@ -169,11 +168,11 @@ impl SchemeExport for QScheme {
#[wasm_bindgen] #[wasm_bindgen]
pub fn q_scheme_color_expanding_methods() -> Result<JsValue, String> { pub fn q_scheme_color_expanding_methods() -> Result<JsValue, String> {
let methods = ColorExpand::iter() let methods = enum_iterator::all::<ColorExpand>()
.map(|variant| { .map(|variant| {
serde_json::json!({ serde_json::json!({
"label": variant.label(), "label": variant.label(),
"value": variant.to_string(), "value": variant as u8,
}) })
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -183,14 +182,19 @@ pub fn q_scheme_color_expanding_methods() -> Result<JsValue, String> {
#[wasm_bindgen] #[wasm_bindgen]
pub fn q_scheme_wacg_settings() -> Result<JsValue, String> { pub fn q_scheme_wacg_settings() -> Result<JsValue, String> {
let settings = WACGSetting::iter() let settings = enum_iterator::all::<WACGSetting>()
.map(|setting| { .map(|setting| {
serde_json::json!({ serde_json::json!({
"label": setting.label(), "label": setting.label(),
"value": setting.to_string(), "value": setting as u8,
}) })
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
serde_wasm_bindgen::to_value(&settings).map_err(|e| e.to_string()) serde_wasm_bindgen::to_value(&settings).map_err(|e| e.to_string())
} }
#[wasm_bindgen]
pub fn q_scheme_default_settings() -> SchemeSetting {
SchemeSetting::default()
}

View File

@ -1,8 +1,9 @@
use std::ops::Mul; use std::ops::Mul;
use enum_iterator::Sequence;
use palette::Oklch; use palette::Oklch;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use strum::{Display, EnumIter, EnumString}; use strum::Display;
use wasm_bindgen::prelude::wasm_bindgen; use wasm_bindgen::prelude::wasm_bindgen;
#[derive(Debug, Clone, Copy, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, Serialize, Deserialize)]
@ -68,9 +69,9 @@ pub struct SchemeSetting {
pub wacg_follows: WACGSetting, pub wacg_follows: WACGSetting,
} }
#[derive(Debug, Clone, Copy, Display, EnumString, EnumIter, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, Display, Sequence, Serialize, Deserialize)]
#[strum(serialize_all = "lowercase")]
#[wasm_bindgen] #[wasm_bindgen]
#[repr(u8)]
pub enum ColorExpand { pub enum ColorExpand {
Complementary, Complementary,
Analogous, Analogous,
@ -95,9 +96,9 @@ impl ColorExpand {
} }
} }
#[derive(Debug, Clone, Copy, Display, EnumString, EnumIter, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, Display, Sequence, Serialize, Deserialize)]
#[strum(serialize_all = "lowercase")]
#[wasm_bindgen] #[wasm_bindgen]
#[repr(u8)]
pub enum WACGSetting { pub enum WACGSetting {
Fixed, Fixed,
AutomaticAA, AutomaticAA,

View File

@ -2,6 +2,7 @@
/* eslint-disable */ /* eslint-disable */
export function q_scheme_color_expanding_methods(): any; export function q_scheme_color_expanding_methods(): any;
export function q_scheme_wacg_settings(): any; export function q_scheme_wacg_settings(): any;
export function q_scheme_default_settings(): SchemeSetting;
export function differ_in_rgb(color: string, other: string): RGBDifference; export function differ_in_rgb(color: string, other: string): RGBDifference;
export function relative_differ_in_rgb(color: string, other: string): RGBDifference; export function relative_differ_in_rgb(color: string, other: string): RGBDifference;
export function differ_in_hsl(color: string, other: string): HSLDifference; export function differ_in_hsl(color: string, other: string): HSLDifference;
@ -143,6 +144,7 @@ export interface InitOutput {
readonly memory: WebAssembly.Memory; readonly memory: WebAssembly.Memory;
readonly q_scheme_color_expanding_methods: () => [number, number, number]; readonly q_scheme_color_expanding_methods: () => [number, number, number];
readonly q_scheme_wacg_settings: () => [number, number, number]; readonly q_scheme_wacg_settings: () => [number, number, number];
readonly q_scheme_default_settings: () => number;
readonly differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number]; readonly differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly relative_differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number]; readonly relative_differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly differ_in_hsl: (a: number, b: number, c: number, d: number) => [number, number, number]; readonly differ_in_hsl: (a: number, b: number, c: number, d: number) => [number, number, number];
@ -189,18 +191,6 @@ export interface InitOutput {
readonly __wbg_set_mixreversing_b_factor: (a: number, b: number) => void; readonly __wbg_set_mixreversing_b_factor: (a: number, b: number) => void;
readonly __wbg_get_mixreversing_average: (a: number) => number; readonly __wbg_get_mixreversing_average: (a: number) => number;
readonly __wbg_set_mixreversing_average: (a: number, b: number) => void; readonly __wbg_set_mixreversing_average: (a: number, b: number) => void;
readonly __wbg_rgbdifference_free: (a: number, b: number) => void;
readonly __wbg_get_rgbdifference_r: (a: number) => number;
readonly __wbg_set_rgbdifference_r: (a: number, b: number) => void;
readonly __wbg_get_rgbdifference_g: (a: number) => number;
readonly __wbg_set_rgbdifference_g: (a: number, b: number) => void;
readonly __wbg_get_rgbdifference_b: (a: number) => number;
readonly __wbg_set_rgbdifference_b: (a: number, b: number) => void;
readonly __wbg_swatchentry_free: (a: number, b: number) => void;
readonly __wbg_get_swatchentry_name: (a: number) => [number, number];
readonly __wbg_set_swatchentry_name: (a: number, b: number, c: number) => void;
readonly __wbg_get_swatchentry_color: (a: number) => [number, number];
readonly __wbg_set_swatchentry_color: (a: number, b: number, c: number) => void;
readonly color_categories: () => [number, number, number]; readonly color_categories: () => [number, number, number];
readonly search_color_cards: (a: number, b: number, c: number, d: number) => [number, number, number]; readonly search_color_cards: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly __wbg_colorshifting_free: (a: number, b: number) => void; readonly __wbg_colorshifting_free: (a: number, b: number) => void;
@ -228,6 +218,18 @@ export interface InitOutput {
readonly generate_q_scheme_automatically: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number) => [number, number, number]; readonly generate_q_scheme_automatically: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number) => [number, number, number];
readonly generate_q_scheme_manually: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number, r: number, s: number, t: number, u: number) => [number, number, number]; readonly generate_q_scheme_manually: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number, r: number, s: number, t: number, u: number) => [number, number, number];
readonly generate_swatch_scheme: (a: number, b: number, c: number) => [number, number, number]; readonly generate_swatch_scheme: (a: number, b: number, c: number) => [number, number, number];
readonly __wbg_hsldifference_free: (a: number, b: number) => void;
readonly __wbg_get_hsldifference_hue: (a: number) => number;
readonly __wbg_set_hsldifference_hue: (a: number, b: number) => void;
readonly __wbg_get_hsldifference_saturation: (a: number) => number;
readonly __wbg_set_hsldifference_saturation: (a: number, b: number) => void;
readonly __wbg_get_hsldifference_lightness: (a: number) => number;
readonly __wbg_set_hsldifference_lightness: (a: number, b: number) => void;
readonly __wbg_swatchentry_free: (a: number, b: number) => void;
readonly __wbg_get_swatchentry_name: (a: number) => [number, number];
readonly __wbg_set_swatchentry_name: (a: number, b: number, c: number) => void;
readonly __wbg_get_swatchentry_color: (a: number) => [number, number];
readonly __wbg_set_swatchentry_color: (a: number, b: number, c: number) => void;
readonly lighten: (a: number, b: number, c: number) => [number, number, number, number]; readonly lighten: (a: number, b: number, c: number) => [number, number, number, number];
readonly lighten_absolute: (a: number, b: number, c: number) => [number, number, number, number]; readonly lighten_absolute: (a: number, b: number, c: number) => [number, number, number, number];
readonly darken: (a: number, b: number, c: number) => [number, number, number, number]; readonly darken: (a: number, b: number, c: number) => [number, number, number, number];
@ -249,6 +251,13 @@ export interface InitOutput {
readonly represent_hct: (a: number, b: number) => [number, number, number, number]; readonly represent_hct: (a: number, b: number) => [number, number, number, number];
readonly hct_to_hex: (a: number, b: number, c: number) => [number, number, number, number]; readonly hct_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
readonly wacg_relative_contrast: (a: number, b: number, c: number, d: number) => [number, number, number]; readonly wacg_relative_contrast: (a: number, b: number, c: number, d: number) => [number, number, number];
readonly __wbg_rgbdifference_free: (a: number, b: number) => void;
readonly __wbg_get_rgbdifference_r: (a: number) => number;
readonly __wbg_set_rgbdifference_r: (a: number, b: number) => void;
readonly __wbg_get_rgbdifference_g: (a: number) => number;
readonly __wbg_set_rgbdifference_g: (a: number, b: number) => void;
readonly __wbg_get_rgbdifference_b: (a: number) => number;
readonly __wbg_set_rgbdifference_b: (a: number, b: number) => void;
readonly __wbg_swatchschemesetting_free: (a: number, b: number) => void; readonly __wbg_swatchschemesetting_free: (a: number, b: number) => void;
readonly __wbg_get_swatchschemesetting_amount: (a: number) => number; readonly __wbg_get_swatchschemesetting_amount: (a: number) => number;
readonly __wbg_set_swatchschemesetting_amount: (a: number, b: number) => void; readonly __wbg_set_swatchschemesetting_amount: (a: number, b: number) => void;
@ -260,13 +269,6 @@ export interface InitOutput {
readonly __wbg_set_swatchschemesetting_include_primary: (a: number, b: number) => void; readonly __wbg_set_swatchschemesetting_include_primary: (a: number, b: number) => void;
readonly __wbg_get_swatchschemesetting_dark_convert: (a: number) => number; readonly __wbg_get_swatchschemesetting_dark_convert: (a: number) => number;
readonly __wbg_set_swatchschemesetting_dark_convert: (a: number, b: number) => void; readonly __wbg_set_swatchschemesetting_dark_convert: (a: number, b: number) => void;
readonly __wbg_hsldifference_free: (a: number, b: number) => void;
readonly __wbg_get_hsldifference_hue: (a: number) => number;
readonly __wbg_set_hsldifference_hue: (a: number, b: number) => void;
readonly __wbg_get_hsldifference_saturation: (a: number) => number;
readonly __wbg_set_hsldifference_saturation: (a: number, b: number) => void;
readonly __wbg_get_hsldifference_lightness: (a: number) => number;
readonly __wbg_set_hsldifference_lightness: (a: number, b: number) => void;
readonly __wbindgen_malloc: (a: number, b: number) => number; readonly __wbindgen_malloc: (a: number, b: number) => number;
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
readonly __wbindgen_exn_store: (a: number) => void; readonly __wbindgen_exn_store: (a: number) => void;

View File

@ -194,6 +194,14 @@ export function q_scheme_wacg_settings() {
return takeFromExternrefTable0(ret[0]); return takeFromExternrefTable0(ret[0]);
} }
/**
* @returns {SchemeSetting}
*/
export function q_scheme_default_settings() {
const ret = wasm.q_scheme_default_settings();
return SchemeSetting.__wrap(ret);
}
/** /**
* @param {string} color * @param {string} color
* @param {string} other * @param {string} other
@ -1681,6 +1689,14 @@ const SchemeSettingFinalization = (typeof FinalizationRegistry === 'undefined')
export class SchemeSetting { export class SchemeSetting {
static __wrap(ptr) {
ptr = ptr >>> 0;
const obj = Object.create(SchemeSetting.prototype);
obj.__wbg_ptr = ptr;
SchemeSettingFinalization.register(obj, obj.__wbg_ptr, obj);
return obj;
}
__destroy_into_raw() { __destroy_into_raw() {
const ptr = this.__wbg_ptr; const ptr = this.__wbg_ptr;
this.__wbg_ptr = 0; this.__wbg_ptr = 0;

View File

@ -3,6 +3,7 @@
export const memory: WebAssembly.Memory; export const memory: WebAssembly.Memory;
export const q_scheme_color_expanding_methods: () => [number, number, number]; export const q_scheme_color_expanding_methods: () => [number, number, number];
export const q_scheme_wacg_settings: () => [number, number, number]; export const q_scheme_wacg_settings: () => [number, number, number];
export const q_scheme_default_settings: () => number;
export const differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number]; export const differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number];
export const relative_differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number]; export const relative_differ_in_rgb: (a: number, b: number, c: number, d: number) => [number, number, number];
export const differ_in_hsl: (a: number, b: number, c: number, d: number) => [number, number, number]; export const differ_in_hsl: (a: number, b: number, c: number, d: number) => [number, number, number];
@ -49,18 +50,6 @@ export const __wbg_get_mixreversing_b_factor: (a: number) => number;
export const __wbg_set_mixreversing_b_factor: (a: number, b: number) => void; export const __wbg_set_mixreversing_b_factor: (a: number, b: number) => void;
export const __wbg_get_mixreversing_average: (a: number) => number; export const __wbg_get_mixreversing_average: (a: number) => number;
export const __wbg_set_mixreversing_average: (a: number, b: number) => void; export const __wbg_set_mixreversing_average: (a: number, b: number) => void;
export const __wbg_rgbdifference_free: (a: number, b: number) => void;
export const __wbg_get_rgbdifference_r: (a: number) => number;
export const __wbg_set_rgbdifference_r: (a: number, b: number) => void;
export const __wbg_get_rgbdifference_g: (a: number) => number;
export const __wbg_set_rgbdifference_g: (a: number, b: number) => void;
export const __wbg_get_rgbdifference_b: (a: number) => number;
export const __wbg_set_rgbdifference_b: (a: number, b: number) => void;
export const __wbg_swatchentry_free: (a: number, b: number) => void;
export const __wbg_get_swatchentry_name: (a: number) => [number, number];
export const __wbg_set_swatchentry_name: (a: number, b: number, c: number) => void;
export const __wbg_get_swatchentry_color: (a: number) => [number, number];
export const __wbg_set_swatchentry_color: (a: number, b: number, c: number) => void;
export const color_categories: () => [number, number, number]; export const color_categories: () => [number, number, number];
export const search_color_cards: (a: number, b: number, c: number, d: number) => [number, number, number]; export const search_color_cards: (a: number, b: number, c: number, d: number) => [number, number, number];
export const __wbg_colorshifting_free: (a: number, b: number) => void; export const __wbg_colorshifting_free: (a: number, b: number) => void;
@ -88,6 +77,18 @@ export const generate_material_design_2_scheme: (a: number, b: number, c: number
export const generate_q_scheme_automatically: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number) => [number, number, number]; export const generate_q_scheme_automatically: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number) => [number, number, number];
export const generate_q_scheme_manually: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number, r: number, s: number, t: number, u: number) => [number, number, number]; export const generate_q_scheme_manually: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number, r: number, s: number, t: number, u: number) => [number, number, number];
export const generate_swatch_scheme: (a: number, b: number, c: number) => [number, number, number]; export const generate_swatch_scheme: (a: number, b: number, c: number) => [number, number, number];
export const __wbg_hsldifference_free: (a: number, b: number) => void;
export const __wbg_get_hsldifference_hue: (a: number) => number;
export const __wbg_set_hsldifference_hue: (a: number, b: number) => void;
export const __wbg_get_hsldifference_saturation: (a: number) => number;
export const __wbg_set_hsldifference_saturation: (a: number, b: number) => void;
export const __wbg_get_hsldifference_lightness: (a: number) => number;
export const __wbg_set_hsldifference_lightness: (a: number, b: number) => void;
export const __wbg_swatchentry_free: (a: number, b: number) => void;
export const __wbg_get_swatchentry_name: (a: number) => [number, number];
export const __wbg_set_swatchentry_name: (a: number, b: number, c: number) => void;
export const __wbg_get_swatchentry_color: (a: number) => [number, number];
export const __wbg_set_swatchentry_color: (a: number, b: number, c: number) => void;
export const lighten: (a: number, b: number, c: number) => [number, number, number, number]; export const lighten: (a: number, b: number, c: number) => [number, number, number, number];
export const lighten_absolute: (a: number, b: number, c: number) => [number, number, number, number]; export const lighten_absolute: (a: number, b: number, c: number) => [number, number, number, number];
export const darken: (a: number, b: number, c: number) => [number, number, number, number]; export const darken: (a: number, b: number, c: number) => [number, number, number, number];
@ -109,6 +110,13 @@ export const oklch_to_hex: (a: number, b: number, c: number) => [number, number,
export const represent_hct: (a: number, b: number) => [number, number, number, number]; export const represent_hct: (a: number, b: number) => [number, number, number, number];
export const hct_to_hex: (a: number, b: number, c: number) => [number, number, number, number]; export const hct_to_hex: (a: number, b: number, c: number) => [number, number, number, number];
export const wacg_relative_contrast: (a: number, b: number, c: number, d: number) => [number, number, number]; export const wacg_relative_contrast: (a: number, b: number, c: number, d: number) => [number, number, number];
export const __wbg_rgbdifference_free: (a: number, b: number) => void;
export const __wbg_get_rgbdifference_r: (a: number) => number;
export const __wbg_set_rgbdifference_r: (a: number, b: number) => void;
export const __wbg_get_rgbdifference_g: (a: number) => number;
export const __wbg_set_rgbdifference_g: (a: number, b: number) => void;
export const __wbg_get_rgbdifference_b: (a: number) => number;
export const __wbg_set_rgbdifference_b: (a: number, b: number) => void;
export const __wbg_swatchschemesetting_free: (a: number, b: number) => void; export const __wbg_swatchschemesetting_free: (a: number, b: number) => void;
export const __wbg_get_swatchschemesetting_amount: (a: number) => number; export const __wbg_get_swatchschemesetting_amount: (a: number) => number;
export const __wbg_set_swatchschemesetting_amount: (a: number, b: number) => void; export const __wbg_set_swatchschemesetting_amount: (a: number, b: number) => void;
@ -120,13 +128,6 @@ export const __wbg_get_swatchschemesetting_include_primary: (a: number) => numbe
export const __wbg_set_swatchschemesetting_include_primary: (a: number, b: number) => void; export const __wbg_set_swatchschemesetting_include_primary: (a: number, b: number) => void;
export const __wbg_get_swatchschemesetting_dark_convert: (a: number) => number; export const __wbg_get_swatchschemesetting_dark_convert: (a: number) => number;
export const __wbg_set_swatchschemesetting_dark_convert: (a: number, b: number) => void; export const __wbg_set_swatchschemesetting_dark_convert: (a: number, b: number) => void;
export const __wbg_hsldifference_free: (a: number, b: number) => void;
export const __wbg_get_hsldifference_hue: (a: number) => number;
export const __wbg_set_hsldifference_hue: (a: number, b: number) => void;
export const __wbg_get_hsldifference_saturation: (a: number) => number;
export const __wbg_set_hsldifference_saturation: (a: number, b: number) => void;
export const __wbg_get_hsldifference_lightness: (a: number) => number;
export const __wbg_set_hsldifference_lightness: (a: number, b: number) => void;
export const __wbindgen_malloc: (a: number, b: number) => number; export const __wbindgen_malloc: (a: number, b: number) => number;
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
export const __wbindgen_exn_store: (a: number) => void; export const __wbindgen_exn_store: (a: number) => void;

View File

@ -193,6 +193,7 @@
resize: none; resize: none;
} }
.input_wrapper { .input_wrapper {
width: fit-content;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;

View File

@ -3,7 +3,10 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;
gap: var(--spacing-m); gap: var(--spacing-xs);
.extended_input_wrapper {
width: 100%;
}
.rgb_input { .rgb_input {
text-align: right; text-align: right;
text-transform: uppercase; text-transform: uppercase;

View File

@ -146,7 +146,7 @@ export function ColorComponentInput({ color, onChange }: ColorComponentInputProp
return ( return (
<div className={styles.rgb_input}> <div className={styles.rgb_input}>
<div className={cx('input_wrapper')}> <div className={cx('input_wrapper', styles.extended_input_wrapper)}>
<Icon icon="tabler:hash" /> <Icon icon="tabler:hash" />
<input type="text" value={hex} onChange={updateHex} className={styles.rgb_input} /> <input type="text" value={hex} onChange={updateHex} className={styles.rgb_input} />
</div> </div>

View File

@ -1,10 +1,12 @@
import cx from 'clsx'; import cx from 'clsx';
import { isEqual, isNil } from 'lodash-es'; import { isEqual, isMap, isNil } from 'lodash-es';
import { useCallback, useRef, useState } from 'react'; import { useCallback, useRef, useState } from 'react';
import type { Option } from '../models'; import type { Option } from '../models';
import styles from './HSegmentedControl.module.css'; import styles from './HSegmentedControl.module.css';
type HSegmentedControlProps = { type HSegmentedControlProps = {
name?: string;
defaultValue?: Option['value'];
options?: Option[]; options?: Option[];
value?: Option['value']; value?: Option['value'];
onChange?: (value: Option['value']) => void; onChange?: (value: Option['value']) => void;
@ -12,12 +14,19 @@ type HSegmentedControlProps = {
}; };
export function HSegmentedControl({ export function HSegmentedControl({
name,
defaultValue,
options = [], options = [],
value, value,
onChange, onChange,
extendClassName, extendClassName,
}: HSegmentedControlProps) { }: HSegmentedControlProps) {
const [selected, setSelected] = useState(value ?? options[0].value ?? null); const [selected, setSelected] = useState(
value ??
defaultValue ??
(isMap(options[0]) ? options[0].get('value') : options[0].value) ??
null,
);
const [sliderPosition, setSliderPosition] = useState(0); const [sliderPosition, setSliderPosition] = useState(0);
const [sliderWidth, setSliderWidth] = useState(0); const [sliderWidth, setSliderWidth] = useState(0);
const sliderRef = useRef<HTMLDivElement>(null); const sliderRef = useRef<HTMLDivElement>(null);
@ -36,15 +45,19 @@ export function HSegmentedControl({
return ( return (
<div className={cx(styles.segmented_control, extendClassName)}> <div className={cx(styles.segmented_control, extendClassName)}>
<div className={styles.options}> <div className={styles.options}>
{options.map((option, index) => ( {options.map((option, index) => {
<div const label = isMap(option) ? option.get('label') : option.label;
key={`${index}_${option.value}`} const value = isMap(option) ? option.get('value') : option.value;
className={cx(styles.option, isEqual(selected, option.value) && styles.selected)} return (
ref={(el) => (optionsRef.current[index] = el!)} <div
onClick={() => handleSelectAction(option.value, index)}> key={`${index}_${value}`}
{option.label} className={cx(styles.option, isEqual(selected, value) && styles.selected)}
</div> ref={(el) => (optionsRef.current[index] = el!)}
))} onClick={() => handleSelectAction(value, index)}>
{label}
</div>
);
})}
{!isNil(selected) && ( {!isNil(selected) && (
<div <div
className={styles.slider} className={styles.slider}
@ -53,6 +66,7 @@ export function HSegmentedControl({
/> />
)} )}
</div> </div>
{!isNil(name) && <input type="hidden" name={name} value={selected} />}
</div> </div>
); );
} }

View File

@ -1,10 +1,12 @@
import cx from 'clsx'; import cx from 'clsx';
import { isEqual, isNil } from 'lodash-es'; import { isEqual, isMap, isNil } from 'lodash-es';
import { useCallback, useRef, useState } from 'react'; import { useCallback, useRef, useState } from 'react';
import type { Option } from '../models'; import type { Option } from '../models';
import styles from './VSegmentedControl.module.css'; import styles from './VSegmentedControl.module.css';
type VSegmentedControlProps = { type VSegmentedControlProps = {
name?: string;
defaultValue?: Option['value'];
options?: Option[]; options?: Option[];
value?: Option['value']; value?: Option['value'];
onChange?: (value: Option['value']) => void; onChange?: (value: Option['value']) => void;
@ -12,12 +14,19 @@ type VSegmentedControlProps = {
}; };
export function VSegmentedControl({ export function VSegmentedControl({
name,
defaultValue,
options = [], options = [],
value, value,
onChange, onChange,
extendClassName, extendClassName,
}: VSegmentedControlProps) { }: VSegmentedControlProps) {
const [selected, setSelected] = useState(value ?? options[0].value ?? null); const [selected, setSelected] = useState(
value ??
defaultValue ??
(isMap(options[0]) ? options[0].get('value') : options[0].value) ??
null,
);
const [sliderPosition, setSliderPosition] = useState(0); const [sliderPosition, setSliderPosition] = useState(0);
const [sliderHeight, setSliderHeight] = useState(0); const [sliderHeight, setSliderHeight] = useState(0);
const sliderRef = useRef<HTMLDivElement>(null); const sliderRef = useRef<HTMLDivElement>(null);
@ -36,15 +45,19 @@ export function VSegmentedControl({
return ( return (
<div className={cx(styles.segmented_control, extendClassName)}> <div className={cx(styles.segmented_control, extendClassName)}>
<div className={styles.options}> <div className={styles.options}>
{options.map((option, index) => ( {options.map((option, index) => {
<div const label = isMap(option) ? option.get('label') : option.label;
key={`${index}_${option.value}`} const value = isMap(option) ? option.get('value') : option.value;
className={cx(styles.option, isEqual(selected, option.value) && styles.selected)} return (
ref={(el) => (optionsRef.current[index] = el!)} <div
onClick={() => handleSelectAction(option.value, index)}> key={`${index}_${value}`}
{option.label} className={cx(styles.option, isEqual(selected, value) && styles.selected)}
</div> ref={(el) => (optionsRef.current[index] = el!)}
))} onClick={() => handleSelectAction(value, index)}>
{label}
</div>
);
})}
{!isNil(selected) && ( {!isNil(selected) && (
<div <div
className={styles.slider} className={styles.slider}
@ -53,6 +66,7 @@ export function VSegmentedControl({
/> />
)} )}
</div> </div>
{!isNil(name) && <input type="hidden" name={name} value={selected} />}
</div> </div>
); );
} }

View File

@ -22,13 +22,13 @@ export type MaterialDesign2Scheme = {
}; };
export type MaterialDesign2SchemeSource = { export type MaterialDesign2SchemeSource = {
primary: string; primary: string | null;
secondary: string; secondary: string | null;
error: string; error: string | null;
custom_colors: Record<string, string>; custom_colors?: Record<string, string>;
}; };
export type MaterialDesign2SchemeStorage = { export type MaterialDesign2SchemeStorage = {
source: MaterialDesign2SchemeSource; source?: MaterialDesign2SchemeSource;
scheme: MaterialDesign2Scheme; scheme?: MaterialDesign2Scheme;
}; };

View File

@ -46,12 +46,12 @@ export type MaterialDesign3Scheme = {
}; };
export type MaterialDesign3SchemeSource = { export type MaterialDesign3SchemeSource = {
source: string; source: string | null;
error: string; error: string | null;
custom_colors: Record<string, string>; custom_colors?: Record<string, string>;
}; };
export type MaterialDesign3SchemeStorage = { export type MaterialDesign3SchemeStorage = {
source: MaterialDesign3SchemeSource; source?: MaterialDesign3SchemeSource;
scheme: MaterialDesign3Scheme; scheme?: MaterialDesign3Scheme;
}; };

View File

@ -4,10 +4,12 @@ import { MaterialDesign3SchemeStorage } from './material-3-scheme';
import { QSchemeStorage } from './q-scheme'; import { QSchemeStorage } from './q-scheme';
import { SwatchSchemeStorage } from './swatch_scheme'; import { SwatchSchemeStorage } from './swatch_scheme';
export type Option = { export type Option =
label: string; | {
value: string | number | null; label: string;
}; value: string | number | null;
}
| Record<'label' | 'value', string | number | null>;
export type HarmonyColor = { export type HarmonyColor = {
color: string; color: string;
@ -47,7 +49,7 @@ export function schemeType(
const useShort = short ?? false; const useShort = short ?? false;
const foundType = find(SchemeTypeOptions, { value }) as SchemeTypeOption | undefined; const foundType = find(SchemeTypeOptions, { value }) as SchemeTypeOption | undefined;
if (isNil(foundType)) { if (isNil(foundType)) {
return null; return 'CORRUPTED';
} }
return useShort ? foundType.short : foundType.label; return useShort ? foundType.short : foundType.label;
} }

View File

@ -0,0 +1,6 @@
@layer pages {
.corrupted {
font-size: var(--font-size-xl);
color: var(--color-danger);
}
}

View File

@ -0,0 +1,8 @@
import styles from './CorruptedScheme.module.css';
export function CorruptedScheme() {
return (
<div className="center">
<div className={styles.corrupted}>Unrecognizable or corrupted scheme</div>
</div>
);
}

View File

@ -0,0 +1,3 @@
export function M2Scheme() {
return <div>Material Design 2 Scheme</div>;
}

View File

@ -0,0 +1,3 @@
export function M3Scheme() {
return <div>Material Design 3 Scheme</div>;
}

View File

@ -0,0 +1,3 @@
export function QScheme() {
return <div>Q Scheme</div>;
}

View File

@ -1,25 +0,0 @@
@layer pages {
.scheme_content {
flex: 1;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: var(--spacing-m);
}
.series_row {
display: flex;
flex-direction: column;
gap: var(--spacing-s);
h4 {
padding-block: var(--spacing-xs);
font-size: var(--font-size-l);
}
ul {
display: flex;
flex-direction: row;
justify-content: flex-start;
flex-wrap: wrap;
gap: var(--spacing-l);
}
}
}

View File

@ -1,61 +0,0 @@
import { isArray } from 'lodash-es';
import { ColorStand } from '../../components/ColorStand';
import { SchemeSet } from '../../stores/schemes';
import styles from './SchemeContent.module.css';
type ColorSeriesProps = {
title: string;
series: SchemeSet['lightScheme' | 'darkScheme']['primary'];
simpleSeries?: boolean;
};
function ColorSeries({ title, series, simpleSeries = false }: ColorSeriesProps) {
return (
<div className={styles.series_row}>
<h4>{title}</h4>
<ul>
<ColorStand title="Normal" color={series?.normal} />
{simpleSeries ? (
<>
<ColorStand title="Lightness" color={series?.lighten} />
<ColorStand title="Darkness" color={series?.darken} />
</>
) : (
<>
<ColorStand title="Hover" color={series?.hover} />
<ColorStand title="Active" color={series?.active} />
<ColorStand title="Focus" color={series?.focus} />
<ColorStand title="Disabled" color={series?.disabled} />
</>
)}
</ul>
</div>
);
}
type SchemeContentProps = {
scheme: SchemeSet['lightScheme' | 'darkScheme'];
};
export function SchemeContent({ scheme }: SchemeContentProps) {
return (
<div className={styles.scheme_content}>
<ColorSeries title="Foreground Series" series={scheme.foreground} simpleSeries />
<ColorSeries title="Background Series" series={scheme.background} simpleSeries />
<ColorSeries title="Primary Series" series={scheme.primary} />
{isArray(scheme.secondary) ? (
scheme.secondary.map((cSet, index) => (
<ColorSeries title={`Secondary Series ${index + 1}`} series={cSet} />
))
) : (
<ColorSeries title="Secondary Series" series={scheme.secondary} />
)}
<ColorSeries title="Accent Series" series={scheme.accent} />
<ColorSeries title="Neutral Serias" series={scheme.neutral} />
<ColorSeries title="Success Series" series={scheme.success} />
<ColorSeries title="Danger Series" series={scheme.danger} />
<ColorSeries title="Warn Series" series={scheme.warning} />
<ColorSeries title="Info Series" series={scheme.info} />
</div>
);
}

View File

@ -1,17 +0,0 @@
@layer pages {
.scheme_view_layout {
flex: 1 0;
width: 100%;
padding: calc(var(--spacing) * 4) calc(var(--spacing) * 8);
display: flex;
flex-direction: column;
gap: var(--spacing-m);
overflow: hidden;
}
.preview_switch_container {
display: flex;
flex-direction: row;
align-items: center;
gap: var(--spacing-m);
}
}

View File

@ -1,23 +0,0 @@
import { useState } from 'react';
import { Switch } from '../../components/Switch';
import { SchemeSet } from '../../stores/schemes';
import { SchemeContent } from './SchemeContent';
import styles from './SchemeView.module.css';
type SchemeViewProps = {
scheme: SchemeSet['lightScheme' | 'darkScheme'];
};
export function SchemeView({ scheme }: SchemeViewProps) {
const [enablePreview, setEnablePreview] = useState(false);
return (
<div className={styles.scheme_view_layout}>
<div className={styles.preview_switch_container}>
<span>Preview scheme</span>
<Switch onChange={(checked) => setEnablePreview(checked)} />
</div>
{enablePreview ? <div>SVG Preview</div> : <SchemeContent scheme={scheme} />}
</div>
);
}

View File

@ -0,0 +1,3 @@
export function SwatchScheme() {
return <div>Swatch Scheme</div>;
}

View File

@ -5,7 +5,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;
gap: var(--spacing-m); gap: var(--spacing-xs);
overflow: hidden; overflow: hidden;
.badge_layout { .badge_layout {
padding: var(--spacing-xs) var(--spacing-m); padding: var(--spacing-xs) var(--spacing-m);

View File

@ -1,10 +1,15 @@
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { isNil, set } from 'lodash-es'; import { isNil, set } from 'lodash-es';
import { useCallback, useEffect } from 'react'; import { useCallback, useEffect, useMemo } from 'react';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { EditableDescription } from '../components/EditableDescription'; import { EditableDescription } from '../components/EditableDescription';
import { EditableTitle } from '../components/EditableTitle'; import { EditableTitle } from '../components/EditableTitle';
import { SchemeSign } from '../components/SchemeSign'; import { SchemeSign } from '../components/SchemeSign';
import { CorruptedScheme } from '../page-components/scheme/CorruptedScheme';
import { M2Scheme } from '../page-components/scheme/M2Scheme';
import { M3Scheme } from '../page-components/scheme/M3Scheme';
import { QScheme } from '../page-components/scheme/QScheme';
import { SwatchScheme } from '../page-components/scheme/SwatchScheme';
import { useScheme, useUpdateScheme } from '../stores/schemes'; import { useScheme, useUpdateScheme } from '../stores/schemes';
import styles from './SchemeDetail.module.css'; import styles from './SchemeDetail.module.css';
@ -32,6 +37,20 @@ export function SchemeDetail() {
}, },
[id], [id],
); );
const schemeContent = useMemo(() => {
switch (scheme?.type) {
case 'q_scheme':
return <QScheme />;
case 'swatch_scheme':
return <SwatchScheme />;
case 'material_2':
return <M2Scheme />;
case 'material_3':
return <M3Scheme />;
default:
return <CorruptedScheme />;
}
}, [scheme]);
useEffect(() => { useEffect(() => {
if (isNil(scheme)) { if (isNil(scheme)) {
@ -49,6 +68,7 @@ export function SchemeDetail() {
</div> </div>
</div> </div>
<EditableDescription content={scheme?.description} onChange={updateDescription} /> <EditableDescription content={scheme?.description} onChange={updateDescription} />
{schemeContent}
</div> </div>
); );
} }

View File

@ -29,8 +29,8 @@ export type Baseline = {
}; };
export type QScheme = { export type QScheme = {
light: Baseline; light: Baseline | null;
dark: Baseline; dark: Baseline | null;
}; };
export type QSchemeSetting = { export type QSchemeSetting = {
@ -44,20 +44,20 @@ export type QSchemeSetting = {
}; };
export type QSchemeSource = { export type QSchemeSource = {
primary: string; primary: string | null;
secondary: string | null; secondary: string | null;
tertiary: string | null; tertiary: string | null;
accent: string | null; accent: string | null;
danger: string; danger: string | null;
success: string; success: string | null;
warning: string; warning: string | null;
info: string; info: string | null;
foreground: string; foreground: string | null;
background: string; background: strin | nullg;
setting: QSchemeSetting; setting: QSchemeSetting | null;
}; };
export type QSchemeStorage = { export type QSchemeStorage = {
source: QSchemeSource; source?: QSchemeSource;
scheme: QScheme; scheme?: QScheme;
}; };

View File

@ -7,10 +7,10 @@ export type SwatchScheme = {
export type SwatchSchemeSource = { export type SwatchSchemeSource = {
colors: SwatchEntry[]; colors: SwatchEntry[];
setting: SwatchSchemeSetting; setting: SwatchSchemeSetting | null;
}; };
export type SwatchSchemeStorage = { export type SwatchSchemeStorage = {
source: SwatchSchemeSource; source?: SwatchSchemeSource;
scheme: SwatchScheme; scheme?: SwatchScheme;
}; };