为M3D Builder增加保存草稿的功能。

This commit is contained in:
徐涛 2025-03-30 22:01:01 +08:00
parent ef3ef2b349
commit 5f3d58f0f5
2 changed files with 64 additions and 27 deletions

View File

@ -29,6 +29,12 @@
align-items: center; align-items: center;
gap: var(--spacing-s); gap: var(--spacing-s);
} }
.button_row {
display: flex;
flex-direction: row;
align-items: center;
gap: var(--spacing-s);
}
h5 { h5 {
font-size: var(--font-size-m); font-size: var(--font-size-m);
line-height: 1.7em; line-height: 1.7em;

View File

@ -2,10 +2,14 @@ import { includes, isEmpty, isEqual, isNil } from 'lodash-es';
import { useActionState, useCallback, useMemo, useState } from 'react'; import { useActionState, useCallback, useMemo, useState } from 'react';
import { useColorFunction } from '../../../ColorFunctionContext'; import { useColorFunction } from '../../../ColorFunctionContext';
import { FloatColorPicker } from '../../../components/FloatColorPicker'; import { FloatColorPicker } from '../../../components/FloatColorPicker';
import { NotificationType, useNotification } from '../../../components/Notifications';
import { ScrollArea } from '../../../components/ScrollArea'; import { ScrollArea } from '../../../components/ScrollArea';
import { Switch } from '../../../components/Switch'; import { Switch } from '../../../components/Switch';
import { VSegmentedControl } from '../../../components/VSegmentedControl'; import { VSegmentedControl } from '../../../components/VSegmentedControl';
import { MaterialDesign3DynamicSchemeStorage } from '../../../material-3-scheme'; import {
MaterialDesign3DynamicSchemeSource,
MaterialDesign3DynamicSchemeStorage,
} from '../../../material-3-scheme';
import { Option, SchemeContent } from '../../../models'; import { Option, SchemeContent } from '../../../models';
import { useUpdateScheme } from '../../../stores/schemes'; import { useUpdateScheme } from '../../../stores/schemes';
import { mapToObject } from '../../../utls'; import { mapToObject } from '../../../utls';
@ -18,6 +22,7 @@ type M3DynamicSchemeBuilderProps = {
}; };
export function M3DynamicSchemeBuilder({ scheme, onBuildCompleted }: M3DynamicSchemeBuilderProps) { export function M3DynamicSchemeBuilder({ scheme, onBuildCompleted }: M3DynamicSchemeBuilderProps) {
const { showToast } = useNotification();
const { colorFn } = useColorFunction(); const { colorFn } = useColorFunction();
const updateScheme = useUpdateScheme(scheme.id); const updateScheme = useUpdateScheme(scheme.id);
const originalColors = useMemo(() => { const originalColors = useMemo(() => {
@ -49,7 +54,47 @@ export function M3DynamicSchemeBuilder({ scheme, onBuildCompleted }: M3DynamicSc
const [contrastLevel, setContrastLevel] = useState<number>( const [contrastLevel, setContrastLevel] = useState<number>(
() => scheme.schemeStorage.source?.contrastLevel ?? 1, () => scheme.schemeStorage.source?.contrastLevel ?? 1,
); );
const collectSchemeSource = (formData: FormData): MaterialDesign3DynamicSchemeSource => {
const sourceColor = formData.get('source') as string;
const dynamicVariant = Number(formData.get('variant'));
const contrast = Number(formData.get('contrast_level'));
const harmonizeCustoms = isEqual(formData.get('harmonize_customs'), 'true');
const errorColor = formData.get('error') as string;
const customColors: Record<string, string> = {};
for (const key of colorKeys) {
const name = formData.get(`name_${key}`) as string;
const color = formData.get(`color_${key}`) as string;
if (isNil(name) || isEmpty(name) || isNil(color) || isEmpty(color)) continue;
customColors[name] = color;
}
return {
source: isNil(sourceColor) || isEmpty(sourceColor) ? null : sourceColor,
error: isNil(errorColor) || isEmpty(errorColor) ? null : errorColor,
custom_colors: customColors,
variant: dynamicVariant,
contrastLevel: contrast,
harmonizeCustoms: harmonizeCustoms,
};
};
const [, handleDraftAction] = useActionState<Map<string, string>, FormData>(
(_state, formData) => {
const errMsg = new Map<string, string>();
const collectedSource = collectSchemeSource(formData);
updateScheme((prev) => {
prev.schemeStorage.source = collectedSource;
return prev;
});
showToast(NotificationType.SUCCESS, 'Scheme draft saved!', 'tabler:device-floppy', 3000);
return errMsg;
},
new Map<string, string>(),
);
const [errMsg, handleSubmitAction] = useActionState<Map<string, string>, FormData>( const [errMsg, handleSubmitAction] = useActionState<Map<string, string>, FormData>(
(_state, formData) => { (_state, formData) => {
const errMsg = new Map<string, string>(); const errMsg = new Map<string, string>();
@ -61,35 +106,18 @@ export function M3DynamicSchemeBuilder({ scheme, onBuildCompleted }: M3DynamicSc
if (!isEmpty(errMsg)) return errMsg; if (!isEmpty(errMsg)) return errMsg;
try { try {
const dynamicVariant = Number(formData.get('variant')); const collectedSource = collectSchemeSource(formData);
const contrast = Number(formData.get('contrast_level'));
const harmonizeCustoms = isEqual(formData.get('harmonize_customs'), 'true');
const errorColor = formData.get('error') as string;
const customColors: Record<string, string> = {};
for (const key of colorKeys) {
const name = formData.get(`name_${key}`) as string;
const color = formData.get(`color_${key}`) as string;
if (isNil(name) || isEmpty(name) || isNil(color) || isEmpty(color)) continue;
customColors[name] = color;
}
const generate_scheme = colorFn.generate_material_design_3_dynamic_scheme( const generate_scheme = colorFn.generate_material_design_3_dynamic_scheme(
sourceColor, collectedSource.source,
isNil(errorColor) || isEmpty(errorColor) ? null : errorColor, collectedSource.error,
dynamicVariant, collectedSource.variant,
contrastLevel, collectedSource.contrastLevel,
harmonizeCustoms, collectedSource.harmonizeCustoms,
customColors, collectedSource.custom_colors,
); );
updateScheme((prev) => { updateScheme((prev) => {
prev.schemeStorage.source = { prev.schemeStorage.source = collectedSource;
source: sourceColor,
error: errorColor,
custom_colors: customColors,
variant: dynamicVariant,
contrastLevel: contrast,
harmonizeCustoms: harmonizeCustoms,
};
prev.schemeStorage.scheme = { prev.schemeStorage.scheme = {
white: generate_scheme[0].white, white: generate_scheme[0].white,
black: generate_scheme[0].black, black: generate_scheme[0].black,
@ -204,10 +232,13 @@ export function M3DynamicSchemeBuilder({ scheme, onBuildCompleted }: M3DynamicSc
onDelete={(index) => setDeleted((prev) => [...prev, index])} onDelete={(index) => setDeleted((prev) => [...prev, index])}
/> />
))} ))}
<div style={{ gridColumn: '2 / span 2' }}> <div className={styles.button_row} style={{ gridColumn: '2 / span 2' }}>
<button type="submit" className="primary"> <button type="submit" className="primary">
Build Scheme Build Scheme
</button> </button>
<button type="submit" className="secondary" formAction={handleDraftAction}>
Save Draft
</button>
</div> </div>
</form> </form>
</ScrollArea> </ScrollArea>