From fb90d79eb340b58298185abcf293696ded9e6412 Mon Sep 17 00:00:00 2001 From: jialin Date: Wed, 23 Apr 2025 09:59:41 +0800 Subject: [PATCH] chore: custom brand color --- src/atoms/settings.ts | 6 +- src/components/seal-form/wrapper/index.tsx | 18 +- src/config/theme/dark.ts | 2 +- src/config/theme/index.ts | 4 +- src/global.less | 16 +- src/hooks/use-tab-active.ts | 3 +- src/hooks/use-user-settings.ts | 10 +- src/layouts/index.tsx | 12 ++ src/pages/profile/backup.tsx | 135 ++++++++++++++ src/pages/profile/components/custom-ui.tsx | 30 +++ .../profile/components/modify-password.tsx | 125 +++++++++++++ src/pages/profile/index.tsx | 176 ++++++------------ 12 files changed, 398 insertions(+), 139 deletions(-) create mode 100644 src/pages/profile/backup.tsx create mode 100644 src/pages/profile/components/custom-ui.tsx create mode 100644 src/pages/profile/components/modify-password.tsx diff --git a/src/atoms/settings.ts b/src/atoms/settings.ts index ae3f610d..3ed68009 100644 --- a/src/atoms/settings.ts +++ b/src/atoms/settings.ts @@ -1,14 +1,17 @@ +import { colorPrimary } from '@/config/theme'; import { atom } from 'jotai'; import { atomWithStorage } from 'jotai/utils'; type UserSettings = { theme: 'light' | 'realDark' | 'auto'; + colorPrimary: string; isDarkTheme?: boolean; }; export const userSettingsAtom = atomWithStorage('userSettings', { theme: 'light', - isDarkTheme: false + isDarkTheme: false, + colorPrimary: colorPrimary }); export const userSettingsHelperAtom = atom( @@ -21,6 +24,7 @@ export const userSettingsHelperAtom = atom( }; set(userSettingsAtom, { ...newSettings, + colorPrimary: newSettings.colorPrimary || colorPrimary, isDarkTheme: newSettings.theme === 'realDark' }); } diff --git a/src/components/seal-form/wrapper/index.tsx b/src/components/seal-form/wrapper/index.tsx index be2a2b9d..d746d027 100644 --- a/src/components/seal-form/wrapper/index.tsx +++ b/src/components/seal-form/wrapper/index.tsx @@ -1,3 +1,4 @@ +import { theme } from 'antd'; import classNames from 'classnames'; import React, { FC } from 'react'; import styled from 'styled-components'; @@ -191,6 +192,8 @@ const Wrapper: FC = ({ labelExtra, onClick }) => { + const { token } = theme.useToken(); + console.log('token=====', token); const wrapperClass = classNames( status ? `validate-status-${status}` : '', className, @@ -201,8 +204,21 @@ const Wrapper: FC = ({ 'seal-input-wrapper-disabled': disabled } ); + const wrapperStyle: Record = { + '--ant-line-width': '1px', + '--ant-line-type': 'solid', + '--ant-color-border': token.colorBorder, + '--ant-color-bg-container': token.colorBgContainer, + '--ant-color-bg-container-disabled': token.colorBgContainerDisabled, + '--ant-color-error': token.colorError, + '--ant-input-hover-border-color': token.colorPrimaryHover, + '--ant-color-error-border-hover': token.colorErrorBorderHover, + '--ant-input-active-border-color': token.colorPrimary, + '--ant-input-active-shadow': `0 0 0 2px ${token.controlOutline}`, + '--ant-input-active-bg': token.colorBgContainer + }; return ( - + { @@ -17,15 +17,16 @@ export default function useUserSettings() { }; const themeData = useMemo(() => { + const themeTokens = userSettings.theme === 'realDark' ? dark : light; + themeTokens.token.colorPrimary = userSettings.colorPrimary || colorPrimary; return { - ...(userSettings.theme === 'realDark' ? dark : light) + ...themeTokens }; - }, [userSettings.theme]); + }, [userSettings.theme, userSettings.colorPrimary]); const setTheme = (theme: Theme) => { setHtmlThemeAttr(theme); setUserSettings({ - ...userSettings, theme: theme, isDarkTheme: theme === 'realDark' }); @@ -35,7 +36,6 @@ export default function useUserSettings() { setHtmlThemeAttr(userSettings.theme); }, [userSettings.theme]); - // set theme by system theme: only for theme is auto useEffect(() => { const handleChange = (e: MediaQueryListEvent) => { setTheme(e.matches ? 'realDark' : 'light'); diff --git a/src/layouts/index.tsx b/src/layouts/index.tsx index 321fca01..834aa843 100644 --- a/src/layouts/index.tsx +++ b/src/layouts/index.tsx @@ -407,9 +407,21 @@ export default (props: any) => { ); }; + const currentTheme = useMemo(() => { + const data = { + algorithm: userSettings.isDarkTheme + ? theme.darkAlgorithm + : theme.defaultAlgorithm, + ...themeData + }; + console.log('currentTheme====', data); + return data; + }, [userSettings.isDarkTheme, themeData]); + return ( { + const [form] = Form.useForm(); + const intl = useIntl(); + + const handleOnFinish = async (values: any) => { + try { + await updatePassword({ + new_password: values.new_password, + current_password: values.current_password + }); + message.success(intl.formatMessage({ id: 'common.message.success' })); + } catch (error) {} + }; + + const handleOnFinishFailed = (errorInfo: any) => { + console.log('handleOnFinishFailed', errorInfo); + }; + const handleCancel = () => { + form.resetFields(); + }; + + return ( + +
+ + name="current_password" + rules={[ + { + required: true, + message: intl.formatMessage( + { id: 'common.form.rule.input' }, + { + name: intl.formatMessage({ + id: 'users.form.currentpassword' + }) + } + ) + } + ]} + > + + + + name="new_password" + rules={[ + { + required: true, + pattern: PasswordReg, + message: intl.formatMessage({ + id: 'users.form.rule.password' + }) + } + ]} + > + + + ({ + validator(_, value) { + if (!value || getFieldValue('new_password') === value) { + return Promise.resolve(); + } + return Promise.reject( + new Error( + intl.formatMessage({ id: 'users.password.confirm.error' }) + ) + ); + } + }) + ]} + > + + + + +
+ ); +}; + +export default Profile; diff --git a/src/pages/profile/components/custom-ui.tsx b/src/pages/profile/components/custom-ui.tsx new file mode 100644 index 00000000..4353034b --- /dev/null +++ b/src/pages/profile/components/custom-ui.tsx @@ -0,0 +1,30 @@ +import useUserSettings from '@/hooks/use-user-settings'; +import { Button, ColorPicker } from 'antd'; +import React from 'react'; + +const CustomUI: React.FC = () => { + const { setUserSettings, userSettings } = useUserSettings(); + + const handleOnChange = (color: any, css: string) => { + const colorPrimary = color.toHexString(); + if (!colorPrimary) return; + setUserSettings({ + ...userSettings, + colorPrimary: color.toHexString() + }); + }; + + return ( +
+

Custom UI Component

+ +
+ +
+
+ ); +}; + +CustomUI.displayName = 'CustomUI'; + +export default CustomUI; diff --git a/src/pages/profile/components/modify-password.tsx b/src/pages/profile/components/modify-password.tsx new file mode 100644 index 00000000..14547f41 --- /dev/null +++ b/src/pages/profile/components/modify-password.tsx @@ -0,0 +1,125 @@ +import FormButtons from '@/components/form-buttons'; +import SealInput from '@/components/seal-form/seal-input'; +import { PasswordReg } from '@/config'; +import { INPUT_WIDTH } from '@/constants'; +import { updatePassword } from '@/pages/login/apis'; +import { useIntl } from '@umijs/max'; +import { Form, message } from 'antd'; +import React from 'react'; + +interface ProfileProps { + username?: string; + new_password: string; + current_password: string; +} +const Profile: React.FC = () => { + const [form] = Form.useForm(); + const intl = useIntl(); + + const handleOnFinish = async (values: any) => { + try { + await updatePassword({ + new_password: values.new_password, + current_password: values.current_password + }); + message.success(intl.formatMessage({ id: 'common.message.success' })); + } catch (error) {} + }; + + const handleOnFinishFailed = (errorInfo: any) => { + console.log('handleOnFinishFailed', errorInfo); + }; + const handleCancel = () => { + form.resetFields(); + }; + + return ( +
+ + name="current_password" + rules={[ + { + required: true, + message: intl.formatMessage( + { id: 'common.form.rule.input' }, + { + name: intl.formatMessage({ + id: 'users.form.currentpassword' + }) + } + ) + } + ]} + > + + + + name="new_password" + rules={[ + { + required: true, + pattern: PasswordReg, + message: intl.formatMessage({ + id: 'users.form.rule.password' + }) + } + ]} + > + + + ({ + validator(_, value) { + if (!value || getFieldValue('new_password') === value) { + return Promise.resolve(); + } + return Promise.reject( + new Error( + intl.formatMessage({ id: 'users.password.confirm.error' }) + ) + ); + } + }) + ]} + > + + + + + ); +}; + +Profile.displayName = 'ModifyPassword'; + +export default Profile; diff --git a/src/pages/profile/index.tsx b/src/pages/profile/index.tsx index bfaecfc7..9ea62633 100644 --- a/src/pages/profile/index.tsx +++ b/src/pages/profile/index.tsx @@ -1,134 +1,68 @@ -import FormButtons from '@/components/form-buttons'; -import SealInput from '@/components/seal-form/seal-input'; -import { PasswordReg } from '@/config'; -import { INPUT_WIDTH } from '@/constants'; -import { updatePassword } from '@/pages/login/apis'; +import useTabActive from '@/hooks/use-tab-active'; import { PageContainer } from '@ant-design/pro-components'; import { useIntl } from '@umijs/max'; -import { Form, message } from 'antd'; +import { TabsProps } from 'antd'; +import React, { useCallback, useState } from 'react'; +import styled from 'styled-components'; +import CustomUI from './components/custom-ui'; +import ModifyPasswordn from './components/modify-password'; + +const Wrapper = styled.div` + .ant-page-header-heading { + padding-inline: 8px; + } +`; -interface ProfileProps { - username?: string; - new_password: string; - current_password: string; -} const Profile: React.FC = () => { - const [form] = Form.useForm(); const intl = useIntl(); + const { setTabActive, getTabActive, tabsMap } = useTabActive(); + const [activeKey, setActiveKey] = useState( + getTabActive(tabsMap.userSettings) || 'modify-password' + ); - const handleOnFinish = async (values: any) => { - try { - await updatePassword({ - new_password: values.new_password, - current_password: values.current_password - }); - message.success(intl.formatMessage({ id: 'common.message.success' })); - } catch (error) {} - }; + const items: TabsProps['items'] = [ + { + key: 'modify-password', + label: intl.formatMessage({ id: 'users.form.updatepassword' }), + children: + }, + { + key: 'custom-ui', + label: 'Custom UI', + children: + } + ]; - const handleOnFinishFailed = (errorInfo: any) => { - console.log('handleOnFinishFailed', errorInfo); - }; - const handleCancel = () => { - form.resetFields(); - }; + const handleChangeTab = useCallback((key: string) => { + setActiveKey(key); + setTabActive(tabsMap.userSettings, key); + }, []); return ( - -
- - name="current_password" - rules={[ - { - required: true, - message: intl.formatMessage( - { id: 'common.form.rule.input' }, - { - name: intl.formatMessage({ - id: 'users.form.currentpassword' - }) - } - ) - } - ]} - > - - - - name="new_password" - rules={[ - { - required: true, - pattern: PasswordReg, - message: intl.formatMessage({ - id: 'users.form.rule.password' - }) - } - ]} - > - - - ({ - validator(_, value) { - if (!value || getFieldValue('new_password') === value) { - return Promise.resolve(); - } - return Promise.reject( - new Error( - intl.formatMessage({ id: 'users.password.confirm.error' }) - ) - ); - } - }) - ]} - > - - - - -
+ + + ); }; +Profile.displayName = 'Profile'; + export default Profile;