feat(q-2-scheme): 添加 q_scheme_select_options 方法并重构预览组件布局

This commit is contained in:
徐涛
2026-01-15 10:24:38 +08:00
parent 27f6d09ade
commit ff858ccbcd
4 changed files with 56 additions and 94 deletions

View File

@@ -3,6 +3,7 @@ import { includes, isEmpty, isNil } from 'lodash-es';
import { useActionState, useCallback, useMemo, useState } from 'react';
import { useColorFunction } from '../../../ColorFunctionContext';
import { FloatColorPicker } from '../../../components/FloatColorPicker';
import { HSegmentedControl } from '../../../components/HSegmentedControl';
import { NotificationType, useNotification } from '../../../components/Notifications';
import { ScrollArea } from '../../../components/ScrollArea';
import { VSegmentedControl } from '../../../components/VSegmentedControl';
@@ -84,6 +85,15 @@ export function Q2SchemeBuilder({ scheme, onBuildCompleted }: Q2SchemeBuilderPro
}
return [];
}, []);
const schemeStrategies = useMemo(() => {
try {
if (!colorFn) throw 'Web Assembly functions is not available';
return colorFn.q_scheme_select_options();
} catch (e) {
console.error('[Q scheme builder]', e);
}
return [];
}, []);
// Custom Colors processing
const originalColors = useMemo(() => {
@@ -127,18 +137,9 @@ export function Q2SchemeBuilder({ scheme, onBuildCompleted }: Q2SchemeBuilderPro
// collect scheme settings
const schemeSetting = new SchemeSetting(
new ColorShifting(
Number(formData.get('hover_chroma')) / 100,
Number(formData.get('hover_lightness')) / 100,
),
new ColorShifting(
Number(formData.get('active_chroma')) / 100,
Number(formData.get('active_lightness')) / 100,
),
new ColorShifting(
Number(formData.get('focus_chroma')) / 100,
Number(formData.get('focus_lightness')) / 100,
),
new ColorShifting(0, 0),
new ColorShifting(0, 0),
new ColorShifting(0, 0),
new ColorShifting(
Number(formData.get('disabled_chroma')) / 100,
Number(formData.get('disabled_lightness')) / 100,
@@ -406,63 +407,6 @@ export function Q2SchemeBuilder({ scheme, onBuildCompleted }: Q2SchemeBuilderPro
<h5 className={styles.segment_title}>Automated parameters</h5>
<label style={{ gridColumn: 2 }}>Chroma shifting</label>
<label style={{ gridColumn: 3 }}>Lightness shifting</label>
<label className={styles.label}>Hover</label>
<div className="input_wrapper">
<input
type="number"
name="hover_chroma"
defaultValue={((defaultSetting?.hover.chroma ?? 0) * 100).toFixed(2)}
className={styles.parameter_input}
/>
<span>%</span>
</div>
<div className="input_wrapper">
<input
type="number"
name="hover_lightness"
defaultValue={((defaultSetting?.hover.lightness ?? 0) * 100).toFixed(2)}
className={styles.parameter_input}
/>
<span>%</span>
</div>
<label className={styles.label}>Active</label>
<div className="input_wrapper">
<input
type="number"
name="active_chroma"
defaultValue={((defaultSetting?.active.chroma ?? 0) * 100).toFixed(2)}
className={styles.parameter_input}
/>
<span>%</span>
</div>
<div className="input_wrapper">
<input
type="number"
name="active_lightness"
defaultValue={((defaultSetting?.active.lightness ?? 0) * 100).toFixed(2)}
className={styles.parameter_input}
/>
<span>%</span>
</div>
<label className={styles.label}>Focus</label>
<div className="input_wrapper">
<input
type="number"
name="focus_chroma"
defaultValue={((defaultSetting?.focus.chroma ?? 0) * 100).toFixed(2)}
className={styles.parameter_input}
/>
<span>%</span>
</div>
<div className="input_wrapper">
<input
type="number"
name="focus_lightness"
defaultValue={((defaultSetting?.focus.lightness ?? 0) * 100).toFixed(2)}
className={styles.parameter_input}
/>
<span>%</span>
</div>
<label className={styles.label}>Disabled</label>
<div className="input_wrapper">
<input
@@ -518,6 +462,14 @@ export function Q2SchemeBuilder({ scheme, onBuildCompleted }: Q2SchemeBuilderPro
defaultValue={defaultSetting?.wacg_follows}
/>
</div>
<label className={styles.label}>Generate scheme</label>
<div style={{ gridColumn: '2 / span 2' }}>
<HSegmentedControl
options={schemeStrategies}
name="scheme_select"
defaultValue={defaultSetting?.scheme_select}
/>
</div>
<div className={styles.button_row} style={{ gridColumn: '2 / span 2' }}>
<button type="submit" className="primary">
Build Scheme

View File

@@ -24,9 +24,21 @@
.preview_unit {
width: inherit;
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-template-columns: repeat(4, 1fr);
gap: var(--spacing-xs);
}
.preview_surface {
width: inherit;
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: var(--spacing-xs);
.surface_block {
display: flex;
flex-direction: column;
gap: var(--spacing-xs);
justify-content: stretch;
}
}
.preview_indi_block {
width: inherit;
display: grid;

View File

@@ -39,23 +39,14 @@ interface PreviewLineProps {
const PreviewLine: FC<PreviewLineProps> = ({ name, unit }) => {
return (
<div className={styles.preview_unit}>
<>
<PreviewCell bg={unit.root} fg={unit.onRoot}>
{name}
</PreviewCell>
<PreviewCell bg={unit.hover} fg={unit.onRoot}>
{name} Hover
</PreviewCell>
<PreviewCell bg={unit.active} fg={unit.onRoot}>
{name} Active
</PreviewCell>
<PreviewCell bg={unit.focus} fg={unit.onRoot}>
{name} Focus
</PreviewCell>
<PreviewCell bg={unit.disabled} fg={unit.onDisabled}>
{name} Disabled
</PreviewCell>
</div>
</>
);
};
@@ -93,8 +84,10 @@ interface PreviewSetProps {
const PreviewSet: FC<PreviewSetProps> = ({ name, colorUnit }) => {
return (
<>
<PreviewLine name={name} unit={colorUnit.root} />
<PreviewLine name={`${name} Surface`} unit={colorUnit.surface} />
<div className={styles.preview_unit}>
<PreviewLine name={name} unit={colorUnit.root} />
<PreviewLine name={`${name} Surface`} unit={colorUnit.surface} />
</div>
<PreviewSwatchLine swatch={colorUnit.swatch} />
</>
);
@@ -119,8 +112,8 @@ const PreviewBlock: FC<PreviewBlockProps> = ({ baseline, title }) => {
}, [baseline.customColors]);
return (
<div className={styles.preview_block} style={{ backgroundColor: `#${baseline.surface.root}` }}>
<h2 style={{ color: `#${baseline.surface.onRoot}` }}>{title}</h2>
<div className={styles.preview_block} style={{ backgroundColor: `#${baseline.background}` }}>
<h2 style={{ color: `#${baseline.foreground}` }}>{title}</h2>
<PreviewSet name="Primary" colorUnit={baseline.primary} />
{baseline.secondary && <PreviewSet name="Secondary" colorUnit={baseline.secondary} />}
{baseline.tertiary && <PreviewSet name="Tertiary" colorUnit={baseline.tertiary} />}
@@ -129,10 +122,17 @@ const PreviewBlock: FC<PreviewBlockProps> = ({ baseline, title }) => {
<PreviewSet name="Success" colorUnit={baseline.success} />
<PreviewSet name="Warn" colorUnit={baseline.warn} />
<PreviewSet name="Info" colorUnit={baseline.info} />
<PreviewLine name="Neutral" unit={baseline.neutral} />
<PreviewLine name="Neutral Variant" unit={baseline.neutralVariant} />
<PreviewLine name="Surface" unit={baseline.surface} />
<PreviewLine name="Surface Variant" unit={baseline.surfaceVariant} />
<div className={styles.preview_unit}>
<PreviewLine name="Neutral" unit={baseline.neutral} />
<PreviewLine name="Neutral Variant" unit={baseline.neutralVariant} />
</div>
<div className={styles.preview_surface}>
{baseline.surface.map((surfaceSet, index) => (
<div className={styles.surface_block} key={index}>
<PreviewLine key={index} name={`Surface ${index + 1}`} unit={surfaceSet} />
</div>
))}
</div>
<div className={styles.preview_indi_block}>
<PreviewCell bg={baseline.shadow} fg={baseline.neutralVariant.onRoot}>
Shadow

View File

@@ -2,9 +2,6 @@ import { QSchemeSetting } from './q-scheme';
export type Q2ColorSet = {
root: string;
hover: string;
active: string;
focus: string;
disabled: string;
onRoot: string;
onDisabled: string;
@@ -23,13 +20,14 @@ export type Q2Baseline = {
accent: Q2ColorUnit | null;
neutral: Q2ColorSet;
neutralVariant: Q2ColorSet;
surface: Q2ColorSet;
surfaceVariant: Q2ColorSet;
surface: Q2ColorSet[];
neutralSwatch: Record<string, string>;
danger: Q2ColorUnit;
success: Q2ColorUnit;
warn: Q2ColorUnit;
info: Q2ColorUnit;
foreground: string;
background: string;
shadow: string;
overlay: string;
outline: string;