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

This commit is contained in:
徐涛 2025-03-30 22:32:57 +08:00
parent 0a5d475655
commit 00d1e425c0
2 changed files with 61 additions and 25 deletions

View File

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

View File

@ -2,8 +2,12 @@ import { includes, isEmpty, isNil, merge } from 'lodash-es';
import { useActionState, useCallback, useMemo, useState } from 'react';
import { useColorFunction } from '../../../ColorFunctionContext';
import { FloatColorPicker } from '../../../components/FloatColorPicker';
import { NotificationType, useNotification } from '../../../components/Notifications';
import { ScrollArea } from '../../../components/ScrollArea';
import { MaterialDesign2SchemeStorage } from '../../../material-2-scheme';
import {
MaterialDesign2SchemeSource,
MaterialDesign2SchemeStorage,
} from '../../../material-2-scheme';
import { SchemeContent } from '../../../models';
import { useUpdateScheme } from '../../../stores/schemes';
import { mapToObject } from '../../../utls';
@ -16,6 +20,7 @@ type M2SchemeBuilderProps = {
};
export function M2SchemeBuilder({ scheme, onBuildComplete }: M2SchemeBuilderProps) {
const { showToast } = useNotification();
const { colorFn } = useColorFunction();
const updateScheme = useUpdateScheme(scheme.id);
const originalColors = useMemo(() => {
@ -35,45 +40,67 @@ export function M2SchemeBuilder({ scheme, onBuildComplete }: M2SchemeBuilderProp
.filter((c) => !includes(deleted, c)),
[originalColors, newColors, deleted],
);
const colectSchemeSource = (formData: FormData): MaterialDesign2SchemeSource => {
const primaryColor = formData.get('primary') as string;
const secondaryColor = formData.get('secondary') as string;
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 {
primary: isNil(primaryColor) || isEmpty(primaryColor) ? null : primaryColor,
secondary: isNil(secondaryColor) || isEmpty(secondaryColor) ? null : secondaryColor,
error: isNil(errorColor) || isEmpty(errorColor) ? null : errorColor,
custom_colors: customColors,
};
};
const [, handleDraftAction] = useActionState<Map<string, string>, FormData>(
(_state, formData) => {
const errMsg = new Map<string, string>();
const collectedSource = colectSchemeSource(formData);
updateScheme((prev) => {
prev.schemeStorage.source = collectedSource;
return prev;
});
setNewColors([]);
showToast(NotificationType.SUCCESS, 'Scheme draft saved!', 'tabler:device-floppy', 3000);
return errMsg;
},
new Map<string, string>(),
);
const [errMsg, handleSubmitAction] = useActionState<Map<string, string>, FormData>(
(_state, formData) => {
const errMsg = new Map<string, string>();
try {
const primaryColor = formData.get('primary') as string;
if (isNil(primaryColor) || isEmpty(primaryColor)) {
const collected = colectSchemeSource(formData);
if (isNil(collected.primary) || isEmpty(collected.primary)) {
errMsg.set('primary', 'Primary color is required');
}
const secondaryColor = formData.get('secondary') as string;
if (isNil(secondaryColor) || isEmpty(secondaryColor)) {
if (isNil(collected.secondary) || isEmpty(collected.secondary)) {
errMsg.set('secondary', 'Secondary color is required');
}
const errorColor = formData.get('error') as string;
if (isNil(errorColor) || isEmpty(errorColor)) {
if (isNil(collected.error) || isEmpty(collected.error)) {
errMsg.set('error', 'Error color is required');
}
if (!isEmpty(errMsg)) return errMsg;
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 generatedScheme = colorFn?.generate_material_design_2_scheme(
primaryColor,
secondaryColor,
errorColor,
customColors,
collected.primary,
collected.secondary,
collected.error,
collected.custom_colors,
);
updateScheme((prev) => {
prev.schemeStorage.source = {
primary: primaryColor,
secondary: secondaryColor,
error: errorColor,
custom_colors: customColors,
};
prev.schemeStorage.source = collected;
prev.schemeStorage.scheme = merge(generatedScheme[0], {
light: { custom_colors: mapToObject(generatedScheme[0].light.custom_colors) },
dark: { custom_colors: mapToObject(generatedScheme[0].dark.custom_colors) },
@ -168,10 +195,13 @@ export function M2SchemeBuilder({ scheme, onBuildComplete }: M2SchemeBuilderProp
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">
Build Scheme
</button>
<button type="submit" className="secondary" formAction={handleDraftAction}>
Save Draft
</button>
</div>
</form>
</ScrollArea>