From 0a5d4756555a3d12b4ce0d5087eeea886236c0a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=B6=9B?= Date: Sun, 30 Mar 2025 22:23:49 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BAM3=20Builder=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E8=8D=89=E7=A8=BF=E7=9A=84=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scheme/m3-scheme/Builder.module.css | 6 ++ .../scheme/m3-scheme/Builder.tsx | 74 +++++++++++++------ 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/page-components/scheme/m3-scheme/Builder.module.css b/src/page-components/scheme/m3-scheme/Builder.module.css index 9de5b8d..ca2ee72 100644 --- a/src/page-components/scheme/m3-scheme/Builder.module.css +++ b/src/page-components/scheme/m3-scheme/Builder.module.css @@ -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; diff --git a/src/page-components/scheme/m3-scheme/Builder.tsx b/src/page-components/scheme/m3-scheme/Builder.tsx index 723290f..8a89b6a 100644 --- a/src/page-components/scheme/m3-scheme/Builder.tsx +++ b/src/page-components/scheme/m3-scheme/Builder.tsx @@ -2,8 +2,13 @@ import { includes, isEmpty, isNil } 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 { MaterialDesign3Scheme, MaterialDesign3SchemeStorage } from '../../../material-3-scheme'; +import { + MaterialDesign3Scheme, + MaterialDesign3SchemeSource, + MaterialDesign3SchemeStorage, +} from '../../../material-3-scheme'; import { SchemeContent } from '../../../models'; import { useUpdateScheme } from '../../../stores/schemes'; import { mapToObject } from '../../../utls'; @@ -16,6 +21,7 @@ type M3SchemeBuilderProps = { }; export function M3SchemeBuilder({ scheme, onBuildCompleted }: M3SchemeBuilderProps) { + const { showToast } = useNotification(); const { colorFn } = useColorFunction(); const updateScheme = useUpdateScheme(scheme.id); const originalColors = useMemo(() => { @@ -36,40 +42,61 @@ export function M3SchemeBuilder({ scheme, onBuildCompleted }: M3SchemeBuilderPro [originalColors, newColors, deleted], ); + const collectSchemeSource = (formData: FormData): MaterialDesign3SchemeSource => { + const sourceColor = formData.get('source') as string; + const errorColor = formData.get('error') as string; + const customColors: Record = {}; + 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, + }; + }; + + const [, handleDraftAction] = useActionState, FormData>( + (_state, formData) => { + const errMsg = new Map(); + 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(), + ); const [errMsg, handleSubmitAction] = useActionState, FormData>( (_state, formData) => { const errMsg = new Map(); try { - const sourceColor = formData.get('source') as string; - if (isNil(sourceColor) || isEmpty(sourceColor)) { + const collectedSource = collectSchemeSource(formData); + if (isNil(collectedSource.source) || isEmpty(collectedSource.source)) { errMsg.set('source', 'Source color is required'); } - const errorColor = formData.get('error') as string; - if (isNil(errorColor) || isEmpty(errorColor)) { + if (isNil(collectedSource.error) || isEmpty(collectedSource.error)) { errMsg.set('error', 'Error color is required'); } if (!isEmpty(errMsg)) return errMsg; - const customColors: Record = {}; - 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_3_scheme( - sourceColor, - errorColor, - customColors, + collectedSource.source, + collectedSource.error, + collectedSource.custom_colors, ); updateScheme((prev) => { - prev.schemeStorage.source = { - source: sourceColor as string, - error: errorColor as string, - custom_colors: customColors, - }; + prev.schemeStorage.source = collectedSource; prev.schemeStorage.scheme = { white: generatedScheme[0].white, black: generatedScheme[0].black, @@ -155,10 +182,13 @@ export function M3SchemeBuilder({ scheme, onBuildCompleted }: M3SchemeBuilderPro onDelete={(index) => setDeleted((prev) => [...prev, index])} /> ))} -
+
+